lily-lark-ui 0.0.0-stage → 0.2.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.
Files changed (104) hide show
  1. package/CHANGELOG.md +235 -0
  2. package/INSTALL.md +278 -0
  3. package/LICENSE +21 -0
  4. package/README.md +123 -2
  5. package/bin/lark-ui.mjs +149 -0
  6. package/dist/components/alert-dialog.d.ts +15 -0
  7. package/dist/components/alert-dialog.js +12 -0
  8. package/dist/components/avatar.d.ts +10 -0
  9. package/dist/components/avatar.js +31 -0
  10. package/dist/components/badge.d.ts +8 -0
  11. package/dist/components/badge.js +16 -0
  12. package/dist/components/button.d.ts +14 -0
  13. package/dist/components/button.js +57 -0
  14. package/dist/components/checkbox.d.ts +10 -0
  15. package/dist/components/checkbox.js +15 -0
  16. package/dist/components/dialog.d.ts +23 -0
  17. package/dist/components/dialog.js +20 -0
  18. package/dist/components/dropdown-menu.d.ts +24 -0
  19. package/dist/components/dropdown-menu.js +60 -0
  20. package/dist/components/empty-state.d.ts +9 -0
  21. package/dist/components/empty-state.js +5 -0
  22. package/dist/components/pagination.d.ts +16 -0
  23. package/dist/components/pagination.js +30 -0
  24. package/dist/components/radio-group.d.ts +26 -0
  25. package/dist/components/radio-group.js +23 -0
  26. package/dist/components/select.d.ts +19 -0
  27. package/dist/components/select.js +13 -0
  28. package/dist/components/spinner.d.ts +7 -0
  29. package/dist/components/spinner.js +14 -0
  30. package/dist/components/switch.d.ts +10 -0
  31. package/dist/components/switch.js +16 -0
  32. package/dist/components/table.d.ts +39 -0
  33. package/dist/components/table.js +30 -0
  34. package/dist/components/tabs.d.ts +29 -0
  35. package/dist/components/tabs.js +30 -0
  36. package/dist/components/tag.d.ts +7 -0
  37. package/dist/components/tag.js +24 -0
  38. package/dist/components/text-area.d.ts +7 -0
  39. package/dist/components/text-area.js +13 -0
  40. package/dist/components/text-field.d.ts +10 -0
  41. package/dist/components/text-field.js +14 -0
  42. package/dist/components/toast.d.ts +17 -0
  43. package/dist/components/toast.js +42 -0
  44. package/dist/components/tooltip.d.ts +15 -0
  45. package/dist/components/tooltip.js +23 -0
  46. package/dist/index.d.ts +21 -0
  47. package/dist/index.js +23 -0
  48. package/dist/lib/utils.d.ts +2 -0
  49. package/dist/lib/utils.js +5 -0
  50. package/lark-ui-components.html +17 -0
  51. package/mcp/server.mjs +235 -0
  52. package/package.json +112 -4
  53. package/registry.json +1 -0
  54. package/scripts/bundle-showcase.mjs +39 -0
  55. package/scripts/check-lark.mjs +85 -0
  56. package/scripts/install.sh +455 -0
  57. package/scripts/publish.sh +111 -0
  58. package/scripts/rename-package.mjs +98 -0
  59. package/scripts/setup-vite-tailwind.mjs +58 -0
  60. package/scripts/showcase-hash.mjs +36 -0
  61. package/showcase/README.md +82 -0
  62. package/skill/lark-ui/SKILL.md +213 -0
  63. package/specs/alert-dialog.md +62 -0
  64. package/specs/buttons.md +106 -0
  65. package/specs/checkbox.md +63 -0
  66. package/specs/dialog.md +66 -0
  67. package/specs/dropdown-menu.md +80 -0
  68. package/specs/feedback-states.md +75 -0
  69. package/specs/install.md +80 -0
  70. package/specs/layout-app-shell.md +68 -0
  71. package/specs/pagination.md +68 -0
  72. package/specs/radio-group.md +57 -0
  73. package/specs/select.md +81 -0
  74. package/specs/switch.md +59 -0
  75. package/specs/table.md +82 -0
  76. package/specs/tabs.md +58 -0
  77. package/specs/tag-badge-avatar.md +76 -0
  78. package/specs/text-area.md +61 -0
  79. package/specs/text-field.md +54 -0
  80. package/specs/toast.md +70 -0
  81. package/specs/tokens.md +423 -0
  82. package/specs/tooltip.md +76 -0
  83. package/src/components/alert-dialog.tsx +77 -0
  84. package/src/components/avatar.tsx +71 -0
  85. package/src/components/badge.tsx +45 -0
  86. package/src/components/button.tsx +101 -0
  87. package/src/components/checkbox.tsx +51 -0
  88. package/src/components/dialog.tsx +81 -0
  89. package/src/components/dropdown-menu.tsx +131 -0
  90. package/src/components/empty-state.tsx +23 -0
  91. package/src/components/pagination.tsx +113 -0
  92. package/src/components/radio-group.tsx +96 -0
  93. package/src/components/select.tsx +85 -0
  94. package/src/components/spinner.tsx +31 -0
  95. package/src/components/switch.tsx +48 -0
  96. package/src/components/table.tsx +160 -0
  97. package/src/components/tabs.tsx +116 -0
  98. package/src/components/tag.tsx +50 -0
  99. package/src/components/text-area.tsx +50 -0
  100. package/src/components/text-field.tsx +60 -0
  101. package/src/components/toast.tsx +118 -0
  102. package/src/components/tooltip.tsx +70 -0
  103. package/src/lib/utils.ts +6 -0
  104. package/src/styles/lark-tokens.css +324 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,235 @@
1
+ # Changelog
2
+
3
+ Mọi thay đổi đáng chú ý của `lily-lark-ui` được ghi ở đây. Định dạng theo
4
+ [Keep a Changelog](https://keepachangelog.com/vi/1.1.0/), phiên bản theo
5
+ [SemVer](https://semver.org/lang/vi/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.2.0] — 2026-11-05
10
+
11
+ ### Changed — đổi tên package sang `lily-lark-ui`
12
+
13
+ - Bỏ scope `@lily` (chưa tồn tại trên npm, cần tạo org). Tên không scope cài
14
+ bằng `npx lily-lark-ui init`, không cần quyền org.
15
+ - `scripts/rename-package.mjs` đổi tên ở 41 file, có `--dry-run` và validate tên.
16
+
17
+ ### Added — phát hành
18
+
19
+ - `scripts/publish.sh` (`pnpm publish` / `pnpm publish:dry`): kiểm đăng nhập,
20
+ build, test, `check-lark`, `publint`, pack tarball rồi `import()` thật bằng
21
+ Node ESM, kiểm kích thước, `npm publish`, rồi cài lại từ registry.
22
+ - Metadata đủ để publish: `license` MIT + `LICENSE`, `publishConfig.access=public`,
23
+ `author`, `keywords`, `prepublishOnly` chạy build+test+check.
24
+
25
+ ### Fixed — package không dùng được ngoài bundler
26
+
27
+ - `dist` giữ import tương đối thiếu đuôi `.js` (`from './components/button'`),
28
+ Node ESM không resolve → `ERR_MODULE_NOT_FOUND dist/lib/utils` khi `import()`
29
+ từ tarball. Đã thêm `.js` cho 44 import trong `src/`. `publint` vẫn báo
30
+ "All good", chỉ `import()` thật mới phát hiện.
31
+ - Installer `--skip-install` không gọi `npm i` cho bootstrap Tailwind nữa
32
+ (test offline từng timeout 5s vì tải package từ mạng).
33
+
34
+ ### Added
35
+
36
+ - Trang showcase responsive (`pnpm showcase:dev`, `pnpm showcase:build`) render
37
+ đủ 20 component và một màn ví dụ dùng chung cho desktop/tablet/mobile; bản
38
+ đóng gói một file HTML tự chứa tại `lark-ui-components.html` (root repo).
39
+ - `tests/showcase.test.ts` so hash nguồn, FAIL khi file HTML chưa build lại sau
40
+ khi sửa component/token/showcase.
41
+ - Showcase có nút chuyển sáng/tối: đặt `data-theme` trên `<html>`, nhớ lựa chọn
42
+ trong `localStorage`, mặc định theo `prefers-color-scheme`; thêm `color-scheme`
43
+ để thanh cuộn và control của trình duyệt đổi theo.
44
+
45
+ ### Fixed
46
+
47
+ - Tương phản chế độ tối: chữ accent dùng `text-brand-link` (`#75A4FF`) thay vì
48
+ `text-brand-secondary` (`#275FCE`, chỉ dùng làm nền) ở Button/Tabs/Select/
49
+ Dropdown/Tag — trước đó 3.0–3.6:1.
50
+ - `LarkButton` variant `primaryError` và `LarkBadge` dùng `--danger-foreground`
51
+ thay vì chữ trắng cứng: nền danger bản tối là `#F6827E` nên chữ trắng chỉ
52
+ đạt 2.50:1; nay 6.97:1 (sáng 5.83:1). Token `--danger-foreground` bổ sung
53
+ cho khối sáng.
54
+ - Chữ phụ 12–14px đổi `text-lark-n500` → `text-lark-n600`: `n500` ở chế độ tối
55
+ chỉ đạt 3.78:1, guide ghi "không dùng cho chữ nhỏ quan trọng".
56
+ - `LarkTag` màu blue dùng nền `bg-lark-accent-soft` thay `bg-brand-secondary/20`
57
+ (4.26:1 → 5.16:1 ở bản sáng).
58
+ - Audit tương phản bằng pixel thật (Chromium + ImageMagick): 0 vi phạm WCAG AA
59
+ ở cả sáng và tối cho chữ không bị disabled.
60
+
61
+ ### Added — tài liệu cài đặt
62
+
63
+ - `INSTALL.md` viết lại: bảng yêu cầu (Tailwind v4 bắt buộc, không dùng v3),
64
+ công thức 3 dòng CSS, hướng dẫn cho app đã có CSS riêng, bảng 4 lỗi thường
65
+ gặp, cách kiểm `grep -c 'bg-brand-secondary' dist/assets/*.css`.
66
+ - `README.md`: mục yêu cầu + 3 dòng CSS bắt buộc.
67
+ - Skill `lark-ui` viết lại: style guide chính thức là nguồn quyết định (Figma
68
+ chỉ tham khảo), thêm mục cài một lệnh và ví dụ code đã kiểm chứng.
69
+
70
+ ### Fixed — installer (phát hiện khi chạy thử trên lily-store-division-kpis)
71
+
72
+ - Không chèn `@import "lily-lark-ui/styles.css"` khi repo đích chưa có
73
+ Tailwind v4 (trước đây chèn mù làm `vite build` hỏng với `ENOENT`).
74
+ - Thêm bước `@source "../node_modules/lily-lark-ui/src"`: Tailwind v4 không
75
+ quét `node_modules`, thiếu dòng này component render không style (nút trong
76
+ suốt, cao 22px thay vì 32px) trong khi build vẫn PASS.
77
+ - Nhận cả `@import 'tailwindcss'` (nháy đơn) lẫn nháy kép khi chèn import;
78
+ trước chỉ khớp nháy kép nên chèn sai vị trí.
79
+ - Test harness đọc cả stdout và stderr (thông báo `warn` ghi ra stderr).
80
+
81
+ ### Changed — căn theo style guide chính thức của Lark
82
+
83
+ Nguồn số đo từ nay là Lark Design (MCP `lark-design`, `design-language/*` và
84
+ `components/*`); file Figma chỉ còn để tham khảo đối chiếu.
85
+
86
+ - Thang màu neutral đổi về đúng bảng "Màu chữ" và "Viền": N400 `#BBBFC4`,
87
+ N500 `#8F959E`, N600 `#646A73`, N700 `#2B2F36`, N300 `#D0D3D6`.
88
+ Trước đó dùng N400 `#C9CDD4`, N500 `#86909C`, N600 `#4E5969` (bảng cũ).
89
+ - Viền control tương tác dùng `border-lark-n300` (`#D0D3D6`) cho nút secondary,
90
+ ô nhập, select — đúng "Viền điều khiển tương tác 1px" của guide.
91
+ - Bo góc theo thang Radius-XS 4 / S 6 / M 8 / L 10: ô nhập, item menu, tab đổi
92
+ sang 6px (`rounded-lg`); tooltip sang 8px (`rounded-xl`); badge sang tròn
93
+ hoàn toàn (`rounded-full`) theo "Radius-XL: badge".
94
+ - Focus chuyển sang utility `focus-visible:focus-ring` = `outline: 2px solid
95
+ var(--focus-ring-color)` + offset 2px, chỉ hiện với bàn phím/voice đúng
96
+ trạng thái "Focus-visible" của guide. Trước đó dùng `ring-2` (box-shadow)
97
+ và một số chỗ mất focus hoàn toàn.
98
+
99
+ ### Fixed — spacing và cắt nội dung
100
+
101
+ - `LarkTable`: cột ghim phải (`pin: 'right'`) thiếu vạch phân cách, nội dung
102
+ cuộn bên dưới chạm thẳng vào cột nên trông như bị cắt giữa chữ. Thêm
103
+ `border-s border-lark-n200` cho `th` và `td` ghim, đúng mô tả trong
104
+ `patterns/table.md`.
105
+ - Showcase: grid 2 cột skeleton/empty state thiếu `grid-cols-1` + `min-w-0`
106
+ nên mỗi khối rộng 360px trong khung 309px, tràn ra ngoài.
107
+ - Showcase: nút icon trong header màn ví dụ dùng `size="sm"` (28×28) — dưới
108
+ ngưỡng chạm; đổi sang `size="md"` (32×36).
109
+ - Showcase: badge số đè lên icon chuông (`-end-0.5 -top-0.5`); đổi thành
110
+ `-end-1 -top-1` + `pointer-events-none` để nằm ngoài góc.
111
+
112
+ ### Fixed
113
+
114
+ - Installer khong con chen `@import "lily-lark-ui/styles.css"` vao repo dich
115
+ khi repo do chua co Tailwind v4 — truoc day chen mu va lam `vite build` hong
116
+ (`ENOENT: lily-lark-ui/styles.css`). Gio bao WARN + huong dan cai Tailwind,
117
+ giu nguyen file CSS goc. Phat hien khi chay thu tren `lily-store-division-kpis`.
118
+ - `outline-[var(--focus-ring-color)]` không sinh CSS đúng (Tailwind v4 hiểu là
119
+ outline-width) khiến focus ring trắng/không màu; thay bằng `@utility focus-ring`.
120
+ - `LarkTag` màu blue dùng nền `bg-lark-accent-soft` thay `bg-brand-secondary/20`
121
+ (4.26:1 → 5.16:1).
122
+
123
+ ## [0.1.1] — 2026-11-05
124
+
125
+ ### Changed
126
+
127
+ - Mục đang chọn của `LarkSelect` dùng nền trắng
128
+ theo Figma (`Basic/Selected` nền `#FFFFFF`, `token/bg/float`),
129
+ phân biệt bằng `text-brand-secondary` + `font-medium` + indicator;
130
+ bỏ `bg-lark-accent-soft` của mẫu nội bộ (`patterns/dropdown.md`
131
+ là mẫu lệch). Mục đang chọn dropdown dùng prop `checked`
132
+ (icon + chữ brand, nền trắng theo Figma). Hover giữ `bg-lark-n100`
133
+ (adapt để thấy điểm hover; Figma ghi hover trong suốt).
134
+
135
+ ### Added
136
+
137
+ - `LarkTooltipProvider` đặt ở root: `delayDuration`/`skipDelayDuration` của
138
+ provider giờ có tác dụng; `LarkTooltip` render độc lập vẫn tự bọc provider
139
+ dự phòng 300ms.
140
+ - `LarkTooltip` nhận prop `delayDuration` riêng.
141
+ - `LarkDropdownMenu.Item` nhận prop `checked` + icon dấu chọn thật.
142
+
143
+ ### Fixed
144
+
145
+ - Dropdown trả focus về trigger khi đóng bằng Escape, chọn item, hoặc click
146
+ ngoài; click lần hai lên trigger đóng menu (có test chặn hồi quy).
147
+ - Bỏ lớp neo `span.contents` làm `getBoundingClientRect()` bằng 0 khiến menu
148
+ hiện sai vị trí trên trình duyệt thật.
149
+ - Dọn cảnh báo `act()` của Radix RovingFocus và `ToastAnnounce`; test chạy
150
+ không còn cảnh báo.
151
+ - `LarkDropdownMenu.Item` dùng `data-[state=checked]` (Radix `Menu.Item`
152
+ không sinh state này) nên mục đang chọn trước đây không có dấu hiệu nào;
153
+ nay dùng prop `checked`.
154
+
155
+ ## [0.1.0] — 2026-11-05
156
+
157
+ Bản phát hành đầu tiên: 20 component theo số đo Lark, token Tailwind v4,
158
+ installer một lệnh, MCP server đọc specs.
159
+
160
+ ### Added — Phase 1: nền tảng
161
+
162
+ - Scaffold package `lily-lark-ui` (TypeScript strict, Vite + Vitest + jsdom,
163
+ RTL + axe), build `tsc` sinh `dist/index.js` + `dist/index.d.ts`.
164
+ - Token Lark tại `src/styles/lark-tokens.css`: màu (brand `#1456F0`), chữ,
165
+ bo góc (`--radius-lg: 6px`), hiệu ứng hai tầng (micro `120ms ease-base`,
166
+ overlay `300ms` vào / `200ms` ra), hai khối tối (`prefers-color-scheme`
167
+ và `[data-theme='dark']`), `prefers-reduced-motion`.
168
+ - `cn()` (clsx + tailwind-merge) và script `check:lark` chặn hex trong TSX,
169
+ `dark:`, icon unicode/emoji, `#3370FF`, duration literal.
170
+ - Component: `LarkButton` (24/28/32/40 PC, 32 mặc định, 40 form, responsive
171
+ mobile 36/48), `LarkTextField` (42 mobile / 36 PC), `LarkDropdownMenu`,
172
+ `LarkTabs` (34px, indicator 3px), `LarkTooltip` (delay 300ms).
173
+ - Registry shadcn (`registry.json`), README, INSTALL, AGENTS, skill
174
+ `lark-ui`, MCP server `lui_list/lui_get/lui_search/lui_tokens`.
175
+ - Installer `scripts/install.sh`: dry-run mặc định, `--apply`, `--skip-install`,
176
+ idempotent, backup `opencode.jsonc`.
177
+ - Playwright visual: không tràn ngang 375/768/1280, nút 36@375–32@1280,
178
+ input 42@375–36@1280, dropdown trong viewport, motion 0.12s / 0.3s,
179
+ reduced-motion về 0s.
180
+
181
+ ### Added — Phase 2: form và overlay
182
+
183
+ - `LarkTextArea` (dùng lại `inputClass`, tối thiểu 3 dòng 72px).
184
+ - `LarkSelect` (trigger/item 32px, popover rộng bằng trigger, motion overlay).
185
+ - `LarkCheckbox` (16px, bo 4, check 12px), `LarkRadioGroup` (16px, viền 5px),
186
+ `LarkSwitch` (rãnh 36×20, núm 16).
187
+ - `LarkDialog` (+ `Content`/`Footer`, r=8, đệm 20/24, footer full-bleed),
188
+ `LarkAlertDialog` (chặn Escape và disable nút khi `isPending`).
189
+ - `LarkToast` + `LarkToastProvider` + `useLarkToast` (nền n900, slide-up, 4s,
190
+ swipe right, pill trên mobile).
191
+ - `LarkSpinner` (16/24), `LarkEmptyState`.
192
+ - Chuẩn hoá prop: `disabled` cho trạng thái native; `isPending`/`isInvalid`/
193
+ `isIconOnly` cho trạng thái riêng của thư viện.
194
+ - `forwardRef` cho toàn bộ component có phần tử gốc tương tác.
195
+
196
+ ### Added — Phase 3: hiển thị dữ liệu và phát hành
197
+
198
+ - `LarkTable` (+ `Wrapper`, `Footer`, cột `pin: 'right'` dính phải, header
199
+ `sticky top-0`, skeleton loading, `LarkTruncatedCell`).
200
+ - `LarkPagination` (+ `pageWindow` cửa sổ 7 mục, nút 28px, active bo 6px,
201
+ chọn số dòng qua `LarkSelect`).
202
+ - `LarkTag` (24/16, 5 màu), `LarkBadge` (14px, `99+`, dot), `LarkAvatar`
203
+ (20/32/36, initials, nhóm tròn 36px).
204
+ - Installer: `--components <list>` cài lẻ theo registry, kiểm Tailwind v4
205
+ (chỉ cảnh báo), chạy `check-lark` trên repo đích (chỉ báo cáo), E2E
206
+ `pnpm pack` → cài tarball → `vite build` fixture.
207
+ - Docs: 20 trang `specs/`, skill mapping 20 component + quy tắc bố cục
208
+ trang, registry 20 item.
209
+ - Package phát hành kèm `registry.json`, `skill/`, `specs/`, `mcp/`,
210
+ `scripts/`, `INSTALL.md`.
211
+
212
+ ### Fixed
213
+
214
+ - Tailwind v4 không sinh utility `duration-*` vì sai namespace → đổi sang
215
+ `--transition-duration-*`; `anim-overlay-*` chuyển thành `@utility` để
216
+ variant `data-[state=*]` hoạt động.
217
+ - CSS token còn 3 dòng `@import` giữa file làm vỡ build khi app import.
218
+ - Import alias `@/` bị giữ trong `dist` khiến consumer build lỗi → đổi sang
219
+ import tương đối trong `src/components`.
220
+ - `spinner.tsx` dùng `process.env` thiếu type → thêm `@types/node` cho build.
221
+ - Pagination từng thiếu `lucide-react` trong registry dependencies.
222
+ - Avatar nhóm từng bo vuông do đọc sai nguồn → luôn tròn theo Figma.
223
+
224
+ ### Known limitations
225
+
226
+ - `LarkTable` chưa `forwardRef` (component generic, không có use case ref).
227
+ - Tag màu `warning` dùng `brand-support` vì token chưa có `--color-lark-warning`.
228
+ - `check-lark` chỉ quét `.ts`/`.tsx`, bỏ qua file CSS.
229
+ - Núm `LarkSwitch` 16px trong khi Figma ghi 20×20; rãnh giữ đúng 36×20 nên
230
+ núm nhỏ hơn nguồn 4px (đã ghi trong `specs/switch.md`).
231
+ - `LarkTooltip` dùng delay 300ms theo chuẩn overlay của repo; file Figma
232
+ feedback không ghi số delay riêng.
233
+
234
+ [0.1.1]: https://github.com/KINHMATLILY/lark-ui/releases/tag/v0.1.1
235
+ [0.1.0]: https://github.com/KINHMATLILY/lark-ui/releases/tag/v0.1.0
package/INSTALL.md ADDED
@@ -0,0 +1,278 @@
1
+ # Cài đặt lily-lark-ui
2
+
3
+ ## Cài từ npm (sau khi package được publish)
4
+
5
+ ```bash
6
+ npx lily-lark-ui init
7
+ ```
8
+
9
+ Nếu `npx` báo không tìm thấy package, nghĩa là chưa publish lên registry — xem
10
+ mục "Phát hành" bên dưới, hoặc cài từ tarball.
11
+
12
+ ## Phát hành (dành cho maintainer)
13
+
14
+ Package dùng tên không scope: `lily-lark-ui`. Không cần tạo org, không cần
15
+ quyền trên scope nào.
16
+
17
+ Một lần chuẩn bị:
18
+
19
+ 1. Tạo tài khoản npm: https://www.npmjs.com/signup
20
+ 2. `npm login` rồi `npm whoami` để xác nhận.
21
+
22
+ Sau đó:
23
+
24
+ ```bash
25
+ cd ~/Sites/lark-ui
26
+ pnpm release:dry # kiểm tra toàn bộ, không publish
27
+ pnpm release # publish thật
28
+ ```
29
+
30
+ Nếu tài khoản bật 2FA, `npm publish` sẽ dừng ở `EOTP`. Tạo một **Automation
31
+ token** tại https://www.npmjs.com/settings/<user>/tokens (loại Automation bỏ qua
32
+ OTP) rồi thêm vào `~/.npmrc`:
33
+
34
+ ```bash
35
+ echo '//registry.npmjs.org/:_authToken=<token>' >> ~/.npmrc
36
+ ```
37
+
38
+ Script tự: kiểm đăng nhập, build, test, `check-lark`, `publint`, pack tarball
39
+ rồi `import()` thật bằng Node ESM, kiểm kích thước, `npm publish`, và cuối cùng
40
+ cài lại từ registry để xác nhận.
41
+
42
+ Nếu sau này muốn đổi tên (ví dụ sang scope riêng):
43
+
44
+ ```bash
45
+ node scripts/rename-package.mjs --name @user/lark-ui # dry-run trước, bỏ --dry-run để ghi
46
+ ```
47
+
48
+ ## Yêu cầu bắt buộc
49
+
50
+ | Thứ | Phiên bản | Vì sao |
51
+ |---|---|---|
52
+ | **Tailwind CSS** | **v4** (`^4.0.0`) | Token dùng `@theme`/`@utility` của Tailwind v4. **v3 không chạy được.** |
53
+ | `@tailwindcss/vite` | `^4.0.0` | Plugin build; không dùng PostCSS config kiểu v3. |
54
+ | React / React DOM | `^19.0.0` | peerDependency của package. |
55
+ | Node | `>= 20` | ESM + Vite hiện hành. |
56
+
57
+ ## Cách nhanh nhất — một lệnh CLI
58
+
59
+ ```bash
60
+ npx lily-lark-ui init
61
+ ```
62
+
63
+ Chạy trong thư mục app. CLI tự: cài `lily-lark-ui`, cài Tailwind v4 (nếu
64
+ thiếu), thêm plugin vào `vite.config.ts`, chèn `@import` + `@source`, ghi
65
+ `components.json`, symlink skill, chèn MCP, smoke test, `check-lark`.
66
+
67
+ Các lệnh khác:
68
+
69
+ ```bash
70
+ npx lily-lark-ui init --repo ../app # cài vào app khác
71
+ npx lily-lark-ui init --dry-run # xem kế hoạch, không ghi
72
+ npx lily-lark-ui init --no-bootstrap # không cài Tailwind/sửa vite config
73
+ npx lily-lark-ui init --components button,table
74
+ npx lily-lark-ui check # chạy check-lark trên ./src
75
+ npx lily-lark-ui tokens # in bảng token
76
+ npx lily-lark-ui --help
77
+ ```
78
+
79
+ Yêu cầu: chạy trong repo đã có `package.json` + `react`.
80
+
81
+ ### Nếu gọi thẳng installer (không qua CLI)
82
+
83
+ ```bash
84
+ bash ~/Sites/lark-ui/scripts/install.sh --repo . --apply --bootstrap
85
+ ```
86
+
87
+ Nếu package chưa publish lên registry, trỏ tới tarball:
88
+
89
+ ```bash
90
+ cd ~/Sites/lark-ui && pnpm pack
91
+ LARK_UI_TARBALL=~/Sites/lark-ui/lily-lark-ui-0.2.0.tgz \
92
+ bash ~/Sites/lark-ui/scripts/install.sh --repo . --apply --bootstrap
93
+ ```
94
+
95
+ Lưu ý: `--bootstrap` cần `--apply` để ghi thật; thiếu `--apply` là dry-run.
96
+ Installer không cài được `react`/`vite` — repo phải là app Vite + React sẵn.
97
+
98
+ ## Không dùng Vite
99
+
100
+ `--bootstrap` tự nhận bundler và chỉ cài phần cần:
101
+
102
+ | Bundler | Installer làm | Việc bạn cần làm |
103
+ |---|---|---|
104
+ | **Vite** | cài `tailwindcss@^4` + `@tailwindcss/vite`, sửa `vite.config.ts` | không cần gì |
105
+ | **Next.js 15+** | chỉ cài `tailwindcss@^4` (không cài plugin Vite) | thêm 3 dòng vào `app/globals.css` |
106
+ | **Nuxt** | chỉ cài `tailwindcss@^4` | thêm `@tailwindcss/vite` vào `nuxt.config` mục `vite.plugins`, khai `css: ['~/assets/css/main.css']` |
107
+ | **Astro** | chỉ cài `tailwindcss@^4` | thêm `tailwindcss()` vào `astro.config.mjs` > `vite.plugins` |
108
+ | **CRA** | chỉ cài `tailwindcss@^4` | CRA không hỗ trợ Tailwind v4 trực tiếp; cần eject hoặc chuyển sang Vite |
109
+ | **Khác** | chỉ cài `tailwindcss@^4` | tự làm theo tài liệu bundler đó |
110
+
111
+ Với mọi bundler, CSS vẫn cần đúng 3 dòng:
112
+
113
+ ```css
114
+ @import "tailwindcss";
115
+ @import "lily-lark-ui/styles.css";
116
+ @source "../node_modules/lily-lark-ui/src";
117
+ ```
118
+
119
+ Đường dẫn `@source` tính từ file CSS. Với Next.js đặt ở `app/globals.css` thì
120
+ `../node_modules/...` trỏ từ `app/` — kiểm lại bằng
121
+ `grep -c 'bg-brand-secondary' .next/static/css/*.css` sau khi build.
122
+
123
+ ### Next.js: ví dụ đầy đủ
124
+
125
+ ```css
126
+ /* app/globals.css */
127
+ @import "tailwindcss";
128
+ @import "lily-lark-ui/styles.css";
129
+ @source "../node_modules/lily-lark-ui/src";
130
+ ```
131
+
132
+ `next.config.ts` không cần sửa — Next 15 dùng PostCSS nội bộ cho `@import` CSS.
133
+
134
+ ## Cách thủ công (nếu muốn kiểm soát từng bước)
135
+
136
+ Cài Tailwind v4 trước khi cài thư viện:
137
+
138
+ ```bash
139
+ npm i -D tailwindcss@^4 @tailwindcss/vite
140
+ ```
141
+
142
+ Thêm plugin vào `vite.config.ts`:
143
+
144
+ ```ts
145
+ import tailwindcss from '@tailwindcss/vite'
146
+
147
+ export default defineConfig({ plugins: [react(), tailwindcss()] })
148
+ ```
149
+
150
+ ## Ba bước bắt buộc trong entry CSS
151
+
152
+ Tailwind v4 **không tự quét `node_modules`**, nên ngoài `@import` còn phải có
153
+ `@source` trỏ tới package. Thiếu `@source`, component render ra không có style
154
+ (nút mất nền, sai chiều cao) dù build không báo lỗi.
155
+
156
+ ```css
157
+ /* src/index.css */
158
+ @import "tailwindcss";
159
+ @import "lily-lark-ui/styles.css";
160
+
161
+ /* Bắt buộc: sinh utility dùng trong component của thư viện */
162
+ @source "../node_modules/lily-lark-ui/src";
163
+ ```
164
+
165
+ Đường dẫn `@source` tính từ file CSS. Nếu entry CSS nằm ở `src/index.css` thì
166
+ `../node_modules/...` là đúng; nếu ở chỗ khác thì chỉnh lại.
167
+
168
+ **Thứ tự quan trọng:** `@import "tailwindcss"` phải đứng trước
169
+ `@import "lily-lark-ui/styles.css"`.
170
+
171
+ ## Cài đặt
172
+
173
+ ### Cách A — npm
174
+
175
+ ```bash
176
+ pnpm add lily-lark-ui
177
+ ```
178
+
179
+ Nếu package chưa publish lên registry, cài từ tarball:
180
+
181
+ ```bash
182
+ # trong repo lark-ui
183
+ pnpm pack # sinh lily-lark-ui-<version>.tgz
184
+
185
+ # trong repo đích
186
+ pnpm add ./lily-lark-ui-0.2.0.tgz
187
+ ```
188
+
189
+ Dùng component:
190
+
191
+ ```tsx
192
+ import { LarkButton } from 'lily-lark-ui'
193
+
194
+ export function Demo() {
195
+ return <LarkButton variant="primary">Lưu</LarkButton>
196
+ }
197
+ ```
198
+
199
+ ### Cách B — script tự động
200
+
201
+ ```bash
202
+ scripts/install.sh --repo <path> [--apply] [--skip-install] [--components <list>]
203
+ ```
204
+
205
+ - `<path>`: repo đích.
206
+ - Không truyền `--apply` thì dry-run (chỉ in kế hoạch, không sửa file).
207
+ - `--apply`: ghi thật.
208
+ - `--skip-install`: bỏ qua `pnpm add` (dùng khi đã cài tarball, hoặc test offline).
209
+ - `--components <list>`: cài lẻ vài component, cách nhau bằng phẩy
210
+ (`button,table`); tự thêm tiền tố `lark-`; tên sai thì exit 1 kèm danh sách
211
+ tên hợp lệ.
212
+ - Idempotent: chạy lại nhiều lần không trùng lặp.
213
+
214
+ Các bước installer thực hiện:
215
+
216
+ 1. `pnpm add lily-lark-ui`.
217
+ 1b. Kiểm Tailwind v4 trong `package.json` đích. **Thiếu hoặc v3 → không chèn
218
+ CSS** (vì sẽ làm `vite build` hỏng), chỉ cảnh báo và in hướng dẫn cài.
219
+ 2. Chèn `@import "lily-lark-ui/styles.css"` ngay sau `@import "tailwindcss"`
220
+ (nhận cả nháy đơn và nháy kép).
221
+ 2b. Thêm `@source "../node_modules/lily-lark-ui/src"` — bắt buộc với Tailwind v4.
222
+ 2c. Nếu có `--components`: copy file component theo `registry.json`
223
+ + `src/lib/utils.ts` + `src/styles/lark-tokens.css` (chỉ khi chưa có).
224
+ 3. Ghi `components.json` (dạng shadcn) nếu chưa có.
225
+ 4. Symlink skill `lark-ui` vào `~/.config/opencode/skills/`.
226
+ 5. Chèn block MCP `lark-ui` vào `~/.config/opencode/opencode.jsonc`
227
+ (backup trước khi sửa).
228
+ 6. Smoke test `lui_list`.
229
+ 7. Chạy `check-lark` trên `src/` đích (chỉ báo cáo, không fail cài).
230
+
231
+ ### Nếu app đã có CSS riêng (không dùng Tailwind từ đầu)
232
+
233
+ CSS cũ đặt ngoài `@layer` sẽ **đè** utility của component (rule `button { font:
234
+ inherit }` thắng `h-8`). Bọc CSS cũ vào `@layer base`:
235
+
236
+ ```css
237
+ @import "tailwindcss";
238
+ @import "lily-lark-ui/styles.css";
239
+ @source "../node_modules/lily-lark-ui/src";
240
+
241
+ @layer base {
242
+ /* toàn bộ CSS cũ của app ở đây */
243
+ }
244
+ ```
245
+
246
+ ## Kiểm tra sau khi cài
247
+
248
+ ```bash
249
+ npm run build # phải PASS
250
+ ```
251
+
252
+ Trong CSS build ra phải thấy utility của thư viện:
253
+
254
+ ```bash
255
+ grep -c 'bg-brand-secondary' dist/assets/*.css # > 0
256
+ ```
257
+
258
+ Nếu bằng 0 → thiếu `@source` hoặc sai đường dẫn.
259
+
260
+ ## Chế độ tối
261
+
262
+ Không dùng class `dark:`. Đặt `data-theme="dark"` trên `<html>`:
263
+
264
+ ```ts
265
+ document.documentElement.dataset.theme = 'dark'
266
+ ```
267
+
268
+ Token tự đổi. Nếu không set gì, thư viện theo `prefers-color-scheme` của hệ
269
+ điều hành.
270
+
271
+ ## Lỗi thường gặp
272
+
273
+ | Hiện tượng | Nguyên nhân | Cách sửa |
274
+ |---|---|---|
275
+ | Component không có style, nút trong suốt | Thiếu `@source` | Thêm `@source "../node_modules/lily-lark-ui/src"` |
276
+ | `ENOENT: lily-lark-ui/styles.css` | Repo chưa có Tailwind, hoặc chưa `pnpm add` | Cài Tailwind v4 + package |
277
+ | Style bị đè, chiều cao sai | CSS cũ ngoài `@layer` | Bọc CSS cũ vào `@layer base` |
278
+ | Màu không đổi khi bật tối | Thiếu `[data-theme]` trên `<html>` | Set `data-theme` |
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 LILY-EYE
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,124 @@
1
- # Temporary Holding Version
1
+ # lily-lark-ui
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Thu vien component React theo phong cach Lark (Universe Design), dung kieu shadcn:
4
+ copy-paste component Tailwind v4 + Radix headless. Hien co 20 component.
5
+
6
+ ## Cài đặt
7
+
8
+ Xem [INSTALL.md](./INSTALL.md) để biết đầy đủ. Tóm tắt 2 đường:
9
+
10
+ - **CLI (khuyến nghị):** `npx lily-lark-ui init` — tự cài Tailwind v4, sửa
11
+ `vite.config.ts`, chèn CSS + `@source`.
12
+ - npm thủ công: `pnpm add lily-lark-ui` rồi tự thêm 3 dòng CSS.
13
+ - script: `scripts/install.sh --repo <path> --apply` (nếu dùng source checkout).
14
+
15
+ ### Yêu cầu bắt buộc
16
+
17
+ | Thứ | Phiên bản | Ghi chú |
18
+ |---|---|---|
19
+ | **Tailwind CSS** | **v4** (`^4.0.0`) | Token dùng `@theme`/`@utility` của v4. **v3 không chạy.** |
20
+ | `@tailwindcss/vite` | `^4.0.0` | Plugin build (không dùng PostCSS config kiểu v3). |
21
+ | React / React DOM | `^19.0.0` | peerDependency. |
22
+ | Node | `>= 20` | ESM + Vite hiện hành. |
23
+
24
+ ```bash
25
+ npm i -D tailwindcss@^4 @tailwindcss/vite
26
+ ```
27
+
28
+ ### Ba dòng bắt buộc trong entry CSS
29
+
30
+ Tailwind v4 **không tự quét `node_modules`**. Thiếu `@source` thì component
31
+ render ra không có style (nút trong suốt, sai chiều cao) dù build không báo lỗi.
32
+
33
+ ```css
34
+ @import "tailwindcss";
35
+ @import "lily-lark-ui/styles.css";
36
+ @source "../node_modules/lily-lark-ui/src";
37
+ ```
38
+
39
+ `@import "tailwindcss"` phải đứng trước import của thư viện. Nếu app đã có CSS
40
+ riêng, bọc CSS đó vào `@layer base` để không đè utility của component.
41
+
42
+ Kiểm tra sau khi build: `grep -c 'bg-brand-secondary' dist/assets/*.css` phải
43
+ lớn hơn 0.
44
+
45
+ ## Cai vao repo moi
46
+
47
+ Mot lenh (6 buoc + kiem Tailwind v4, copy --components neu co, check-lark report):
48
+
49
+ ```bash
50
+ scripts/install.sh --repo <path> --apply [--components button,text-field]
51
+ ```
52
+
53
+ - Khong truyen `--apply` thi dry-run: chi in ke hoach, khong sua file.
54
+ - `--skip-install`: bo qua buoc `pnpm add` (dung cho test offline).
55
+ - `--components <list>`: chi copy component can (ten cach nhau boi dau phay,
56
+ vd `button,text-field`); kem `src/lib/utils.ts` + `src/styles/lark-tokens.css`
57
+ neu chua co. Ten sai thi bao loi + liet ke ten hop le.
58
+ - Idempotent: chay lai khong them trung import/block MCP.
59
+
60
+ ## Component
61
+
62
+ | Component | Import | Props chinh | So do |
63
+ |---|---|---|---|
64
+ | LarkButton | `import { LarkButton } from 'lily-lark-ui'` | `variant` (primary/secondary/danger/ghost/text), `size` (xs/sm/md/lg), `isIconOnly`, `fullWidth`, `isPending`, `asChild` | 32px mac dinh (h-8), 40px nut chinh form (h-10), 28/24 nho; mobile 36/48px |
65
+ | LarkTextField (+inputClass) | `import { LarkTextField } from 'lily-lark-ui'` | `label`, `error`, `description`, `isRequired`, `isInvalid` | Cao 42 mobile / 36 PC (`md:min-h-9`), chu 16 mobile / 14 PC |
66
+ | LarkDropdownMenu | `import { LarkDropdownMenu } from 'lily-lark-ui'` | `trigger`, `align` (start/center/end); `Item` (`value`, `onSelect?`, `danger?`, `disabled?`, `checked?`) | Popover toi thieu 200 rong, bo goc 8, bong overlay; item 32px, dropdown vien #DEE0E3 qua token; dong menu (Escape/chon/click ngoai) tra focus ve trigger, click lai dong menu |
67
+ | LarkTabs | `import { LarkTabs } from 'lily-lark-ui'` | `defaultValue`/`value`/`onValueChange`, `LarkTabs.List/Tab/Panel` | Tab cao 34, gach duoi tab kich hoat |
68
+ | LarkTooltip (+LarkTooltipProvider) | `import { LarkTooltip, LarkTooltipProvider } from 'lily-lark-ui'` | `content`, `side` (top/right/bottom/left); Provider `delayDuration` (=300), `skipDelayDuration?` | delay 300ms, lech 6, overlay 300ms ease-out; render doc lap van mo (fallback), trong Provider dung chung |
69
+ | LarkTextArea | `import { LarkTextArea } from 'lily-lark-ui'` | `label`, `error`, `isRequired` (ke thua moi prop `textarea`) | toi thieu 72px (~3 dong), chu 16 mobile / 14 PC |
70
+ | LarkSelect | `import { LarkSelect } from 'lily-lark-ui'` | `options`, `value`/`onValueChange`, `placeholder`, `disabled`, `isInvalid` | trigger 32px (`h-8`) bo 6 (`rounded-lg`), item 32px, dropdown bo 6 vien `#DEE0E3` qua token |
71
+ | LarkCheckbox | `import { LarkCheckbox } from 'lily-lark-ui'` | `label`, `checked` (true/false/'indeterminate'), `onCheckedChange` | khung 16px (`size-4`) bo 4, dau `size-3` trang |
72
+ | LarkRadioGroup | `import { LarkRadioGroup } from 'lily-lark-ui'` | `label?`, `options`, `value`/`onValueChange` | khung 16px tron, cham chon vien brand 5px |
73
+ | LarkSwitch | `import { LarkSwitch } from 'lily-lark-ui'` | `label?`, `checked`/`onCheckedChange` | ranh 36x20 (`h-5 w-9`), num 16px trang |
74
+ | LarkDialog | `import { LarkDialog } from 'lily-lark-ui'` | `open`/`onOpenChange`, `Content` (`title`, `description?`), `Footer` | bo 8 (`rounded-xl`), dem 20 mobile / 24 PC, toi da `max-w-md` |
75
+ | LarkAlertDialog | `import { LarkAlertDialog } from 'lily-lark-ui'` | `title`, `confirmLabel`, `cancelLabel` (=`Huy`), `onConfirm`, `isPending` | khung nhu dialog; pending chan Escape + disable nut huy |
76
+ | LarkToast (+Provider/useLarkToast) | `import { LarkToastProvider, useLarkToast } from 'lily-lark-ui'` | `toast({ title, description?, variant? })` (default/success/danger) | nen `n900`, bo 8 / pill mobile, hien 4s, quet phai de tat |
77
+ | LarkSpinner / LarkEmptyState | `import { LarkSpinner, LarkEmptyState } from 'lily-lark-ui'` | Spinner `size` (sm/md), `label` bat buoc; EmptyState `icon`, `title`, `description?`, `action?` | spinner 16/24px xoay `n500`; empty can giua, icon 24px, dem doc 40px |
78
+ | LarkTable (+Wrapper/Footer/TruncatedCell) | `import { LarkTable, LarkTableWrapper, LarkPagination } from 'lily-lark-ui'` | `columns`, `rows`, `rowKey`, `isLoading?`, `emptyState?`; cot `pin: 'right'`; caller tu boc `<LarkTable.Footer>` quanh `<LarkPagination>` | head 48 (`h-12`), body 47 (`h-[47px]`), divider `n200/n300`, ghim `z-10/z-20`, skeleton `animate-pulse` |
79
+ | LarkPagination (+pageWindow) | `import { LarkPagination } from 'lily-lark-ui'` | `page`, `total`, `pageSize`, `onPageChange`, `pageSizes?` (mac dinh `[50, 100, 200]`), `onPageSizeChange?`, `isLoading?` | nut 28 (`size-7`), active 28x28 bo 6 (rounded-lg = --radius-lg 6px), footer `py-2 px-3`, pageWindow toi da 7 |
80
+ | LarkTag | `import { LarkTag } from 'lily-lark-ui'` | `color` (blue/gray/success/danger/warning), `size` (md/sm) | cao 24 md (`h-6`) / 16 sm (`h-4`), bo 4 (`rounded-sm`) |
81
+ | LarkBadge | `import { LarkBadge } from 'lily-lark-ui'` | `count?`, `max` (=`99`), `dot?` | cao 14 (`h-[14px]`), cham `size-2`, pill do `rounded-full` |
82
+ | LarkAvatar (+getInitials) | `import { LarkAvatar } from 'lily-lark-ui'` | `name?`, `src?`, `team?`, `size` (sm/md/lg) | 20 sm (`size-5`) / 32 md (`size-8`) / 36 lg (`size-9`), team tron 36px (alias size lg) |
83
+
84
+ ## Nguon so do
85
+
86
+ Moi so do trong thu vien lay tu `~/Sites/lily-projects/lark-design-guide`:
87
+ uu tien mau noi bo `patterns/`, sau do so do goc Figma `figma/`
88
+ (buttons, list, navigation, action-menu, feedback).
89
+ Chi tiet xem `docs/specs/2026-11-05-lark-ui.md`.
90
+
91
+ ## Vi du
92
+
93
+ ```tsx
94
+ import { LarkButton, LarkTextField } from 'lily-lark-ui'
95
+ import 'lily-lark-ui/styles.css'
96
+
97
+ export function LoginForm() {
98
+ return (
99
+ <form>
100
+ <LarkTextField label="So dien thoai" placeholder="Nhap so dien thoai" isRequired />
101
+ <LarkButton type="submit">Dang nhap</LarkButton>
102
+ </form>
103
+ )
104
+ }
105
+ ```
106
+
107
+ ```tsx
108
+ import { LarkTable, LarkTableWrapper, LarkPagination } from 'lily-lark-ui'
109
+
110
+ export function RecordsTable({ columns, rows, page, total, pageSize, onPageChange }) {
111
+ return (
112
+ <LarkTableWrapper>
113
+ <LarkTable columns={columns} rows={rows} rowKey={(r) => r.id} />
114
+ <LarkTable.Footer>
115
+ <LarkPagination page={page} total={total} pageSize={pageSize} onPageChange={onPageChange} />
116
+ </LarkTable.Footer>
117
+ </LarkTableWrapper>
118
+ )
119
+ }
120
+ ```
121
+
122
+ ## Phat trien
123
+
124
+ Xem [AGENTS.md](./AGENTS.md) truoc khi sua code.