@fwkui/x-css 1.0.10 → 1.0.12

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/DICTIONARY.md CHANGED
@@ -246,8 +246,8 @@ These abbreviations work with almost all properties (where applicable).
246
246
  | `ins` | **inline-size** | _(raw values)_ | `ins10px`<br/>*(inline-size: 10px)* |
247
247
  | `is` | **isolation** | `i`: isolate | `isI`<br/>*(isolation: isolate)* |
248
248
  | `jc` | **justify-content** | `c`: center<br/> `s`: start<br/> `e`: end<br/> `fs`: flex-start<br/> `fe`: flex-end<br/> `l`: left<br/> `r`: right<br/> `n`: normal<br/> `sp`: space-between<br/> `sa`: space-around<br/> `se`: space-evenly<br/> `st`: stretch<br/> `sc`: safe center<br/> `uc`: unsafe center | `jcC`<br/>*(justify-content: center)* |
249
- | `ji` | **justify-items** | `n`: normal<br/> `st`: stretch<br/> `c`: center<br/> `s`: start<br/> `e`: end<br/> `fs`: flex-start<br/> `fe`: flex-end<br/> `ss`: self-start<br/> `se`: self-end<br/> `l`: left<br/> `r`: right<br/> `b`: baseline<br/> `fb`: first baseline<br/> `lb`: last baseline<br/> `lr`: legacy right<br/> `ll`: legacy left<br/> `lc`: legacy center<br/> `sc`: safe center<br/> `uc`: unsafe center | `jiN`<br/>*(justify-items: normal)* |
250
- | `js` | **justify-self** | `n`: normal<br/> `st`: stretch<br/> `c`: center<br/> `s`: start<br/> `e`: end<br/> `fs`: flex-start<br/> `fe`: flex-end<br/> `ss`: self-start<br/> `se`: self-end<br/> `l`: left<br/> `r`: right<br/> `b`: baseline<br/> `sc`: safe center<br/> `uc`: unsafe center | `jsN`<br/>*(justify-self: normal)* |
249
+ | `ji` | **justify-items** | `c`: center<br/> `s`: start<br/> `e`: end<br/> `fs`: flex-start<br/> `fe`: flex-end<br/> `l`: left<br/> `r`: right<br/> `n`: normal<br/> `sp`: space-between<br/> `sa`: space-around<br/> `se`: space-evenly<br/> `st`: stretch<br/> `sc`: safe center<br/> `uc`: unsafe center | `jiC`<br/>*(justify-items: center)* |
250
+ | `js` | **justify-self** | `c`: center<br/> `s`: start<br/> `e`: end<br/> `fs`: flex-start<br/> `fe`: flex-end<br/> `l`: left<br/> `r`: right<br/> `n`: normal<br/> `sp`: space-between<br/> `sa`: space-around<br/> `se`: space-evenly<br/> `st`: stretch<br/> `sc`: safe center<br/> `uc`: unsafe center | `jsC`<br/>*(justify-self: center)* |
251
251
  | `l` | **left** | _(raw values)_ | `l10px`<br/>*(left: 10px)* |
252
252
  | `lbrk` | **line-break** | _(raw values)_ | `lbrkUn`<br/>*(line-break: unset)* |
253
253
  | `lh` | **line-height** | _(raw values)_ | `lh10px`<br/>*(line-height: 10px)* |
@@ -335,7 +335,7 @@ These abbreviations work with almost all properties (where applicable).
335
335
  | `pgba` | **page-break-after** | _(raw values)_ | `pgbaPage`<br/>*(page-break-after: page)* |
336
336
  | `pgbb` | **page-break-before** | _(raw values)_ | `pgbbPage`<br/>*(page-break-before: page)* |
337
337
  | `pgbi` | **page-break-inside** | _(raw values)_ | `pgbiPage`<br/>*(page-break-inside: page)* |
338
- | `pi` | **padding-inline** | `s`: start<br/> `c`: center<br/> `e`: end<br/> `b`: baseline<br/> `st`: stretch | `piS`<br/>*(padding-inline: start)* |
338
+ | `pi` | **padding-inline** | `c`: center<br/> `s`: start<br/> `e`: end<br/> `fs`: flex-start<br/> `fe`: flex-end<br/> `l`: left<br/> `r`: right<br/> `n`: normal<br/> `sp`: space-between<br/> `sa`: space-around<br/> `se`: space-evenly<br/> `st`: stretch<br/> `sc`: safe center<br/> `uc`: unsafe center | `piC`<br/>*(padding-inline: center)* |
339
339
  | `pie` | **padding-inline-end** | _(raw values)_ | `pie10px`<br/>*(padding-inline-end: 10px)* |
340
340
  | `pis` | **padding-inline-start** | _(raw values)_ | `pis10px`<br/>*(padding-inline-start: 10px)* |
341
341
  | `pl` | **padding-left** | _(raw values)_ | `pl10px`<br/>*(padding-left: 10px)* |
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 FKUI Team
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,103 +1,230 @@
1
- # @fwkui/x-css 🚀
1
+ # @fwkui/x-css
2
2
 
3
- **@fwkui/x-css**một thư viện CSS-in-JS siêu nhẹ, hiệu năng cao, kế thừa tinh hoa từ `fwxcss` với cú pháp Emmet-like. giúp bạn viết mã CSS nhanh hơn bằng cách sử dụng các lớp atomic ngắn gọn, hỗ trợ đầy đủ TypeScript, SSR và khả năng mở rộng mạnh mẽ.
3
+ `@fwkui/x-css`utility CSS engine siêu nhẹ, parse class theo cú pháp ngắn sinh CSS runtime theo layer + media.
4
+
5
+ Mục tiêu của README này:
6
+ 1. Người dùng có thể tích hợp ngay.
7
+ 2. AI có thể suy luận đúng cú pháp để sinh class dùng được ngay.
8
+ 3. QA có thể kiểm thử parser theo vector cố định.
4
9
 
5
10
  ![License](https://img.shields.io/npm/l/@fwkui/x-css)
6
11
  ![Version](https://img.shields.io/npm/v/@fwkui/x-css)
7
12
 
8
- ---
13
+ ## Cài Đặt Nhanh
9
14
 
10
- ## 📖 Hướng dẫn Cơ bản
15
+ ### 1) NPM
11
16
 
12
- ### 1. Cú pháp Cốt lõi
13
- Mỗi class trong @fwkui/x-css được cấu tạo theo công thức:
14
- `[Media]:[Layer][Property][Value][@Selector]`
17
+ ```bash
18
+ npm install @fwkui/x-css
19
+ ```
15
20
 
16
- **Ví dụ:**
17
- - `m10px` ⮕ `margin: 10px`
18
- - `cRed` ⮕ `color: red`
19
- - `sm:p20px` ⮕ `@media (min-width: 576px) { padding: 20px }`
20
- - `3bgWhite` ⮕ `@layer l3 { background: white }`
21
- - `cBlue@:hover` ⮕ `.class:hover { color: blue }`
21
+ ### 2) Dùng trực tiếp qua URL (không cần bundler)
22
22
 
23
- ### 2. Nguyên lý Parser (Scan & Slice) 🧠
24
- Thư viện quét class từ trái sang phải và tự động cắt Property/Value dựa trên các điểm ngắt (Số, Chữ Hoa, Ký tự đặc biệt...), giúp tốc độ xử lý nhanh hơn ~1.6x so với Regex truyền thống.
23
+ Lưu ý:
24
+ 1. `dist/index.js` CommonJS (Node).
25
+ 2. Trình duyệt dùng `dist/index.mjs` hoặc `dist/index-auto.mjs`.
25
26
 
26
- | Loại điểm ngắt | Ví dụ Class | Phân tích (Prop \| Value) |
27
- | :--- | :--- | :--- |
28
- | **Số (0-9)** | `w100px` | `w` (width) \| `100px` |
29
- | **Chữ Hoa (A-Z)** | `dFlex` | `d` (display) \| `Flex` |
30
- | **Dấu gạch ngang + Số** | `m-10px` | `m` (margin) \| `-10px` |
27
+ Option A: chủ động khởi tạo
31
28
 
32
- > [!IMPORTANT]
33
- > **Lưu ý về CamelCase**: Sử dụng `mt10px` hoặc `margin-top-10px`, tránh `marginTop10px` để đảm bảo parser hoạt động chính xác.
29
+ ```html
30
+ <script type="module">
31
+ import xcss from 'https://unpkg.com/@fwkui/x-css@latest/dist/index.mjs';
34
32
 
35
- ---
33
+ xcss.cssObserve(document, {
34
+ dictionaryImport: true
35
+ });
36
+ </script>
37
+ ```
36
38
 
37
- ## 📚 Bộ Từ điển (Dictionary)
38
- Danh sách đầy đủ các từ viết tắt được cập nhật liên tục tại [DICTIONARY.md](./DICTIONARY.md).
39
+ Option B: auto observe khi import
39
40
 
40
- ### Một số Alias phổ biến:
41
- - **Layout**: `d` (display), `pos` (position), `z` (z-index), `fl` (float).
42
- - **Flexbox**: `fx` (flex), `ai` (align-items), `jc` (justify-content).
43
- - **Spacing**: `m` (margin), `p` (padding), `w` (width), `h` (height).
44
- - **Styling**: `c` (color), `bg` (background), `bd` (border), `op` (opacity).
45
- - **Typography**: `fz` (font-size), `fw` (font-weight), `ta` (text-align).
41
+ ```html
42
+ <script type="module" src="https://unpkg.com/@fwkui/x-css@latest/dist/index-auto.mjs"></script>
43
+ ```
46
44
 
47
- ---
45
+ CDN thay thế:
46
+ `https://cdn.jsdelivr.net/npm/@fwkui/x-css@latest/dist/index.mjs`
48
47
 
49
- Bạn thể tải thư viện hoặc xem mã nguồn tại: [https://github.com/dwork-dev/fwkui](https://github.com/dwork-dev/fwkui)
48
+ ## Dùng Trong 60 Giây
49
+
50
+ ```js
51
+ import xcss from '@fwkui/x-css';
50
52
 
51
- ## 📦 Cài đặt
53
+ xcss.cssObserve(document);
54
+ ```
52
55
 
53
- ### Cách 1: Dùng qua CDN (Khuyên dùng cho thử nghiệm nhanh)
54
- Thêm thẻ script sau vào `index.html`:
55
56
  ```html
56
- <script src="https://unpkg.com/@fwkui/x-css@1.0.9/dist/index.js"></script>
57
+ <button class="dF aiC jcC p10px;16px bdN bdra8px bgc#0a64e8 cWhite">
58
+ Đăng nhập
59
+ </button>
57
60
  ```
58
61
 
59
- ### Cách 2: Cài đặt qua NPM
60
- ```bash
61
- npm install @fwkui/x-css
62
+ ## Contract Pháp
63
+
64
+ Mỗi utility class theo form:
65
+
66
+ `[Media]:[Layer][Property][Value][@Selector]`
67
+
68
+ Thứ tự parse bắt buộc:
69
+ 1. `selector` (hậu tố `@...`, nằm ngoài `[]`).
70
+ 2. `media` (tiền tố trước `:`).
71
+ 3. `layer` (chuỗi số liên tiếp ở đầu).
72
+ 4. `property`.
73
+ 5. `value`.
74
+
75
+ Ý nghĩa từng phần:
76
+ 1. `Media` (tùy chọn): key media như `sm`, `md`, `lg`, hoặc key custom.
77
+ 2. `Layer` (tùy chọn): số ưu tiên cascade.
78
+ 3. `Property` (bắt buộc): alias thuộc dictionary hoặc CSS property hợp lệ.
79
+ 4. `Value` (bắt buộc với utility chuẩn): giá trị CSS, alias value hoặc arbitrary value.
80
+ 5. `@Selector` (tùy chọn): ví dụ `@:hover`, `@::before`.
81
+
82
+ Ngoại lệ parser (special syntax):
83
+ 1. `[AliasName]`: class group alias (không dùng value trực tiếp).
84
+ 2. `&...`: nhánh selector đặc biệt theo parser hiện tại.
85
+
86
+ ### Media Mặc Định Và Thứ Tự Nội Bộ
87
+
88
+ Engine nạp media theo thứ tự:
89
+
90
+ | Thứ tự | Key | Query |
91
+ | :--- | :--- | :--- |
92
+ | 1 | `default` | Không bọc `@media` |
93
+ | 2 | `xs` | `screen and (max-width: 575px)` |
94
+ | 3 | `sm` | `screen and (min-width: 576px)` |
95
+ | 4 | `md` | `screen and (min-width: 768px)` |
96
+ | 5 | `lg` | `screen and (min-width: 992px)` |
97
+ | 6 | `xl` | `screen and (min-width: 1200px)` |
98
+ | 7 | `2xl` | `screen and (min-width: 1400px)` |
99
+ | 8 | `sma` | `screen and (max-width: 768px)` |
100
+ | 9 | `mda` | `screen and (max-width: 992px)` |
101
+ | 10 | `lga` | `screen and (max-width: 1200px)` |
102
+ | 11 | `xla` | `screen and (max-width: 1400px)` |
103
+
104
+ Quy tắc custom breakpoint:
105
+ 1. `breakpoints` được nối vào sau danh sách mặc định.
106
+ 2. Nếu trùng key, key khai báo sau cùng ghi đè key trước (`last write wins`).
107
+
108
+ Ví dụ:
109
+
110
+ ```js
111
+ xcss.cssObserve(document, {
112
+ breakpoints: [
113
+ { tablet: 'screen and (min-width: 768px)' }
114
+ ]
115
+ });
62
116
  ```
63
117
 
64
- ---
118
+ Dùng class: `tablet:dB`.
65
119
 
66
- ## 🚀 Hướng dẫn Sử dụng
120
+ ### Layer Mặc Định
67
121
 
68
- ### 1. Vanilla JavaScript (Tự động)
122
+ 1. Nếu không khai báo layer, engine dùng `0`.
123
+ 2. Engine tạo sẵn 24 layer: `l0 -> l23`.
124
+ 3. Nên dùng dải `0-23` để giữ thứ tự ổn định.
125
+ 4. Số layer lớn hơn có ưu tiên cascade cao hơn trong cùng media.
69
126
 
70
- Để tự động scan apply style cho toàn bộ document:
127
+ ## Quy Tắc Điểm Ngắt Đầy Đủ (Theo Parser Hiện Tại)
71
128
 
72
- ```javascript
73
- import xcss from '@fwkui/x-css';
129
+ Mục tiêu là tách class thành tuple:
130
+ `{ media, layer, property, value, selector }`
74
131
 
75
- // Khởi tạo lắng nghe thay đổi DOM
76
- xcss.cssObserve(document);
132
+ Thứ tự suy luận bắt buộc:
133
+ 1. Tách `selector`: lấy phần sau ký tự `@` cuối cùng, chỉ khi `@` nằm ngoài `[]`.
134
+ 2. Tách `media`: nếu còn `:` thì phần trước `:` là `media`.
135
+ 3. Tách `layer`: đọc chuỗi số liên tiếp ở đầu phần còn lại.
136
+ 4. Tách `property/value`: quét trái -> phải và dừng `property` theo bảng quyết định.
137
+ 5. Nếu phần còn lại bắt đầu bằng `&` hoặc `[` thì đi vào nhánh special syntax.
138
+
139
+ ### Bảng Quyết Định Khi Quét `property`
140
+
141
+ | Ký tự đang xét | Điều kiện | Hành động |
142
+ | :--- | :--- | :--- |
143
+ | `a-z` | luôn đúng | vẫn là `property` |
144
+ | `-` hoặc `.` | ký tự kế tiếp là số | dừng `property`, phần còn lại là `value` |
145
+ | `-` | gặp `--` và đã có ít nhất 1 ký tự property | dừng `property`, bắt đầu `value` (CSS variable) |
146
+ | `-` hoặc `.` | không rơi vào 2 điều kiện trên | vẫn là `property` |
147
+ | ký tự khác (`A-Z`, `0-9`, `#`, `!`, `[`, `(`, `%`, ...) | luôn đúng | dừng `property`, phần còn lại là `value` |
148
+
149
+ ### Chuẩn Hóa `value` Sau Khi Tách
150
+
151
+ 1. Value bắt đầu bằng `!` -> thêm hậu tố `!important`.
152
+ 2. Value bắt đầu bằng `--` -> đổi thành `var(--...)`.
153
+ 3. Value dạng `[...]` -> bỏ `[` `]`, rồi thay `;` thành khoảng trắng.
154
+ 4. Ký tự `#` trong value giữ nguyên (hex color).
155
+
156
+ Pseudo-flow cho AI:
157
+
158
+ ```text
159
+ class -> selector -> media -> layer -> property -> value
160
+ if value startsWith('!') => important
161
+ if value startsWith('--') => var(value)
162
+ if value is bracketed [..] => strip brackets + replace ';' with ' '
77
163
  ```
78
164
 
79
- Sử dụng trong HTML:
165
+ ### Test Vector Mini (10 input -> expected tuple)
166
+
167
+ | # | Input | Expected tuple |
168
+ | :--- | :--- | :--- |
169
+ | 1 | `m10px` | `{ media: '', layer: '', property: 'm', value: '10px', selector: '' }` |
170
+ | 2 | `md:w100%` | `{ media: 'md', layer: '', property: 'w', value: '100%', selector: '' }` |
171
+ | 3 | `sm:3bgWhite` | `{ media: 'sm', layer: '3', property: 'bg', value: 'White', selector: '' }` |
172
+ | 4 | `cBlue@:hover` | `{ media: '', layer: '', property: 'c', value: 'Blue', selector: ':hover' }` |
173
+ | 5 | `m-10px` | `{ media: '', layer: '', property: 'm', value: '-10px', selector: '' }` |
174
+ | 6 | `opc0.8` | `{ media: '', layer: '', property: 'opc', value: '0.8', selector: '' }` |
175
+ | 7 | `bgc--brand` | `{ media: '', layer: '', property: 'bgc', value: '--brand', selector: '' }` |
176
+ | 8 | `c!#0a64e8` | `{ media: '', layer: '', property: 'c', value: '!#0a64e8', selector: '' }` |
177
+ | 9 | `w[calc(100%;-;10px)]` | `{ media: '', layer: '', property: 'w', value: '[calc(100%;-;10px)]', selector: '' }` |
178
+ | 10 | `[btnPrimary]` | `{ media: '', layer: '', property: '[btnPrimary]', value: '', selector: '' }` |
179
+
180
+ ## Bảng Sai -> Đúng (Những Lỗi Gây Vỡ Parse)
181
+
182
+ | Sai | Đúng | Giải thích |
183
+ | :--- | :--- | :--- |
184
+ | `bdn` | `bdN` | Value viết tắt dạng chữ cái phải viết hoa ký tự đầu (`N` = none). |
185
+ | `df` | `dF` | `F` là value viết tắt của `flex`. |
186
+ | `posa` | `posA` | `A` là value viết tắt của `absolute`. |
187
+ | `tr0.2s` | `tran0.2s` | Property `transition` là `tran`, không phải `tr`. |
188
+ | `op0.8` | `opc0.8` | `op` là `object-position`; `opc` mới là `opacity`. |
189
+ | `3:bgWhite` | `3bgWhite` | Layer là số đứng liền trước property, không có `:` sau layer. |
190
+ | `hover:cRed` | `cRed@:hover` | Selector modifier dùng hậu tố `@Selector`. |
191
+ | `tablet:dB` (chưa khai báo) | `tablet:dB` + `breakpoints` config | Media custom phải được khai báo trước trong config. |
192
+ | `m--10px` | `m-10px` | Số âm dùng `-`; `--` dành cho CSS variable (`bgc--brand`). |
193
+ | `bgcbrand` | `bgcBrand` hoặc `bgc--brand` | Cần điểm ngắt rõ ràng để parser tách đúng value. |
194
+ | `wcalc(100%-10px)` | `w[calc(100%;-;10px)]` | Value phức tạp nên bọc `[]`, dùng `;` để biểu diễn khoảng trắng. |
195
+ | `!cRed` | `c!Red` | `!` phải đứng trong phần value (sau property), không đứng đầu class. |
196
+
197
+ ## Ví Dụ Chính Xác Theo Dictionary
198
+
199
+ Danh sách đầy đủ alias xem tại [DICTIONARY.md](./DICTIONARY.md).
200
+
201
+ Một số alias dễ nhầm:
202
+ 1. `op` = `object-position`
203
+ 2. `opc` = `opacity`
204
+ 3. `tran` = `transition`
205
+ 4. `tr` = `transparent` (value alias, không phải property transition)
206
+
207
+ Ví dụ:
208
+
80
209
  ```html
81
- <div class="dFlex cRed m20px">Hello World</div>
210
+ <div class="dF aiC jcSB p12px;16px bdN bgcWhite"></div>
211
+ <div class="tran0.2s opc0.8@:hover"></div>
212
+ <div class="c!#0a64e8"></div>
213
+ <div class="w[calc(100%;-;10px)]"></div>
82
214
  ```
83
215
 
84
- ### 2. React / Components (`clsx`)
85
-
86
- Sử dụng `clsx` để kết hợp class động và tối ưu việc gom nhóm string (tương tự `classnames` nhưng tích hợp sẵn parser engine):
216
+ ## Dùng Trong React / Component
87
217
 
88
218
  ```jsx
89
219
  import { clsx } from '@fwkui/x-css';
90
220
 
91
- function Button({ primary, children }) {
221
+ export function Button({ primary, children }) {
92
222
  return (
93
- <button
223
+ <button
94
224
  className={clsx(
95
- 'p10px;20px', // padding: 10px 20px
96
- 'bdn bdra4px', // border: none, border-radius: 4px
97
- 'tr0.2s', // transition: 0.2s
98
- 'cWhite', // color: white
99
- primary ? 'bgBlue' : 'bgGray',
100
- 'op0.8@:hover' // Opacity 0.8 on hover
225
+ 'dF aiC jcC p10px;16px bdN bdra8px tran0.2s',
226
+ primary ? 'bgc#0a64e8 cWhite' : 'bgc#e5e7eb c#111827',
227
+ 'opc0.9@:hover'
101
228
  )}
102
229
  >
103
230
  {children}
@@ -106,118 +233,180 @@ function Button({ primary, children }) {
106
233
  }
107
234
  ```
108
235
 
109
- ### 3. Cấu hình (Configuration)
110
-
111
- Bạn có thể truyền object config khi khởi tạo:
236
+ ## Cấu Hình
112
237
 
113
- ```javascript
238
+ ```js
114
239
  import xcss from '@fwkui/x-css';
115
240
 
116
241
  xcss.cssObserve(document, {
117
- // Thêm màu sắc hoặc giá trị custom
118
242
  theme: {
119
- brand: '#ff5722',
120
- dark: '#333333'
243
+ brand: '#0a64e8',
244
+ danger: '#ef4444'
121
245
  },
122
- // Thêm breakpoint tùy chỉnh
123
246
  breakpoints: [
124
247
  { tablet: 'screen and (min-width: 768px)' }
125
248
  ],
126
- // Base CSS
127
- base: 'body { margin: 0; font-family: sans-serif; }',
128
-
129
- // [New] Thêm tiền tố (Prefix) để tránh xung đột
130
- prefix: 'fk-' // Chỉ xử lý các class bắt đầu bằng 'fk-'
249
+ base: 'body{margin:0;font-family:system-ui,sans-serif;}',
250
+ prefix: 'fk-',
251
+ dictionaryImport: true
131
252
  });
132
253
  ```
133
254
 
134
- Sau đó sử dụng: `fk-cBrand`, `fk-tablet:dBlock`.
135
- Các class không có tiền tố (ví dụ `m10px`) sẽ bị **bỏ qua**.
255
+ Sau đó dùng class: `fk-cBrand fk-tablet:dB`.
256
+
257
+ `dictionaryImport`:
258
+ 1. `true` (mặc định): dùng dictionary tích hợp.
259
+ 2. `false`: tắt dictionary mặc định.
260
+ 3. `string` URL/path: import dictionary ngoài.
136
261
 
137
- ### 4. Server-Side Rendering (SSR)
262
+ Nếu import dictionary ngoài:
263
+
264
+ ```js
265
+ const engine = xcss.css({ dictionaryImport: 'https://cdn.example.com/xcss-dict.mjs' });
266
+ await engine.ready;
267
+ const { clsx, observe } = engine.buildCss(document);
268
+ observe();
269
+ ```
138
270
 
139
- Để hỗ trợ SSR (Next.js, Remix...), bạn cần inject CSS sinh ra từ server vào thẻ `<head>`:
271
+ Mẫu file để thay thế trực tiếp URL `https://cdn.example.com/xcss-dict.mjs`:
272
+
273
+ ```js
274
+ // xcss-dict.mjs
275
+ // Có thể public lên CDN của bạn rồi truyền URL vào dictionaryImport
276
+
277
+ export const SHORT_PROPERTIES = {
278
+ d: 'display',
279
+ c: 'color',
280
+ bgc: 'background-color',
281
+ bd: 'border',
282
+ w: 'width',
283
+ h: 'height',
284
+ p: 'padding',
285
+ m: 'margin',
286
+ tran: 'transition',
287
+ opc: 'opacity'
288
+ };
289
+
290
+ export const COMMON_VALUES = {
291
+ n: 'none',
292
+ b: 'block',
293
+ f: 'flex',
294
+ t: 'transparent',
295
+ i: 'inherit'
296
+ };
297
+
298
+ export const SPECIFIC_VALUES = {
299
+ d: {
300
+ f: 'flex',
301
+ b: 'block',
302
+ ib: 'inline-block'
303
+ },
304
+ bd: {
305
+ n: 'none'
306
+ },
307
+ c: {
308
+ pri: '#0a64e8',
309
+ danger: '#ef4444'
310
+ },
311
+ bgc: {
312
+ pri: '#0a64e8',
313
+ soft: '#e8f1ff'
314
+ }
315
+ };
316
+
317
+ export default {
318
+ SHORT_PROPERTIES,
319
+ COMMON_VALUES,
320
+ SPECIFIC_VALUES
321
+ };
322
+ ```
140
323
 
141
- ```javascript
324
+ Quy trình thay link:
325
+ 1. Tạo file `xcss-dict.mjs` theo mẫu trên.
326
+ 2. Upload lên CDN/public URL của bạn.
327
+ 3. Thay `dictionaryImport` bằng URL thật.
328
+ 4. Chờ `await engine.ready` trước khi render class.
329
+
330
+ ## SSR Và Static Extraction
331
+
332
+ SSR:
333
+
334
+ ```js
142
335
  import { getCss } from '@fwkui/x-css';
143
336
 
144
- // Trong file layout/server entry
145
337
  const styles = getCss();
146
-
147
- // Inject HTML
148
- // Inject HTML
149
338
  // <style dangerouslySetInnerHTML={{ __html: styles }} />
150
339
  ```
151
340
 
152
- ### 5. Xuất File CSS (Static Extraction)
341
+ Static extraction:
153
342
 
154
- Nếu bạn muốn tạo file `.css` tĩnh (dành cho Static Site Generation hoặc Cache build), bạn có thể dùng script sau:
155
-
156
- ```javascript
157
- // build-css.js
158
- const fs = require('fs');
159
- const xcss = require('@fwkui/x-css');
343
+ ```js
344
+ import xcss from '@fwkui/x-css';
345
+ import fs from 'node:fs';
160
346
 
161
- // 1. Giả lập quá trình Render để thu thập class
162
- // (Bạn thể import App và renderToString nếu dùng React/Vue)
163
- // Ở đây ví dụ gọi thủ công:
164
- const { clsx, getCssString } = xcss({
165
- theme: { brand: '#ff0000' } // Cấu hình (nếu có)
347
+ const { clsx, getCssString } = xcss.css({
348
+ theme: { brand: '#0a64e8' }
166
349
  }).buildCss();
167
350
 
168
- // Gọi clsx với các class bạn sử dụng trong project
169
- clsx('m10px p20px cBrand dFlex');
351
+ clsx('m10px p20px cBrand dF');
170
352
 
171
- // 2. Lấy nội dung CSS đã sinh
172
- const cssContent = getCssString();
173
-
174
- // 3. Ghi ra file
175
- fs.writeFileSync('./public/styles.css', cssContent);
176
- console.log('✅ CSS file generated!');
353
+ fs.writeFileSync('./public/styles.css', getCssString());
177
354
  ```
178
355
 
179
- > [!NOTE]
180
- > **Custom Config SSR**: Nếu dự án dùng config tùy chỉnh (Theme, Prefix...), hãy đảm bảo khởi tạo `xcss(config)` và truyền instance đó xuống các component (qua Context/Props) thay vì dùng `import { clsx }` mặc định. Điều này đảm bảo Server và Client đồng bộ hash.
181
-
182
- ### 5. Zero-FOUC (Hybrid Cache) ⚡
356
+ ## Prompt Mẫu Cho AI (Dùng Thẳng)
183
357
 
184
- Để tăng tốc độ hiển thị và ngăn chặn FOUC (Flash of Unstyled Content) hoàn toàn, bạn hãy thêm đoạn script Bootloader này vào thẻ `<head>` của `index.html` (đặt **trước** tất cả các thẻ style/script khác):
358
+ Bạn thể đưa block này vào prompt system/project rules:
185
359
 
186
- ```html
187
- <script>
188
- // @fwkui/x-css Bootloader
189
- (function(){try{if(typeof window==='undefined')return;var d=localStorage.getItem('xcss_cache_v1');if(!d)return;var j=JSON.parse(d);if(!j||!j.cssText)return;var s=document.getElementById('fwkui');if(!s){s=document.createElement('style');s.id='fwkui';document.head.appendChild(s)}var c='';if(j.cssText.root)c+=j.cssText.root+'\n';for(var k in j.cssText){if(k!=='root')c+=j.cssText[k]+'\n'}s.textContent=c}catch(e){}})()
190
- </script>
360
+ ```markdown
361
+ You are using @fwkui/x-css.
362
+ Generate class names strictly with syntax: [Media]:[Layer][Property][Value][@Selector].
363
+
364
+ Rules:
365
+ 1. Value is required for normal utility classes.
366
+ 2. Layer must be numeric and placed directly before Property (e.g. 3bgWhite).
367
+ 3. Selector must be suffix @Selector (e.g. cBlue@:hover).
368
+ 4. Use dictionary aliases from DICTIONARY.md.
369
+ 5. Keep abbreviation values capitalized when needed (bdN, dF, posA).
370
+ 6. For complex CSS values, use bracket notation, and use ';' as space placeholder:
371
+ w[calc(100%;-;10px)].
372
+ 7. Use opc for opacity, tran for transition, op for object-position.
373
+
374
+ Before final answer:
375
+ - Validate each class can be parsed into {media, layer, property, value, selector}.
376
+ - Avoid invalid forms like bdn, tr0.2s, op0.8, 3:bgWhite, hover:cRed.
191
377
  ```
192
378
 
193
- **Cơ chế hoạt động:**
194
- 1. **Lần đầu truy cập**: Thư viện load bình thường, sinh CSS và tự động lưu vào `localStorage`.
195
- 2. **Lần sau (F5/Revisit)**: Script trên sẽ chạy ngay lập tức (10-50ms), đọc CSS từ cache và inject vào trang trước khi bất kỳ nội dung nào được render.
196
- 3. **Tự động Invalidate**: Nếu bạn thay đổi config (Theme/Breakpoints), cache cũ sẽ tự động bị xóa để tránh lỗi giao diện.
379
+ Template giao việc cho AI thiết kế UI:
380
+
381
+ ```markdown
382
+ Thiết kế giao diện [màn hình] bằng @fwkui/x-css.
383
+ Yêu cầu:
384
+ 1. Trả về HTML/JSX hoàn chỉnh.
385
+ 2. Chỉ dùng class theo cú pháp [Media]:[Layer][Property][Value][@Selector].
386
+ 3. Với value phức tạp, dùng [] và ';' thay cho khoảng trắng.
387
+ 4. Không dùng class sai quy tắc (bdn, tr0.2s, op0.8, hover:cRed...).
388
+ 5. Cuối câu trả lời thêm bảng kiểm:
389
+ - class
390
+ - parsed tuple {media, layer, property, value, selector}
391
+ - css dự kiến
392
+ ```
197
393
 
198
- > [!TIP]
199
- > **Lưu ý về Theme Custom**:
200
- > Parser dựa vào ký tự viết hoa để tách Property và Value.
201
- > - `theme: { brandColor: '...' }` ⮕ Class: `cBrandColor` (Khuyên dùng).
202
- > - `theme: { 'brand-color': '...' }` ⮕ Class: `cBrand-color` (Vẫn hỗ trợ, chữ `B` làm điểm ngắt).
203
- >
204
- > Tuyệt đối tránh viết thường toàn bộ (ví dụ `cbrandcolor`) vì thư viện sẽ không thể phân tách đúng.
394
+ ## Checklist QA Trước Khi Build
205
395
 
206
- ---
396
+ 1. Không còn class sai viết hoa value (`bdn`, `df`, `posa`).
397
+ 2. Không dùng nhầm alias (`op`/`opc`, `tr`/`tran`).
398
+ 3. Các value phức tạp đều bọc `[]`.
399
+ 4. Media custom đã khai báo trong `breakpoints`.
400
+ 5. Không có dạng sai layer/selector (`3:bg`, `hover:cRed`).
401
+ 6. Test parser với ít nhất bộ 10 test vector ở trên.
207
402
 
208
- ## ⚙️ Hỗ trợ AI Coding
403
+ ## Tài Liệu Liên Quan
209
404
 
210
- Để AI (Cursor, Copilot) code chính xác với cú pháp của @fwkui/x-css, hãy thêm rule sau vào `.cursorrules` hoặc prompt:
405
+ 1. Dictionary đầy đủ: [DICTIONARY.md](./DICTIONARY.md)
406
+ 2. Source code: [https://github.com/dwork-dev/fwkui](https://github.com/dwork-dev/fwkui)
211
407
 
212
- ```markdown
213
- You are using @fwkui/x-css. Follow these rules:
214
- 1. Syntax: `[Media]:[Layer][Property][Value][@Selector]`
215
- 2. Layer prefix: `3bgWhite` (NOT `3:bgWhite`).
216
- 3. Selector suffix: `cRed@:hover` (NOT `hover:cRed`).
217
- 4. Value capitalization: `dFlex`, `posAbs`.
218
- 5. Use aliases from DICTIONARY.md (e.g., `m` for margin, `d` for display).
219
- ```
408
+ ## License
220
409
 
221
- ---
410
+ Licensed under MIT. See [LICENSE](./LICENSE).
222
411
 
223
- *Verified & Updated at 2026-01-27*
412
+ Updated: 2026-03-02