Nền tảng
Iconography
Đã đặc tảMột bộ icon duy nhất: Hugeicons, đi qua wrapper Icon của @nexobox/ui. Hai cỡ: 20px khi icon là nội dung, 16px khi icon là dấu cạnh chữ. Nét 1.5px. Icon mặc định là trang trí và bị ẩn khỏi cây trợ năng; nó chỉ có tên khi nó mang nghĩa. Vùng chạm của một control chỉ có icon là kích thước control, không phải kích thước icon.
Bối cảnh
Vì sao trang này tồn tại
ADR-UI-001 chọn Hugeicons qua wrapper của package. Không có file nào trong 01_foundations/ nói về icon trước ngày 2026-09-23 — lưới, nét, thang cỡ, quy tắc đặt tên và luật icon-only không được viết ở đâu trong corpus thị giác trước trang này. DS-010 clause 8 thêm file này làm trang nền tảng thứ chín.
Token
Token
| Token | Giá trị |
|---|---|
--nf-foundation-size-icon | Unknown |
--nf-foundation-size-icon-small | Unknown |
--nf-foundation-stroke-icon | Unknown |
--nf-component-icon-size | Unknown |
Màu icon không có token riêng và không được có: icon thừa hưởng currentColor từ chữ quanh nó, nên nó đúng màu trong mọi theme và mọi scope nghịch đảo mà không cần biết mình đang ở đâu.
Render
Thang hai cỡ, và vì sao chỉ có hai bậc
Hai bậc, không phải năm. 20px là icon mang nội dung (cảnh báo, toast, thẻ số). 16px (small) là dấu nằm cùng hàng chữ ui hoặc caption — mũi tên Select, dấu chọn, tìm kiếm, accordion.
20px mặc định
16px small
Render
Vùng chạm không phải cỡ icon
Một control chỉ có icon có vùng chạm bằng kích thước control, tối thiểu 44px. Icon 20px nằm giữa vùng đó. Số đo dưới đây đọc hộp thật của nút đang render, không phải một con số chép ra.
Vùng chạm: Unknown · Icon: 20pxNghĩa vụ
Obligation
A29
A29 Một bộ icon
Hugeicons là bộ icon duy nhất. Import qua @nexobox/ui/icons/<Icon>. Chỉ packages/ui/src/icons/glyphs/<Icon>.ts được deep-import file gốc của Hugeicons.eslint.config.mjs chặn @hugeicons/core-free-icons ở mọi nơi khác.
Cảnh báo
Đừng thêm lucide-react, heroicons, phosphor, hay bất kỳ bộ thứ hai. Đừng dán một <svg> thô vào một component sản phẩm — ngoại lệ duy nhất là logo kênh bên thứ ba, có ADR riêng.
A30
A30 Icon mặc định là trang trí
Icon đặt aria-hidden="true" khi không có title. Khi có title, nó đặt role="img" và aria-label. Một icon được đặt tên cạnh một nhãn chữ làm screen reader đọc hai lần. Một control chỉ có icon thì tên trợ năng thuộc về control, không phải icon.
A31
A31 Cỡ và nét đến từ token
Cỡ và nét đọc từ --nf-foundation-size-icon, -icon-small, --nf-foundation-stroke-icon. HugeiconsIcon đòi size và strokeWidth là số nên một var() không truyền vào được — wrapper giải bằng cách đặt width, height và stroke-width thật bằng class đọc token trên cùng <svg>, thắng attribute nội tại. Ba prop size, strokeWidth, color là cửa thoát cho specimen tài liệu, không phải API sản phẩm.
A32
A32 Vùng chạm không phải cỡ icon
Một control chỉ có icon có vùng chạm bằng kích thước control, tối thiểu --nf-foundation-size-touch-target (44px). 20px là kích thước hình, không phải kích thước đích. Con trỏ thô vẫn thắng: ở pointer: coarse, control về comfortable dù compact đang bật, nhưng icon không to ra theo.
Vận hành
Đặt tên và nhận một glyph mới
Tên glyph giữ nguyên tên của Hugeicons. Một glyph chỉ vào repo khi có một caller thật cần nó — glyphs/ không phải bản sao của bộ Hugeicons. Icon mang nghĩa vận hành phải được chọn một lần rồi dùng nhất quán; hai icon khác nhau cho cùng một trạng thái ở hai bề mặt là một khiếm khuyết, không phải một biến thể.
Chưa quyết
Open questions
| Question | Owner | Resolves when |
|---|---|---|
| Có nên gỡ size, strokeWidth, color khỏi Icon và chuyển chúng thành một component chỉ dùng trong tài liệu? | nexoboxvn@gmail.com | Có một lần đếm cho thấy bao nhiêu caller sản phẩm đang dùng chúng |
| Bộ Hugeicons có phiên bản trả phí với glyph mà bản free thiếu; ngưỡng nào thì mua? | nexoboxvn@gmail.com | Một bề mặt sản phẩm cần một glyph mà core-free-icons không có |
| Icon mang nghĩa vận hành có cần một sổ đăng ký ánh xạ trạng thái sang glyph không? | nexoboxvn@gmail.com | Bề mặt thứ hai dùng cùng một trạng thái |