lily-lark-ui 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +108 -1
- package/INSTALL.md +14 -13
- package/README.md +115 -39
- package/dist/components/date-picker.d.ts +49 -0
- package/dist/components/date-picker.js +416 -0
- package/dist/components/dialog.js +25 -2
- package/dist/components/table.d.ts +34 -1
- package/dist/components/table.js +72 -5
- package/dist/components/toast.js +2 -2
- package/dist/components/tooltip.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/lark-ui-components.html +2 -2
- package/mcp/server.mjs +68 -2
- package/package.json +1 -1
- package/registry.json +1 -1
- package/scripts/gen-spec-props.mjs +266 -0
- package/skill/lark-ui/SKILL.md +53 -8
- package/specs/alert-dialog.md +22 -0
- package/specs/buttons.md +19 -5
- package/specs/checkbox.md +19 -1
- package/specs/date-picker.md +108 -0
- package/specs/dialog.md +35 -3
- package/specs/dropdown-menu.md +30 -0
- package/specs/feedback-states.md +26 -0
- package/specs/install.md +17 -2
- package/specs/pagination.md +20 -0
- package/specs/radio-group.md +32 -1
- package/specs/select.md +36 -3
- package/specs/switch.md +19 -1
- package/specs/table.md +65 -1
- package/specs/tabs.md +39 -2
- package/specs/tag-badge-avatar.md +36 -1
- package/specs/text-area.md +15 -0
- package/specs/text-field.md +17 -0
- package/specs/toast.md +37 -2
- package/specs/tooltip.md +29 -3
- package/src/components/date-picker.tsx +933 -0
- package/src/components/dialog.tsx +27 -2
- package/src/components/table.tsx +237 -44
- package/src/components/toast.tsx +2 -2
- package/src/components/tooltip.tsx +2 -2
- package/src/styles/lark-tokens.css +8 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,114 @@ Mọi thay đổi đáng chú ý của `lily-lark-ui` được ghi ở đây. Đ
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.4.0] — 2026-11-06
|
|
10
|
+
|
|
11
|
+
### Added — bộ chọn ngày và bộ chọn kỳ
|
|
12
|
+
|
|
13
|
+
- `LarkDatePicker` (`YYYY-MM-DD`) và `LarkMonthPicker` (`YYYY-MM`) trong
|
|
14
|
+
`src/components/date-picker.tsx`: **controlled theo chuỗi**, không cầm engine
|
|
15
|
+
ngày. Trigger 32px như `LarkSelect`, panel bo 6 viền N200 bóng overlay, lật
|
|
16
|
+
lên khi hết chỗ phía dưới.
|
|
17
|
+
- Xoá được: hover/focus trigger khi panel đóng hiện nút X, trả `''` qua
|
|
18
|
+
`onChange` và gọi `onClear`; `required` ẩn nút xoá. Chuỗi rỗng hoặc sai định
|
|
19
|
+
dạng hiển thị placeholder như chưa chọn.
|
|
20
|
+
- Lịch 42 ô tuần bắt đầu thứ hai (`T2…CN`), ngày ngoài tháng làm mờ, footer
|
|
21
|
+
"Hôm nay"; `LarkMonthPicker` có lưới 12 tháng và bảng chọn năm 12 ô.
|
|
22
|
+
- Rollover năm: 12→1 và 1→12 đổi cả năm đang xem; chọn năm tự chuyển về bảng
|
|
23
|
+
tháng; `value` đổi từ ngoài thì view bám theo giá trị mới.
|
|
24
|
+
- Bàn phím: trigger `role=combobox` `aria-haspopup=dialog`, Escape đóng; lưới
|
|
25
|
+
arrow/Home/End di chuyển focus theo hàng; chọn hoặc gõ tay xong trả focus về
|
|
26
|
+
trigger. `LarkDatePicker` nhập tay `YYYY/M/D` hoặc `D/M/YYYY` (dấu `/`, `-`,
|
|
27
|
+
`.`), Enter hoặc blur là commit, sai thì báo lỗi tại chỗ.
|
|
28
|
+
|
|
29
|
+
### Added — `LarkTable`: header hai tầng, ghim trái, bảng tổng hợp
|
|
30
|
+
|
|
31
|
+
- `groupedHeader` (`LarkGroupedHeader[]`): hàng 1 là ô nhóm `scope=colgroup`
|
|
32
|
+
với `colSpan`/`rowSpan: 2`, hàng 2 là cột con; nhóm một cột con vẫn giữ ô
|
|
33
|
+
nhóm đúng hàng.
|
|
34
|
+
- `pin: 'left'`: cột ghim trái song song `pin: 'right'` đã có (`sticky left-0`,
|
|
35
|
+
`border-e` phân cách, `z-10` cho body và `z-20` cho head).
|
|
36
|
+
- `rowHeader` trên cột: ô dữ liệu render `th scope=row` thay vì `td`.
|
|
37
|
+
- `caption` + `captionHidden`: caption hiện trên bảng hoặc `sr-only`, đặt
|
|
38
|
+
accessible name cho `<table>`.
|
|
39
|
+
- `sectionRow(row, index)`: hàng phân mục trong `tbody`, một ô
|
|
40
|
+
`th scope=colgroup` phủ hết chiều rộng; `sectionRowClassName` đổi class.
|
|
41
|
+
- `showHeader={false}`: bỏ `thead` cho bảng tổng hợp chỉ có `tbody`.
|
|
42
|
+
|
|
43
|
+
### Added — test
|
|
44
|
+
|
|
45
|
+
- `tests/date-picker.test.tsx`: 16 test cho hai picker (controlled, xoá,
|
|
46
|
+
`required`, rollover năm, ngày ngoài tháng, 29/2, gõ tay, focus sau khi chọn).
|
|
47
|
+
- `tests/table.test.tsx`: 6 test mới cho `groupedHeader` (colSpan/rowSpan,
|
|
48
|
+
scope), `caption`/`captionHidden`, `rowHeader`, `pin: 'left'`,
|
|
49
|
+
`sectionRow` + `showHeader={false}`.
|
|
50
|
+
|
|
51
|
+
### Added — bảng prop trong spec sinh tự động
|
|
52
|
+
|
|
53
|
+
- `scripts/gen-spec-props.mjs` đọc interface thật của 21 file component rồi sinh
|
|
54
|
+
khối `## Props` (prop riêng, kiểu, bắt buộc, prop HTML kế thừa) cho 18 trang
|
|
55
|
+
`specs/`. `--check` chạy trong `tests/spec-props.test.ts`.
|
|
56
|
+
- MCP `lui_props`: trả bảng prop của một component theo tên (`switch`,
|
|
57
|
+
`LarkSwitch`, `tag`, `spinner`…). `serverInfo.version` đọc từ `package.json`.
|
|
58
|
+
|
|
59
|
+
### Changed — tài liệu, registry, README, skill
|
|
60
|
+
|
|
61
|
+
- `specs/date-picker.md` (mới) và `specs/table.md` (header hai tầng, ghim trái,
|
|
62
|
+
section row); `SPEC_MAP` thêm `date-picker`.
|
|
63
|
+
- `registry.json`: thêm `lark-date-picker` và `lark-month-picker` (22 item).
|
|
64
|
+
- `README.md`: thêm hai dòng picker, cập nhật dòng `LarkTable` với prop mới,
|
|
65
|
+
số component 22.
|
|
66
|
+
- `skill/lark-ui/SKILL.md`: bảng chọn component thêm hai picker kèm ví dụ
|
|
67
|
+
import; `LarkTable` cập nhật prop mới.
|
|
68
|
+
- `docs/STATUS.md`: số component 22, 21 trang `specs/`, 22 item registry.
|
|
69
|
+
- Showcase: khối "Chọn ngày · Chọn kỳ" (controlled, nút xoá, case `required`,
|
|
70
|
+
disabled) và bảng tổng hợp dùng `groupedHeader` + `caption` + `sectionRow` +
|
|
71
|
+
`rowHeader` + cột ghim trái; `lark-ui-components.html` build lại.
|
|
72
|
+
|
|
73
|
+
### Changed — đồng bộ tài liệu và skill theo trạng thái 0.3.0
|
|
74
|
+
|
|
75
|
+
- `specs/`: sửa class đã lỗi thời (button viền N300, `text-brand-link` thay
|
|
76
|
+
`brand-secondary`, `focus-visible:focus-ring` thay `ring-2`, select
|
|
77
|
+
placeholder `n600`, tag blue `accent-soft`).
|
|
78
|
+
- `README.md`: bảng component theo prop riêng, mục "Prop HTML", mục phát hành,
|
|
79
|
+
mục xem demo.
|
|
80
|
+
- `INSTALL.md`: bỏ câu "chưa publish", thêm `--version`, ghim bản `0.3.0`.
|
|
81
|
+
- `AGENTS.md`: quy tắc kế thừa prop primitive, quy tắc spec sinh tự động,
|
|
82
|
+
MCP 5 tool, mock `ResizeObserver`, quy trình phát hành.
|
|
83
|
+
- `skill/lark-ui/SKILL.md`: mục prop HTML + bảng prop phụ (`controlClassName`,
|
|
84
|
+
`containerClassName`, `triggerClassName`, `toastClassName`), cập nhật
|
|
85
|
+
`LarkTable`/`LarkRadioGroup`, nhắc `lui_props`.
|
|
86
|
+
|
|
87
|
+
### Fixed — nền tối cố định, autofocus, khoảng cách
|
|
88
|
+
|
|
89
|
+
- Toast và tooltip giữ nền tối `#1F2329` ở cả hai theme (`--toast-bg`,
|
|
90
|
+
`--tooltip-bg` giữ nguyên trong khối dark; trước đây dùng `lark-n900` nên dark
|
|
91
|
+
mode đảo thành xám nhạt chữ mờ). Mũi tên tooltip ăn theo cùng token.
|
|
92
|
+
- `LarkDialog.Footer` thêm `mt-3` (=12px, cùng nhịp `gap=12` Figma và footer
|
|
93
|
+
AlertDialog): body không còn dính sát viền divider.
|
|
94
|
+
- Mở `LarkDialog` không còn cướp focus vào ô nhập đầu: chặn autofocus mặc
|
|
95
|
+
định của Radix, giữ focus trên khung Content (đã `outline-none`).
|
|
96
|
+
- `LarkDatePicker`/`LarkMonthPicker`: bỏ autofocus khi mở panel (ô nhập tay và
|
|
97
|
+
ô tháng/năm đã chọn); panel lịch trần `max-w-[280px]` căn giữa theo trigger
|
|
98
|
+
(ô ngày gần vuông, ô nhập không còn dãn full form rộng); khe nhãn thứ–lưới
|
|
99
|
+
ngày `mt-1` → `mt-2`.
|
|
100
|
+
- Showcase `TableBlock`: nút Xoá demo nay xoá được dòng (state `items`), cờ
|
|
101
|
+
`LarkSwitch` "Hỏi trước khi xoá", `LarkAlertDialog` xác nhận + toast
|
|
102
|
+
"Đã xoá phiếu".
|
|
103
|
+
- `LarkDatePicker`/`LarkMonthPicker`: Escape trong panel đóng và trả focus về
|
|
104
|
+
trigger (chặn lan truyền để dialog cha không đóng theo); rời ô nhập chỉ
|
|
105
|
+
kiểm hợp lệ, không commit/đóng (bấm ngày khác sau khi gõ vẫn chọn đúng);
|
|
106
|
+
nút xoá hiện khi focus còn trong cụm trigger nên Tab tới được; `className`
|
|
107
|
+
gắn lên wrapper ngoài; xoá prop `triggerProps` và tuỳ chọn cột `MonthGrid`
|
|
108
|
+
không ai dùng.
|
|
109
|
+
- `LarkDialog`: merge ref giữ cleanup của caller (unmount gọi cleanup).
|
|
110
|
+
- `LarkTable`: `thead sticky top-0`, bỏ `sticky top-0` từng `th` nên header
|
|
111
|
+
hai tầng dính theo khối, không đè nhau khi cuộn.
|
|
112
|
+
- Token: bỏ `--toast-bg`/`--tooltip-bg` trùng trong hai khối dark (kế thừa
|
|
113
|
+
từ `:root`, giá trị giữ nguyên `#1F2329` ở cả hai theme).
|
|
114
|
+
|
|
115
|
+
## [0.3.0] — 2026-11-06
|
|
116
|
+
|
|
9
117
|
### Added — prop HTML trên toàn bộ component
|
|
10
118
|
|
|
11
119
|
12 component từng chỉ nhận vài prop (Select, Switch, Checkbox, RadioGroup,
|
|
@@ -34,7 +142,6 @@ EmptyState, Table) nay nhận đủ prop HTML của phần tử gốc: `onBlur`,
|
|
|
34
142
|
`tests/fixtures/types-props.tsx` chạy `tsc` để chặn hồi quy.
|
|
35
143
|
- `vitest.setup.ts` mock `ResizeObserver` cho Radix.
|
|
36
144
|
|
|
37
|
-
|
|
38
145
|
## [0.2.0] — 2026-11-05
|
|
39
146
|
|
|
40
147
|
### Changed — đổi tên package sang `lily-lark-ui`
|
package/INSTALL.md
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# Cài đặt lily-lark-ui
|
|
2
2
|
|
|
3
|
-
## Cài từ npm
|
|
3
|
+
## Cài từ npm
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npx lily-lark-ui init
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
Package đã publish: `lily-lark-ui@0.3.0` (npm, không scope, `latest`). Nếu
|
|
10
|
+
`npx` báo không tìm thấy, kiểm `npm view lily-lark-ui version`; bản mới có thể
|
|
11
|
+
còn đang qua automated review của npm vài phút.
|
|
11
12
|
|
|
12
13
|
## Phát hành (dành cho maintainer)
|
|
13
14
|
|
|
@@ -71,8 +72,9 @@ npx lily-lark-ui init --repo ../app # cài vào app khác
|
|
|
71
72
|
npx lily-lark-ui init --dry-run # xem kế hoạch, không ghi
|
|
72
73
|
npx lily-lark-ui init --no-bootstrap # không cài Tailwind/sửa vite config
|
|
73
74
|
npx lily-lark-ui init --components button,table
|
|
74
|
-
npx lily-lark-ui check
|
|
75
|
+
npx lily-lark-ui check [<dir>] # chạy check-lark (mặc định ./src)
|
|
75
76
|
npx lily-lark-ui tokens # in bảng token
|
|
77
|
+
npx lily-lark-ui --version # in phiên bản
|
|
76
78
|
npx lily-lark-ui --help
|
|
77
79
|
```
|
|
78
80
|
|
|
@@ -84,11 +86,11 @@ Yêu cầu: chạy trong repo đã có `package.json` + `react`.
|
|
|
84
86
|
bash ~/Sites/lark-ui/scripts/install.sh --repo . --apply --bootstrap
|
|
85
87
|
```
|
|
86
88
|
|
|
87
|
-
Nếu
|
|
89
|
+
Nếu cần cài từ tarball (bản dev chưa publish, hoặc muốn ghim đúng file):
|
|
88
90
|
|
|
89
91
|
```bash
|
|
90
92
|
cd ~/Sites/lark-ui && pnpm pack
|
|
91
|
-
LARK_UI_TARBALL=~/Sites/lark-ui/lily-lark-ui-0.
|
|
93
|
+
LARK_UI_TARBALL=~/Sites/lark-ui/lily-lark-ui-0.4.0.tgz \
|
|
92
94
|
bash ~/Sites/lark-ui/scripts/install.sh --repo . --apply --bootstrap
|
|
93
95
|
```
|
|
94
96
|
|
|
@@ -176,16 +178,15 @@ Tailwind v4 **không tự quét `node_modules`**, nên ngoài `@import` còn ph
|
|
|
176
178
|
pnpm add lily-lark-ui
|
|
177
179
|
```
|
|
178
180
|
|
|
179
|
-
|
|
181
|
+
Package dùng tên không scope, không cần token cho consumer. Import:
|
|
180
182
|
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
pnpm pack # sinh lily-lark-ui-<version>.tgz
|
|
184
|
-
|
|
185
|
-
# trong repo đích
|
|
186
|
-
pnpm add ./lily-lark-ui-0.2.0.tgz
|
|
183
|
+
```tsx
|
|
184
|
+
import { LarkButton } from 'lily-lark-ui'
|
|
187
185
|
```
|
|
188
186
|
|
|
187
|
+
Nếu cần ghim đúng file build (bản dev chưa publish, hoặc kiểm tra tarball), cài
|
|
188
|
+
bằng `pnpm add ./lily-lark-ui-0.4.0.tgz` sau khi `pnpm pack` trong repo này.
|
|
189
|
+
|
|
189
190
|
Dùng component:
|
|
190
191
|
|
|
191
192
|
```tsx
|
package/README.md
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
# lily-lark-ui
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Thư viện component React theo phong cách Lark (Universe Design) cho React 19 +
|
|
4
|
+
Tailwind v4. 22 component, nền Radix headless, phát hành trên npm.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npx lily-lark-ui init # cài vào app hiện tại (tự cài Tailwind v4)
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Phiên bản hiện tại: `0.4.0`. Mọi component nhận đủ prop HTML của phần tử gốc
|
|
11
|
+
(`onBlur`, `onFocus`, `onKeyDown`, `name`, `form`, `value`, `data-*`, `aria-*`,
|
|
12
|
+
`style`, `id`, `ref`) — xem mục [Prop HTML](#prop-html).
|
|
5
13
|
|
|
6
14
|
## Cài đặt
|
|
7
15
|
|
|
@@ -44,61 +52,117 @@ lớn hơn 0.
|
|
|
44
52
|
|
|
45
53
|
## Cai vao repo moi
|
|
46
54
|
|
|
47
|
-
Mot lenh (6 buoc + kiem Tailwind v4, copy
|
|
55
|
+
Mot lenh (6 buoc + kiem Tailwind v4, copy `--components` neu co, check-lark report):
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npx lily-lark-ui init # app hien tai
|
|
59
|
+
npx lily-lark-ui init --repo ../app # app khac
|
|
60
|
+
npx lily-lark-ui init --dry-run # chi in ke hoach
|
|
61
|
+
npx lily-lark-ui init --no-bootstrap # khong dung Tailwind/vite config
|
|
62
|
+
npx lily-lark-ui init --components button,table
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Hoac goi thang script trong source checkout:
|
|
48
66
|
|
|
49
67
|
```bash
|
|
50
68
|
scripts/install.sh --repo <path> --apply [--components button,text-field]
|
|
51
69
|
```
|
|
52
70
|
|
|
53
71
|
- Khong truyen `--apply` thi dry-run: chi in ke hoach, khong sua file.
|
|
54
|
-
- `--skip-install`: bo qua buoc
|
|
72
|
+
- `--skip-install`: bo qua buoc cai package (dung cho test offline).
|
|
55
73
|
- `--components <list>`: chi copy component can (ten cach nhau boi dau phay,
|
|
56
74
|
vd `button,text-field`); kem `src/lib/utils.ts` + `src/styles/lark-tokens.css`
|
|
57
75
|
neu chua co. Ten sai thi bao loi + liet ke ten hop le.
|
|
58
76
|
- Idempotent: chay lai khong them trung import/block MCP.
|
|
59
77
|
|
|
78
|
+
## Phát hành (maintainer)
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pnpm release:dry # build + test + check-lark + publint + pack + import(), khong publish
|
|
82
|
+
pnpm release # publish thật, rồi cài lại từ registry để xác nhận
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Package là `lily-lark-ui` (không scope). Publish cần token npm có quyền ghi
|
|
86
|
+
package; nếu tài khoản bật 2FA thì `npm publish` trả `EOTP`, cần Automation
|
|
87
|
+
token. Bản mới đi qua automated review của npm (vài phút) trước khi thành
|
|
88
|
+
`latest`.
|
|
89
|
+
|
|
60
90
|
## Component
|
|
61
91
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
|
66
|
-
|
|
67
|
-
|
|
|
68
|
-
|
|
|
69
|
-
|
|
|
70
|
-
|
|
|
71
|
-
|
|
|
72
|
-
|
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
Tất cả component nhận đủ prop HTML của phần tử gốc; bảng dưới chỉ liệt kê prop
|
|
93
|
+
riêng của thư viện.
|
|
94
|
+
|
|
95
|
+
| Component | Props riêng | Số đo |
|
|
96
|
+
|---|---|---|
|
|
97
|
+
| `LarkButton` | `variant` (primary, secondary, secondaryBlue, ghost, text, primaryError, secondaryError), `size` (xs/sm/md/lg), `isIconOnly`, `fullWidth`, `isPending`, `asChild` | 32px mặc định (`h-8`), 40px nút chính form (`h-10`), 28/24 nhỏ; mobile 36/48px |
|
|
98
|
+
| `LarkTextField` (+ `inputClass`) | `label`, `error`, `description`, `isRequired`, `isInvalid` | 42px mobile / 36px PC (`md:min-h-9`), chữ 16/14 |
|
|
99
|
+
| `LarkTextArea` | `label`, `error`, `isRequired` | tối thiểu 72px (~3 dòng) |
|
|
100
|
+
| `LarkDropdownMenu` | `trigger`, `align` (start/center/end); `Item` (`value`, `onSelect`, `danger`, `disabled`, `checked`); `Separator` | popover min 200 rộng, bo 8, bóng overlay; item 32px; đóng menu trả focus về trigger |
|
|
101
|
+
| `LarkTabs` | `defaultValue`/`value`/`onValueChange`; `LarkTabs.List/Tab/Panel` | tab cao 34, gạch dưới 3px |
|
|
102
|
+
| `LarkTooltip` (+ `LarkTooltipProvider`) | `content` (`ReactNode`), `side`, `delayDuration`, `triggerClassName`; Provider `delayDuration` (=300), `skipDelayDuration` | delay 300ms, lệch 6px, overlay 300ms |
|
|
103
|
+
| `LarkSelect` | `options`, `value`/`onValueChange`, `onOpenChange`, `placeholder`, `disabled`, `isInvalid`, `ariaLabel`, `containerClassName` | trigger 32px bo 6, item 32px, dropdown bo 6 |
|
|
104
|
+
| `LarkDatePicker` | `label`, `value` (`YYYY-MM-DD`), `onChange`, `onClear`, `error`, `isInvalid`, `required`, `placeholder`, `disabled`, `describedBy`, `containerClassName` | trigger 32px như Select, panel bo 6, lịch 42 ô tuần bắt đầu T2, ô ngày 32px |
|
|
105
|
+
| `LarkMonthPicker` (+ `formatMonthValue`) | `label`, `value` (`YYYY-MM`), `onChange`, `onClear`, `error`, `isInvalid`, `required`, `placeholder`, `disabled`, `describedBy`, `containerClassName` | trigger 32px, lưới tháng 3 cột, bảng năm 12 ô |
|
|
106
|
+
| `LarkCheckbox` | `label`, `checked` (`true`/`false`/`'indeterminate'`), `onCheckedChange`, `controlClassName` | khung 16px bo 4, dấu 12px trắng |
|
|
107
|
+
| `LarkRadioGroup` | `label`, `options` **hoặc** `children` (`LarkRadioGroup.Item`), `value`/`onValueChange` | khung 16px tròn, chấm viền brand 5px |
|
|
108
|
+
| `LarkSwitch` | `label`, `checked`/`onCheckedChange`, `controlClassName` | rãnh 36×20, núm 16px |
|
|
109
|
+
| `LarkDialog` | `open`/`onOpenChange`; `Content` (`title`, `description`), `Footer` | bo 8, đệm 20/24, tối đa `max-w-md` |
|
|
110
|
+
| `LarkAlertDialog` | `title`, `confirmLabel`, `cancelLabel` (=`Hủy`), `onConfirm`, `isPending` | như dialog; pending chặn Escape, disable nút huỷ |
|
|
111
|
+
| `LarkToastProvider` + `useLarkToast` | `toast({ title, description, variant })`; Provider `duration` (=4000), `toastClassName`, `viewportClassName` | nền `n900`, bo 8 / pill mobile, 4s, quét phải để tắt |
|
|
112
|
+
| `LarkSpinner` / `LarkEmptyState` | Spinner `size` (sm/md), `label` bắt buộc; EmptyState `icon`, `title`, `description`, `action` | spinner 16/24px; empty căn giữa, icon 24px |
|
|
113
|
+
| `LarkTable` (+ `Wrapper`/`Footer`/`TruncatedCell`) | `columns`, `rows`, `rowKey`, `isLoading`, `emptyState`, `onRowClick`, `rowClassName`, `ref`; cột có `pin: 'right' \| 'left'`, `rowHeader`, `className`, `headerClassName`; bảng có `groupedHeader`, `caption`, `captionHidden`, `sectionRow`, `sectionRowClassName`, `showHeader` | head 48, body 47, divider `n200/n300`, ghim `z-10/z-20` |
|
|
114
|
+
| `LarkPagination` (+ `pageWindow`) | `page`, `total`, `pageSize`, `onPageChange`, `pageSizes` (=`[50,100,200]`), `onPageSizeChange`, `isLoading` | nút 28, active 28×28 bo 6, footer `py-2 px-3` |
|
|
115
|
+
| `LarkTag` | `color` (blue/gray/success/danger/warning), `size` (md/sm) | 24 md / 16 sm, bo 4 |
|
|
116
|
+
| `LarkBadge` | `count`, `max` (=99), `dot` | cao 14, chấm 8px |
|
|
117
|
+
| `LarkAvatar` (+ `getInitials`) | `name`, `src`, `team`, `size` (sm/md/lg) | 20/32/36px, tròn |
|
|
118
|
+
|
|
119
|
+
### Prop HTML
|
|
120
|
+
|
|
121
|
+
Mọi component kế thừa prop HTML của phần tử gốc, nên gắn được logic React
|
|
122
|
+
thoải mái:
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
<LarkSwitch
|
|
126
|
+
label="Nhắc lịch hẹn"
|
|
127
|
+
name="notify"
|
|
128
|
+
checked={on}
|
|
129
|
+
onCheckedChange={setOn}
|
|
130
|
+
onBlur={trackBlur}
|
|
131
|
+
data-testid="notify-switch"
|
|
132
|
+
aria-describedby="notify-hint"
|
|
133
|
+
/>
|
|
134
|
+
|
|
135
|
+
<LarkTable
|
|
136
|
+
ref={tableRef}
|
|
137
|
+
columns={cols}
|
|
138
|
+
rows={rows}
|
|
139
|
+
rowKey={(r) => r.id}
|
|
140
|
+
onRowClick={(row, i) => open(row)}
|
|
141
|
+
rowClassName={(row) => (row.urgent ? 'bg-lark-danger/5' : undefined)}
|
|
142
|
+
/>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`name`/`form`/`value` của `LarkSwitch` và `LarkCheckbox` vào hidden input của
|
|
146
|
+
Radix nên `FormData` trong `<form>` thu được giá trị thật.
|
|
147
|
+
|
|
148
|
+
## Nguồn số đo
|
|
149
|
+
|
|
150
|
+
Số đo lấy từ style guide chính thức của Lark (MCP `lark-design`:
|
|
151
|
+
`design-language/*`, `components/*`) — đây là nguồn quyết định. File Figma
|
|
152
|
+
(`~/Sites/lily-projects/lark-design-guide/figma/`) chỉ để đối chiếu; lệch thì
|
|
153
|
+
theo style guide và ghi rõ chỗ lệch trong spec. Chi tiết:
|
|
154
|
+
`docs/specs/2026-11-05-lark-ui.md` và `specs/*.md`.
|
|
155
|
+
|
|
156
|
+
## Ví dụ
|
|
92
157
|
|
|
93
158
|
```tsx
|
|
94
159
|
import { LarkButton, LarkTextField } from 'lily-lark-ui'
|
|
95
|
-
import 'lily-lark-ui/styles.css'
|
|
96
160
|
|
|
97
161
|
export function LoginForm() {
|
|
98
162
|
return (
|
|
99
163
|
<form>
|
|
100
|
-
<LarkTextField label="
|
|
101
|
-
<LarkButton type="submit"
|
|
164
|
+
<LarkTextField label="Số điện thoại" placeholder="Nhập số điện thoại" isRequired />
|
|
165
|
+
<LarkButton type="submit">Đăng nhập</LarkButton>
|
|
102
166
|
</form>
|
|
103
167
|
)
|
|
104
168
|
}
|
|
@@ -119,6 +183,18 @@ export function RecordsTable({ columns, rows, page, total, pageSize, onPageChang
|
|
|
119
183
|
}
|
|
120
184
|
```
|
|
121
185
|
|
|
122
|
-
##
|
|
186
|
+
## Xem component
|
|
187
|
+
|
|
188
|
+
Mở `lark-ui-components.html` ở root repo bằng trình duyệt — một file tự chứa,
|
|
189
|
+
có nút chuyển sáng/tối, responsive 320–1600px.
|
|
190
|
+
|
|
191
|
+
## Phát triển
|
|
123
192
|
|
|
124
|
-
Xem [AGENTS.md](./AGENTS.md)
|
|
193
|
+
Xem [AGENTS.md](./AGENTS.md) trước khi sửa code.
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
pnpm test # 254 test (vitest + jsdom)
|
|
197
|
+
pnpm test:visual # 9 test layout thật (Playwright)
|
|
198
|
+
pnpm check:lark # cấm hex, dark:, emoji-icon trong src/
|
|
199
|
+
pnpm showcase:build # build lại lark-ui-components.html
|
|
200
|
+
```
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
/** Nhãn tháng: `2026-10` → `Tháng 10/2026`; chuỗi lạ giữ nguyên. */
|
|
3
|
+
export declare function formatMonthValue(value: string): string;
|
|
4
|
+
export interface LarkMonthPickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue' | 'children' | 'className'> {
|
|
5
|
+
/** Nhãn hiển thị phía trên trigger. */
|
|
6
|
+
label: string;
|
|
7
|
+
/** Kỳ dạng `YYYY-MM`; chuỗi rỗng hoặc sai định nghĩa là chưa chọn. */
|
|
8
|
+
value: string;
|
|
9
|
+
/** Nhận chuỗi `YYYY-MM` vừa chọn; nút xoá nhận `''`. */
|
|
10
|
+
onChange: (value: string) => void;
|
|
11
|
+
/** Báo lỗi dưới trigger; có lỗi thì trigger viền đỏ. */
|
|
12
|
+
error?: string;
|
|
13
|
+
/** Viền đỏ không kèm chữ (khi caller tự báo lỗi ngoài). */
|
|
14
|
+
isInvalid?: boolean;
|
|
15
|
+
/** true thì ẩn nút xoá — không cho bỏ trống; mặc định false cho phép xoá trả `''`. */
|
|
16
|
+
required?: boolean;
|
|
17
|
+
placeholder?: string;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
/** id đặt lên trigger để label form trỏ htmlFor. */
|
|
20
|
+
id?: string;
|
|
21
|
+
className?: string;
|
|
22
|
+
/** Class cho wrapper ngoài (nhãn + trigger + lỗi). */
|
|
23
|
+
containerClassName?: string;
|
|
24
|
+
/** aria-describedby thêm vào trigger (mô tả ngoài như hint). */
|
|
25
|
+
describedBy?: string;
|
|
26
|
+
/** Callback gọi cùng `onChange` khi người dùng xoá giá trị. */
|
|
27
|
+
onClear?: () => void;
|
|
28
|
+
}
|
|
29
|
+
export declare function LarkMonthPicker({ label, value, onChange, error, isInvalid, required, placeholder, disabled, id, className, containerClassName, describedBy, onClear: onClearProp, ...props }: LarkMonthPickerProps): React.JSX.Element;
|
|
30
|
+
export interface LarkDatePickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue' | 'children' | 'className'> {
|
|
31
|
+
/** Nhãn hiển thị phía trên trigger. */
|
|
32
|
+
label: string;
|
|
33
|
+
/** Ngày dạng `YYYY-MM-DD`; chuỗi rỗng hoặc sai là chưa chọn. */
|
|
34
|
+
value: string;
|
|
35
|
+
/** Nhận `YYYY-MM-DD`; nút xoá nhận `''`. */
|
|
36
|
+
onChange: (value: string) => void;
|
|
37
|
+
error?: string;
|
|
38
|
+
isInvalid?: boolean;
|
|
39
|
+
/** true thì ẩn nút xoá; mặc định false cho phép xoá trả `''`. */
|
|
40
|
+
required?: boolean;
|
|
41
|
+
placeholder?: string;
|
|
42
|
+
disabled?: boolean;
|
|
43
|
+
id?: string;
|
|
44
|
+
className?: string;
|
|
45
|
+
containerClassName?: string;
|
|
46
|
+
describedBy?: string;
|
|
47
|
+
onClear?: () => void;
|
|
48
|
+
}
|
|
49
|
+
export declare function LarkDatePicker({ label, value, onChange, error, isInvalid, required, placeholder, disabled, id, className, containerClassName, describedBy, onClear: onClearProp, ...props }: LarkDatePickerProps): React.JSX.Element;
|