Giao diện
Thêm component C*
Quy trình đưa một component mới vào @tasco/ui, từ quyết định có nên làm tới lúc có trang docs. Claude Code trong repo core có skill /new-component <Tên> làm phần lớn các bước, gồm soạn nháp trang docs bằng skill /doc-component — trang này là checklist để làm tay hoặc để duyệt kết quả của skill.
Trước khi viết
- Đã có chưa? Xem
packages/ui/src/index.ts: ngoài 17 component thương hiệu còn nhiều primitive antdv đã re-export (CInput,CSelect,CModal…). Cần một primitive antdv chưa re-export thì chỉ thêm alias — xem mục cuối. - Có đáng vào core không? Trả lời bộ câu hỏi "core-worthy" trong RFC Process. Component chứa tên hay quy tắc nghiệp vụ của một sản phẩm thì để ở repo sản phẩm.
- Có cần RFC không? Component mới là API công khai (tầng T2): nên có RFC khi nhiều team dùng hoặc API chưa rõ.
- Tên theo dạng
C<PascalCase>, vdCDateRangeLabel.
1. Component
packages/ui/src/components/<Tên>.vue — lấy CStatus.vue làm mẫu.
vue
<script setup lang="ts">
import { Tag } from 'ant-design-vue'
// Nhãn khoảng ngày: hiển thị "01/09/2026 – 30/09/2026", rút gọn khi cùng tháng.
defineOptions({ name: 'CDateRangeLabel' })
const props = withDefaults(defineProps<{
/** Ngày bắt đầu, chuỗi `YYYY-MM-DD`. */
from: string
/** Ngày kết thúc, chuỗi `YYYY-MM-DD`. */
to: string
/** Rút gọn khi hai ngày cùng tháng: `01 – 30/09/2026`. */
compact?: boolean
}>(), {
compact: false,
})
const emit = defineEmits<{
/** Bấm vào nhãn. */
click: [event: MouseEvent]
}>()
defineSlots<{
/** Icon trước nhãn. */
icon?: () => unknown
}>()
</script>| Quy tắc | Vì sao |
|---|---|
Comment // đầu <script setup> mô tả component | Thành mô tả trong component-meta.json và MCP |
defineOptions({ name }) trùng tên file | Tên hiện đúng trong devtools, test tìm component theo tên |
withDefaults(defineProps<…>()), JSDoc cho mọi prop, event, slot | docs-coverage --strict fail nếu thiếu mô tả |
Khai slot bằng defineSlots | Không khai thì slot không có trong bảng API |
Import ant-design-vue ở đây là được phép | @tasco/ui là nơi duy nhất bọc antdv |
<style scoped>, class BEM c-<tên>__phần--biến-thể | Không đụng style của component khác, app ghi đè được có chủ đích |
Màu, khoảng cách chỉ dùng var(--tasco-*) | Đúng theme và chế độ tối; cần giá trị mới thì thêm token trước |
Icon dùng @tabler/icons-vue | Một bộ icon cho cả hệ thống |
Dùng sai API thì throw new Error('[@tasco/ui] … cách sửa') | Lỗi nói rõ cách sửa thay vì hỏng âm thầm |
Không cấu hình style qua theme.components | antdv 4 bỏ qua; style chung đặt ở @tasco/theme/base.css |
2. Story (tuỳ chọn)
Storybook chỉ còn là công cụ dev cục bộ, không deploy (RFC 0003, chốt ở GĐ5). Nó chạy thẳng trên source nên sửa component thấy ngay, và có panel Accessibility (axe) — docs và playground dùng dist, phải build lại mới thấy thay đổi.
Viết <Tên>.stories.ts khi có ích cho việc phát triển, vd component nhiều trạng thái hay cần soi a11y: đặt cạnh component, mỗi story một nhóm biến thể, theo khuôn CStatus.stories.ts (title: 'Components/<Tên>'). Ví dụ cho người dùng framework là demo trong trang docs (mục 5), không phải story.
3. Test
<Tên>.test.ts cạnh component — Vitest + @vue/test-utils, môi trường happy-dom.
- Stub primitive antdv bằng
vi.mock('ant-design-vue', …)đặt trướcimportcomponent: test hành vi của lớp bọc, không test lại antdv. - Tên test dạng
it('<hành vi> → <kết quả>'). - Phủ giá trị mặc định, từng prop chính, từng biến thể, lỗi khi dùng sai.
- Thêm đường dẫn component vào
coverage.includetrongpackages/ui/vitest.config.ts—@tasco/uichỉ tính ngưỡng coverage cho file có trong danh sách này.
Chi tiết: Test & coverage.
4. Đăng ký
Thiếu một chỗ là lỗi âm thầm: component chạy ở chỗ này nhưng không có type hoặc không có ở chỗ khác.
| File | Thêm |
|---|---|
packages/ui/src/index.ts | export { default as <Tên> } from './components/<Tên>.vue' và export type của kiểu đi kèm |
packages/ui/src/install.ts | Import, thêm vào cả khai báo kiểu lẫn object components — kiểu phải viết tường minh <Tên>: typeof <Tên> |
packages/nuxt-layer-base/tasco.d.ts | Import type và dòng trong GlobalComponents — app sản phẩm có type cho component toàn cục |
docs/.vitepress/env.d.ts | Dòng trong GlobalComponents — demo trong docs được vue-tsc kiểm như code app |
install.ts khai kiểu tường minh vì để TypeScript tự suy luận thì d.ts in lại cả cây kiểu component, và build dừng ở chốt chặn typeof import(...) trong vite.config.ts.
5. Trang docs
docs-coverage --strict fail nếu component đăng ký toàn cục mà chưa có docs/components/<tên-kebab>/index.md.
- Tạo
docs/components/c-date-range-label/index.mdtheo chuẩn trang component và demo trongdemos/. - Thêm mục vào sidebar (
docs/.vitepress/config.ts, nhóm Component phù hợp) và vào bảng ở Tổng quan bộ C*. - Chạy
pnpm turbo run dev --filter=docsxem demo chạy thật ở cả chế độ sáng và tối.
Skill /doc-component <Tên> soạn nháp trang và demo từ source, test và story sẵn có. Nháp chỉ là điểm bắt đầu: người mở MR đọc lại từng câu, chạy thử từng demo và sửa chỗ AI đoán sai hành vi.
6. Changeset và kiểm tra
md
---
"@tasco/ui": minor
"@tasco/nuxt-layer-base": patch
---
Thêm component `CDateRangeLabel`: nhãn khoảng ngày, rút gọn khi cùng tháng.bash
pnpm --filter @tasco/ui test
pnpm --filter @tasco/ui lint
pnpm --filter @tasco/ui typecheck
pnpm --filter @tasco/nuxt-layer-base typecheck
pnpm build && node scripts/docs-coverage.mjs --strictThử trên playground (pnpm turbo run dev --filter=playground) và ghi bước thử vào Test plan của MR.
Checklist MR
- [ ] Component có comment mô tả,
defineOptions, JSDoc cho mọi prop/event/slot,defineSlots. - [ ] Chỉ dùng biến
--tasco-*; đã xem ở chế độ tối. - [ ] Test; đã thêm vào
coverage.include. - [ ] Đăng ký đủ 4 file.
- [ ] Trang docs, demo, sidebar, bảng tổng quan.
- [ ] Changeset.
Chỉ thêm primitive antdv
Khi chỉ cần dùng một component antdv chưa có trong @tasco/ui, không tạo wrapper:
- Thêm alias vào khối re-export trong
packages/ui/src/index.ts, đúng nhóm:Timeline as CTimeline. - Ghi vào trang nhóm tương ứng trong
docs/components/primitives/. - Changeset
minorcho@tasco/ui.
Primitive không đăng ký toàn cục — app import từ @tasco/ui. Chưa có yêu cầu style riêng thì không cần story và test.
Liên quan
- Quy ước code — đặt tên, lỗi, JSDoc.
- Viết tài liệu — chuẩn trang component, demo.
- Đổi design token — khi component cần màu hoặc kích thước mới.