@janbox/storefront-ui 2.0.29 → 2.0.31
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/README.md +692 -0
- package/dist/lib/accordion/README.md +81 -0
- package/dist/lib/avatar/README.md +74 -0
- package/dist/lib/badge/README.md +58 -0
- package/dist/lib/box/README.md +69 -0
- package/dist/lib/breadcrumbs/README.md +70 -0
- package/dist/lib/button/README.md +115 -0
- package/dist/lib/cascader/README.md +128 -0
- package/dist/lib/checkbox/README.md +74 -0
- package/dist/lib/checkbox/checkbox.js +107 -12
- package/dist/lib/checkbox/types.d.ts +2 -2
- package/dist/lib/chip/README.md +72 -0
- package/dist/lib/collapse/README.md +78 -0
- package/dist/lib/container/README.md +59 -0
- package/dist/lib/count-up/README.md +52 -0
- package/dist/lib/countdown-timer/README.md +77 -0
- package/dist/lib/date-picker/README.md +94 -0
- package/dist/lib/dialog/README.md +109 -0
- package/dist/lib/drawer/README.md +97 -0
- package/dist/lib/filter-panel/README.md +146 -0
- package/dist/lib/flag/README.md +58 -0
- package/dist/lib/flexbox/README.md +59 -0
- package/dist/lib/floating/README.md +109 -0
- package/dist/lib/form-helper-text/README.md +54 -0
- package/dist/lib/form-label/README.md +50 -0
- package/dist/lib/grid/README.md +72 -0
- package/dist/lib/highlight-words/README.md +64 -0
- package/dist/lib/highlight-words/highlight-words.js +1 -2
- package/dist/lib/icon/README.md +69 -0
- package/dist/lib/icon-button/README.md +92 -0
- package/dist/lib/image/README.md +80 -0
- package/dist/lib/input/README.md +118 -0
- package/dist/lib/input-mask/README.md +88 -0
- package/dist/lib/input-number/README.md +92 -0
- package/dist/lib/input-range/README.md +85 -0
- package/dist/lib/lightbox/README.md +107 -0
- package/dist/lib/linear-progress/README.md +54 -0
- package/dist/lib/link/README.md +67 -0
- package/dist/lib/loading/README.md +65 -0
- package/dist/lib/marquee/README.md +83 -0
- package/dist/lib/marquee/marquee/marquee.js +1 -1
- package/dist/lib/menu/README.md +92 -0
- package/dist/lib/multiple-select/README.md +108 -0
- package/dist/lib/nav-link/README.md +61 -0
- package/dist/lib/notifications/README.md +103 -0
- package/dist/lib/otp-input/README.md +71 -0
- package/dist/lib/pagination/README.md +84 -0
- package/dist/lib/phone-input/README.md +80 -0
- package/dist/lib/popover/README.md +93 -0
- package/dist/lib/price-label/README.md +78 -0
- package/dist/lib/primitive/README.md +80 -0
- package/dist/lib/progress/README.md +50 -0
- package/dist/lib/radio-button/README.md +89 -0
- package/dist/lib/radio-button/radio-button.js +98 -7
- package/dist/lib/ripple-effect/README.md +66 -0
- package/dist/lib/select/README.md +124 -0
- package/dist/lib/star-rating/README.md +67 -0
- package/dist/lib/stepper/README.md +99 -0
- package/dist/lib/suspense-query/README.md +78 -0
- package/dist/lib/swiper/README.md +99 -0
- package/dist/lib/switch/README.md +73 -0
- package/dist/lib/switch/switch.d.ts +1 -1
- package/dist/lib/switch/switch.js +110 -11
- package/dist/lib/table/README.md +115 -0
- package/dist/lib/tabs/README.md +103 -0
- package/dist/lib/text/README.md +59 -0
- package/dist/lib/textarea/README.md +76 -0
- package/dist/lib/time-picker/README.md +100 -0
- package/dist/lib/tooltip/README.md +106 -0
- package/dist/lib/unordered-list/README.md +85 -0
- package/dist/lib/video/README.md +88 -0
- package/dist/style.css +1 -244
- package/package.json +5 -5
- package/dist/lib/checkbox/checkbox.module.scss.js +0 -23
- package/dist/lib/radio-button/radio-button.module.scss.js +0 -17
- package/dist/lib/switch/switch.module.scss.js +0 -14
package/README.md
ADDED
|
@@ -0,0 +1,692 @@
|
|
|
1
|
+
# @janbox/storefront-ui
|
|
2
|
+
|
|
3
|
+
Thư viện component React nội bộ của Janbox — được thiết kế để AI agents và developers có thể làm việc hiệu quả.
|
|
4
|
+
|
|
5
|
+
## Tổng quan
|
|
6
|
+
|
|
7
|
+
`@janbox/storefront-ui` là design system component library được xây dựng trên React 19, Emotion CSS, và Vite. Thư viện cung cấp 60+ components có thể customize, type-safe hoàn toàn, và tuân thủ các convention nhất quán để AI agents có thể hiểu và sử dụng dễ dàng.
|
|
8
|
+
|
|
9
|
+
**Phiên bản hiện tại:** v2.0.29
|
|
10
|
+
|
|
11
|
+
### Đặc điểm nổi bật
|
|
12
|
+
|
|
13
|
+
- **Pure ESM** — Module format hiện đại, tree-shakeable
|
|
14
|
+
- **Type-safe 100%** — TypeScript strict mode, generic types đầy đủ
|
|
15
|
+
- **Convention-driven** — Mọi component tuân thủ cùng một pattern, dễ dự đoán
|
|
16
|
+
- **Polymorphic components** — `Primitive` component với `as` prop linh hoạt
|
|
17
|
+
- **Responsive-first** — Built-in responsive props cho mọi component
|
|
18
|
+
- **Emotion CSS** — CSS-in-JS với type safety và performance tốt
|
|
19
|
+
- **60+ Components** — Từ primitive đến complex UI patterns
|
|
20
|
+
- **AI-friendly** — Documentation rõ ràng, naming nhất quán, patterns dễ học
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
### Yêu cầu
|
|
27
|
+
|
|
28
|
+
- Node.js ≥ 18
|
|
29
|
+
- pnpm ≥ 8 (khuyến nghị)
|
|
30
|
+
- React ≥ 19
|
|
31
|
+
|
|
32
|
+
### Cài đặt qua pnpm
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pnpm add @janbox/storefront-ui
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Peer dependencies
|
|
39
|
+
|
|
40
|
+
Đảm bảo đã cài đặt các peer dependencies:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pnpm add react react-dom @emotion/react
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Nếu sử dụng `Button` với routing:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pnpm add react-router
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Quick Start
|
|
55
|
+
|
|
56
|
+
### 1. Wrap app với ThemeProvider
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { ThemeProvider } from '@janbox/storefront-ui/theme';
|
|
60
|
+
|
|
61
|
+
function App() {
|
|
62
|
+
return (
|
|
63
|
+
<ThemeProvider>
|
|
64
|
+
{/* Your app */}
|
|
65
|
+
</ThemeProvider>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2. Import và sử dụng components
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import { Button, Input, Box, Text } from '@janbox/storefront-ui';
|
|
74
|
+
|
|
75
|
+
function LoginForm() {
|
|
76
|
+
return (
|
|
77
|
+
<Box sx={{ md: { maxWidth: 400 } }}>
|
|
78
|
+
<Text size="2xl" sx={{ marginBottom: 16 }}>Đăng nhập</Text>
|
|
79
|
+
|
|
80
|
+
<Input
|
|
81
|
+
type="email"
|
|
82
|
+
placeholder="Email"
|
|
83
|
+
size="md"
|
|
84
|
+
sx={{ marginBottom: 12 }}
|
|
85
|
+
/>
|
|
86
|
+
|
|
87
|
+
<Input
|
|
88
|
+
type="password"
|
|
89
|
+
placeholder="Mật khẩu"
|
|
90
|
+
size="md"
|
|
91
|
+
sx={{ marginBottom: 16 }}
|
|
92
|
+
/>
|
|
93
|
+
|
|
94
|
+
<Button
|
|
95
|
+
variant="contained"
|
|
96
|
+
color="primary"
|
|
97
|
+
size="lg"
|
|
98
|
+
fullWidth
|
|
99
|
+
>
|
|
100
|
+
Đăng nhập
|
|
101
|
+
</Button>
|
|
102
|
+
</Box>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 3. Import stylesheet (nếu dùng component có CSS)
|
|
108
|
+
|
|
109
|
+
Một số component (như `DatePicker`) import CSS từ third-party libraries. Styles này được tách ra thành file `dist/style.css` riêng biệt trong quá trình build. Consumer app cần import file này khi sử dụng các component đó:
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
// Import CSS stylesheet cho các component có external CSS (DatePicker, v.v.)
|
|
113
|
+
import '@janbox/storefront-ui/style.css';
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
> Nếu app không dùng `DatePicker` hay component nào import CSS, bạn có thể bỏ qua bước này.
|
|
117
|
+
|
|
118
|
+
### 4. Sử dụng responsive props
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
import { Flexbox, Box, Button } from '@janbox/storefront-ui';
|
|
122
|
+
|
|
123
|
+
function ResponsiveLayout() {
|
|
124
|
+
return (
|
|
125
|
+
<Flexbox
|
|
126
|
+
direction="column"
|
|
127
|
+
md={{ direction: 'row' }}
|
|
128
|
+
gap={16}
|
|
129
|
+
>
|
|
130
|
+
<Box sx={{ sm: { flex: 1 } }}>
|
|
131
|
+
Nội dung chính
|
|
132
|
+
</Box>
|
|
133
|
+
|
|
134
|
+
<Box sx={{ sm: { width: 300 } }}>
|
|
135
|
+
Sidebar
|
|
136
|
+
</Box>
|
|
137
|
+
</Flexbox>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Features
|
|
145
|
+
|
|
146
|
+
### 1. Convention-Driven Architecture
|
|
147
|
+
|
|
148
|
+
Mọi component tuân thủ cùng một pattern:
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
src/lib/<component>/
|
|
152
|
+
├── index.ts → Barrel export
|
|
153
|
+
├── types.ts → TypeScript interfaces
|
|
154
|
+
├── helpers.ts → CSS helpers + merge props logic
|
|
155
|
+
├── <component>.tsx → Component implementation
|
|
156
|
+
└── <component>.stories.tsx → Storybook stories
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Pattern nhất quán:**
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
// Mọi component đều nhận props theo format này
|
|
163
|
+
export const Button = ({ ref, ..._props }: ButtonProps) => {
|
|
164
|
+
// 1. Merge với default props qua helper
|
|
165
|
+
const { size, variant, color, children, ...rest } = getButtonProps(_props);
|
|
166
|
+
|
|
167
|
+
// 2. Build CSS từ helpers
|
|
168
|
+
const css = [
|
|
169
|
+
getButtonCssBySize(size),
|
|
170
|
+
getButtonCssByVariant(variant),
|
|
171
|
+
getButtonCssByColor(color),
|
|
172
|
+
createSxInterpolation(sx),
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
// 3. Render với Primitive hoặc native element
|
|
176
|
+
return <button css={css} ref={ref} {...rest}>{children}</button>;
|
|
177
|
+
};
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 2. Type-Safe Responsive Props
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
import { Box } from '@janbox/storefront-ui';
|
|
184
|
+
|
|
185
|
+
// Base props (mobile-first)
|
|
186
|
+
<Box display="none" />
|
|
187
|
+
|
|
188
|
+
// Responsive overrides theo breakpoint
|
|
189
|
+
<Box
|
|
190
|
+
display="none"
|
|
191
|
+
md={{ display: 'flex' }}
|
|
192
|
+
lg={{ display: 'grid' }}
|
|
193
|
+
/>
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Breakpoints:**
|
|
197
|
+
|
|
198
|
+
| Screen | Min-width |
|
|
199
|
+
|--------|-----------|
|
|
200
|
+
| `xs` | 0px (default, không cần khai báo) |
|
|
201
|
+
| `sm` | 768px (tablet) |
|
|
202
|
+
| `md` | 1280px (desktop) |
|
|
203
|
+
| `lg` | 1680px (large desktop) |
|
|
204
|
+
|
|
205
|
+
### 3. Polymorphic Components
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
import { Primitive } from '@janbox/storefront-ui';
|
|
209
|
+
|
|
210
|
+
// Render as div (mặc định)
|
|
211
|
+
<Primitive>Content</Primitive>
|
|
212
|
+
|
|
213
|
+
// Render as button
|
|
214
|
+
<Primitive as="button" onClick={handleClick}>
|
|
215
|
+
Click me
|
|
216
|
+
</Primitive>
|
|
217
|
+
|
|
218
|
+
// Render as Link từ react-router
|
|
219
|
+
<Primitive as={Link} to="/home">
|
|
220
|
+
Go home
|
|
221
|
+
</Primitive>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### 4. Design Token System
|
|
225
|
+
|
|
226
|
+
```tsx
|
|
227
|
+
import { getColorVar, getTypographyVar, mediaQuery } from '@janbox/storefront-ui/theme';
|
|
228
|
+
|
|
229
|
+
// Color tokens
|
|
230
|
+
const style = {
|
|
231
|
+
backgroundColor: getColorVar('primary.600'),
|
|
232
|
+
color: getColorVar('neutral.50'),
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// Typography tokens
|
|
236
|
+
const { fontSize, lineHeight } = getTypographyVar('lg');
|
|
237
|
+
|
|
238
|
+
// Media queries
|
|
239
|
+
const responsiveStyle = {
|
|
240
|
+
[mediaQuery('md')]: { fontSize: 16 },
|
|
241
|
+
[mediaQuery('lg')]: { fontSize: 18 },
|
|
242
|
+
};
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### 5. Utility Functions
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
import {
|
|
249
|
+
cn, // Class names combiner
|
|
250
|
+
mergeComponentProps, // Deep merge props
|
|
251
|
+
getColorShadesByVariant, // Color utilities
|
|
252
|
+
getSizeVariantState, // Size utilities
|
|
253
|
+
formatNumber, // Number formatter
|
|
254
|
+
formatPrice, // Price formatter
|
|
255
|
+
formatDateTime, // DateTime formatter
|
|
256
|
+
} from '@janbox/storefront-ui/utils';
|
|
257
|
+
|
|
258
|
+
// Example: merge props
|
|
259
|
+
const props = mergeComponentProps(defaultProps, userProps);
|
|
260
|
+
|
|
261
|
+
// Example: get color shades
|
|
262
|
+
const { main, dark, light, contrastText } = getColorShadesByVariant('primary');
|
|
263
|
+
|
|
264
|
+
// Example: format price
|
|
265
|
+
const formatted = formatPrice(1000000, 'VND', 'vi-VN'); // "1.000.000 ₫"
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Usage
|
|
271
|
+
|
|
272
|
+
### Component Categories
|
|
273
|
+
|
|
274
|
+
Thư viện cung cấp 60+ components được tổ chức theo các nhóm:
|
|
275
|
+
|
|
276
|
+
#### Layout
|
|
277
|
+
`Box`, `Flexbox`, `Grid`, `Container`
|
|
278
|
+
|
|
279
|
+
#### Typography
|
|
280
|
+
`Text`, `Link`, `HighlightWords`
|
|
281
|
+
|
|
282
|
+
#### Form Controls
|
|
283
|
+
`Input`, `InputNumber`, `InputRange`, `InputMask`, `Textarea`, `Select`, `MultipleSelect`, `Checkbox`, `RadioButton`, `Switch`, `DatePicker`, `TimePicker`, `PhoneInput`, `OtpInput`, `Cascader`
|
|
284
|
+
|
|
285
|
+
#### Buttons
|
|
286
|
+
`Button`, `IconButton`, `NavLink`
|
|
287
|
+
|
|
288
|
+
#### Feedback
|
|
289
|
+
`Loading`, `Progress`, `LinearProgress`, `Dialog`, `Drawer`, `Tooltip`, `Popover`, `Notifications`
|
|
290
|
+
|
|
291
|
+
#### Data Display
|
|
292
|
+
`Badge`, `Chip`, `Avatar`, `Table`, `Pagination`, `Stepper`, `Tabs`, `Accordion`, `Collapse`, `Breadcrumbs`, `StarRating`, `PriceLabel`, `CountUp`, `CountdownTimer`, `Flag`
|
|
293
|
+
|
|
294
|
+
#### Media
|
|
295
|
+
`Image`, `Video`, `Icon`, `Lightbox`, `Swiper`
|
|
296
|
+
|
|
297
|
+
#### Navigation
|
|
298
|
+
`Menu`, `FilterPanel`
|
|
299
|
+
|
|
300
|
+
#### Utilities
|
|
301
|
+
`Primitive`, `RippleEffect`, `SuspenseQuery`, `Marquee`, `Floating`
|
|
302
|
+
|
|
303
|
+
### Export Paths
|
|
304
|
+
|
|
305
|
+
```tsx
|
|
306
|
+
// Main components
|
|
307
|
+
import { Button, Input, Box } from '@janbox/storefront-ui';
|
|
308
|
+
|
|
309
|
+
// Theme utilities
|
|
310
|
+
import { ThemeProvider, getColorVar } from '@janbox/storefront-ui/theme';
|
|
311
|
+
|
|
312
|
+
// Hooks
|
|
313
|
+
import { useWindowScreen, useControllableState } from '@janbox/storefront-ui/hooks';
|
|
314
|
+
|
|
315
|
+
// Types
|
|
316
|
+
import type { SizeVariant, ColorVariant, StyledCSS } from '@janbox/storefront-ui/types';
|
|
317
|
+
|
|
318
|
+
// Utils
|
|
319
|
+
import { cn, formatPrice } from '@janbox/storefront-ui/utils';
|
|
320
|
+
|
|
321
|
+
// Constants
|
|
322
|
+
import { HTMLDatasetAttributes } from '@janbox/storefront-ui/constants';
|
|
323
|
+
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Size Variants
|
|
327
|
+
|
|
328
|
+
Hầu hết components hỗ trợ 4 size variants:
|
|
329
|
+
|
|
330
|
+
```tsx
|
|
331
|
+
<Button size="xs">Extra Small</Button>
|
|
332
|
+
<Button size="sm">Small</Button>
|
|
333
|
+
<Button size="md">Medium (default)</Button>
|
|
334
|
+
<Button size="lg">Large</Button>
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**Size mapping:**
|
|
338
|
+
|
|
339
|
+
| size | iconSize | inputSize | inputPaddingX | textVariant |
|
|
340
|
+
|------|----------|-----------|---------------|-------------|
|
|
341
|
+
| `xs` | 20px | 24px | 8px | `xs` |
|
|
342
|
+
| `sm` | 20px | 32px | 12px | `sm` |
|
|
343
|
+
| `md` | 24px | 40px | 12px | `sm` |
|
|
344
|
+
| `lg` | 24px | 48px | 16px | `base` |
|
|
345
|
+
|
|
346
|
+
### Color Variants
|
|
347
|
+
|
|
348
|
+
```tsx
|
|
349
|
+
<Button color="primary">Primary</Button>
|
|
350
|
+
<Button color="secondary">Secondary</Button>
|
|
351
|
+
<Button color="green">Success</Button>
|
|
352
|
+
<Button color="red">Error</Button>
|
|
353
|
+
<Button color="orange">Warning</Button>
|
|
354
|
+
<Button color="blue">Info</Button>
|
|
355
|
+
<Button color="neutral">Neutral</Button>
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### sx Prop — Inline Styling
|
|
359
|
+
|
|
360
|
+
Mọi component đều hỗ trợ `sx` prop để override styles:
|
|
361
|
+
|
|
362
|
+
```tsx
|
|
363
|
+
<Button
|
|
364
|
+
sx={{
|
|
365
|
+
borderRadius: 8,
|
|
366
|
+
fontWeight: 600,
|
|
367
|
+
md: { fontSize: 16 },
|
|
368
|
+
lg: { fontSize: 18 },
|
|
369
|
+
}}
|
|
370
|
+
>
|
|
371
|
+
Custom Button
|
|
372
|
+
</Button>
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Theming
|
|
378
|
+
|
|
379
|
+
### ThemeProvider
|
|
380
|
+
|
|
381
|
+
Wrap root app với `ThemeProvider` để inject design tokens:
|
|
382
|
+
|
|
383
|
+
```tsx
|
|
384
|
+
import { ThemeProvider } from '@janbox/storefront-ui/theme';
|
|
385
|
+
|
|
386
|
+
function App() {
|
|
387
|
+
return (
|
|
388
|
+
<ThemeProvider>
|
|
389
|
+
<YourApp />
|
|
390
|
+
</ThemeProvider>
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Design Tokens
|
|
396
|
+
|
|
397
|
+
Design tokens được expose qua CSS variables:
|
|
398
|
+
|
|
399
|
+
```css
|
|
400
|
+
/* Colors */
|
|
401
|
+
--color-primary-50
|
|
402
|
+
--color-primary-100
|
|
403
|
+
...
|
|
404
|
+
--color-primary-900
|
|
405
|
+
|
|
406
|
+
/* Typography */
|
|
407
|
+
--typography-xs-font-size
|
|
408
|
+
--typography-xs-line-height
|
|
409
|
+
...
|
|
410
|
+
--typography-6xl-font-size
|
|
411
|
+
--typography-6xl-line-height
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### Accessing Tokens in JS
|
|
415
|
+
|
|
416
|
+
```tsx
|
|
417
|
+
import { getColorVar, getTypographyVar, breakpoint } from '@janbox/storefront-ui/theme';
|
|
418
|
+
|
|
419
|
+
// Get color CSS variable
|
|
420
|
+
const primaryColor = getColorVar('primary.600'); // 'var(--color-primary-600)'
|
|
421
|
+
|
|
422
|
+
// Get typography values
|
|
423
|
+
const { fontSize, lineHeight } = getTypographyVar('lg');
|
|
424
|
+
|
|
425
|
+
// Get breakpoint values
|
|
426
|
+
console.log(breakpoint.md); // 1280
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## Development
|
|
432
|
+
|
|
433
|
+
### Prerequisites
|
|
434
|
+
|
|
435
|
+
- Node.js ≥ 18
|
|
436
|
+
- pnpm ≥ 8
|
|
437
|
+
|
|
438
|
+
### Setup
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
# Clone repo
|
|
442
|
+
git clone <repo-url>
|
|
443
|
+
cd storefront-ui
|
|
444
|
+
|
|
445
|
+
# Install dependencies
|
|
446
|
+
pnpm install
|
|
447
|
+
|
|
448
|
+
# Start Storybook dev server
|
|
449
|
+
pnpm storybook
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
Storybook sẽ chạy tại **http://localhost:6006**
|
|
453
|
+
|
|
454
|
+
### Development Commands
|
|
455
|
+
|
|
456
|
+
| Command | Description |
|
|
457
|
+
|---------|-------------|
|
|
458
|
+
| `pnpm storybook` | Dev server (port 6006) |
|
|
459
|
+
| `pnpm build` | Build thư viện → `dist/` |
|
|
460
|
+
| `pnpm dev` | Build với watch mode |
|
|
461
|
+
| `pnpm type-check` | TypeScript type checking |
|
|
462
|
+
| `pnpm lint` | ESLint |
|
|
463
|
+
| `pnpm build-storybook` | Build Storybook static |
|
|
464
|
+
|
|
465
|
+
### Creating New Components
|
|
466
|
+
|
|
467
|
+
Tham khảo **[CLAUDE.md](./CLAUDE.md)** để hiểu đầy đủ về component architecture và conventions.
|
|
468
|
+
|
|
469
|
+
**Quick steps:**
|
|
470
|
+
|
|
471
|
+
1. Tạo folder `src/lib/<component>/`
|
|
472
|
+
2. Tạo files: `types.ts`, `helpers.ts`, `<component>.tsx`, `<component>.stories.tsx`, `index.ts`
|
|
473
|
+
3. Implement theo pattern chuẩn (xem CLAUDE.md section 4)
|
|
474
|
+
4. Export trong `src/lib/index.ts`
|
|
475
|
+
5. Viết Storybook stories
|
|
476
|
+
|
|
477
|
+
**Pattern template:**
|
|
478
|
+
|
|
479
|
+
```tsx
|
|
480
|
+
// types.ts
|
|
481
|
+
export type XxxProps = PropsWithSx<
|
|
482
|
+
ShallowMerge<
|
|
483
|
+
React.HTMLAttributes<HTMLDivElement>,
|
|
484
|
+
ToResponsiveProps<XxxResponsiveProps> & {
|
|
485
|
+
children?: React.ReactNode;
|
|
486
|
+
}
|
|
487
|
+
>
|
|
488
|
+
>;
|
|
489
|
+
|
|
490
|
+
// helpers.ts
|
|
491
|
+
const defaultProps = { size: 'md' as const } satisfies Partial<XxxProps>;
|
|
492
|
+
export const getXxxProps = (p: XxxProps) => mergeComponentProps(defaultProps, p);
|
|
493
|
+
|
|
494
|
+
// xxx.tsx
|
|
495
|
+
export const Xxx = ({ ref, ..._props }: XxxProps) => {
|
|
496
|
+
const { size, children, ...rest } = getXxxProps(_props);
|
|
497
|
+
return <Primitive ref={ref} {...rest}>{children}</Primitive>;
|
|
498
|
+
};
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
---
|
|
502
|
+
|
|
503
|
+
## API Reference
|
|
504
|
+
|
|
505
|
+
### Documentation
|
|
506
|
+
|
|
507
|
+
- **Storybook**: Chạy `pnpm storybook` để xem interactive docs
|
|
508
|
+
- **CLAUDE.md**: Convention guide đầy đủ cho AI agents và developers
|
|
509
|
+
- **TypeScript**: Mọi component đều có JSDoc comments và type definitions
|
|
510
|
+
|
|
511
|
+
### Key Types
|
|
512
|
+
|
|
513
|
+
```typescript
|
|
514
|
+
// Size variants
|
|
515
|
+
type SizeVariant = 'xs' | 'sm' | 'md' | 'lg';
|
|
516
|
+
|
|
517
|
+
// Color variants
|
|
518
|
+
type ColorVariant = 'primary' | 'secondary' | 'green' | 'red' | 'orange' | 'blue' | 'neutral';
|
|
519
|
+
|
|
520
|
+
// Button variants
|
|
521
|
+
type ButtonVariant = 'contained' | 'outlined' | 'text';
|
|
522
|
+
|
|
523
|
+
// Responsive props wrapper
|
|
524
|
+
type ToResponsiveProps<T> = T & Partial<Record<'sm' | 'md' | 'lg', T>>;
|
|
525
|
+
|
|
526
|
+
// sx prop type
|
|
527
|
+
type PropsWithSx<T> = T & { sx?: ToResponsiveProps<StyledCSS> };
|
|
528
|
+
|
|
529
|
+
// Polymorphic component props
|
|
530
|
+
type PrimitiveProps<Props, ElementType> = Props & { as?: ElementType };
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
### Hooks
|
|
534
|
+
|
|
535
|
+
```typescript
|
|
536
|
+
// Window screen detection
|
|
537
|
+
useWindowScreen(): Screen;
|
|
538
|
+
|
|
539
|
+
// Controllable state pattern
|
|
540
|
+
useControllableState<T>(value, defaultValue, onChange): [T, Dispatch<T>];
|
|
541
|
+
|
|
542
|
+
// Countdown timer
|
|
543
|
+
useCountdownTimer(target, options): CountdownState;
|
|
544
|
+
|
|
545
|
+
// Query params sync
|
|
546
|
+
useQueryParams<T>(key, defaultValue): [T, (value: T) => void];
|
|
547
|
+
|
|
548
|
+
// First mount detection
|
|
549
|
+
useFirstMountState(): boolean;
|
|
550
|
+
|
|
551
|
+
// Update effect (skip first mount)
|
|
552
|
+
useUpdateEffect(effect, deps);
|
|
553
|
+
|
|
554
|
+
// Deep compare effect
|
|
555
|
+
useDeepCompareEffect(effect, deps);
|
|
556
|
+
|
|
557
|
+
// Formatters
|
|
558
|
+
useFormatter(): FormatterUtils;
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
---
|
|
562
|
+
|
|
563
|
+
## AI Agent Guidelines
|
|
564
|
+
|
|
565
|
+
Thư viện này được thiết kế để AI agents có thể làm việc hiệu quả. Dưới đây là các nguyên tắc quan trọng:
|
|
566
|
+
|
|
567
|
+
### 1. Convention nhất quán
|
|
568
|
+
|
|
569
|
+
- Mọi component tuân thủ **cùng một pattern**: `types.ts` → `helpers.ts` → `<component>.tsx` → `index.ts`
|
|
570
|
+
- Props destructuring: `({ ref, ..._props })` → `getXxxProps(_props)` → destructure
|
|
571
|
+
- Default props luôn ở `helpers.ts`, không trong component
|
|
572
|
+
- CSS helpers luôn có prefix `getXxxCssBy...`
|
|
573
|
+
|
|
574
|
+
### 2. Type-first approach
|
|
575
|
+
|
|
576
|
+
- Mọi component có TypeScript types đầy đủ
|
|
577
|
+
- Sử dụng generic types: `PropsWithSx`, `ToResponsiveProps`, `ShallowMerge`
|
|
578
|
+
- Props type luôn export cùng với component
|
|
579
|
+
|
|
580
|
+
### 3. File naming
|
|
581
|
+
|
|
582
|
+
- **Kebab-case** cho tất cả files: `input-number.tsx`, `ripple-effect.tsx`
|
|
583
|
+
- **PascalCase** cho component exports: `export const InputNumber = ...`
|
|
584
|
+
|
|
585
|
+
### 4. Import patterns
|
|
586
|
+
|
|
587
|
+
```tsx
|
|
588
|
+
// ✅ Preferred — từ main entry
|
|
589
|
+
import { Button, Input } from '@janbox/storefront-ui';
|
|
590
|
+
|
|
591
|
+
// ✅ Subpath exports
|
|
592
|
+
import { getColorVar } from '@janbox/storefront-ui/theme';
|
|
593
|
+
import { cn } from '@janbox/storefront-ui/utils';
|
|
594
|
+
|
|
595
|
+
// ❌ Avoid — deep imports
|
|
596
|
+
import { Button } from '@janbox/storefront-ui/lib/button';
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### 5. lodash-es requirement
|
|
600
|
+
|
|
601
|
+
```tsx
|
|
602
|
+
// ✅ Tree-shakeable
|
|
603
|
+
import { isNil, debounce } from 'lodash-es';
|
|
604
|
+
|
|
605
|
+
// ❌ Non-tree-shakeable
|
|
606
|
+
import { isNil } from 'lodash';
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
### 6. Emotion CSS pragma
|
|
610
|
+
|
|
611
|
+
Mọi file `.tsx` sử dụng `css={}` prop phải có:
|
|
612
|
+
|
|
613
|
+
```tsx
|
|
614
|
+
/** @jsxImportSource @emotion/react */
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
**Lưu ý:** Nếu component chỉ dùng `<Primitive>` + `sx` prop, **không cần** pragma này.
|
|
618
|
+
|
|
619
|
+
### 7. Responsive props pattern
|
|
620
|
+
|
|
621
|
+
```tsx
|
|
622
|
+
// Base (xs) — mobile-first
|
|
623
|
+
<Box display="flex" />
|
|
624
|
+
|
|
625
|
+
// Tablet breakpoint (sm: 768px)
|
|
626
|
+
<Box display="flex" sm={{ display: 'grid' }} />
|
|
627
|
+
|
|
628
|
+
// Desktop breakpoint (md: 1280px)
|
|
629
|
+
<Box display="flex" md={{ flexDirection: 'row' }} />
|
|
630
|
+
|
|
631
|
+
// Large desktop breakpoint (lg: 1680px)
|
|
632
|
+
<Box display="flex" lg={{ gap: 32 }} />
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
### 8. Testing trong Storybook
|
|
636
|
+
|
|
637
|
+
- Mọi component mới **bắt buộc** có `.stories.tsx`
|
|
638
|
+
- Storybook là môi trường dev/test chính
|
|
639
|
+
- Chưa có unit test runner (Jest/Vitest)
|
|
640
|
+
|
|
641
|
+
---
|
|
642
|
+
|
|
643
|
+
## License & Contributing
|
|
644
|
+
|
|
645
|
+
### License
|
|
646
|
+
|
|
647
|
+
Private package — chỉ dùng nội bộ Janbox.
|
|
648
|
+
|
|
649
|
+
### Contributing
|
|
650
|
+
|
|
651
|
+
1. Đọc kỹ **[CLAUDE.md](./CLAUDE.md)** trước khi contribute
|
|
652
|
+
2. Mọi component mới phải tuân thủ conventions trong CLAUDE.md
|
|
653
|
+
3. Bắt buộc có Storybook stories
|
|
654
|
+
4. Type-check và lint phải pass: `pnpm type-check && pnpm lint`
|
|
655
|
+
5. Tạo PR, không commit trực tiếp lên `main`
|
|
656
|
+
|
|
657
|
+
### Workflow
|
|
658
|
+
|
|
659
|
+
```bash
|
|
660
|
+
# 1. Create feature branch
|
|
661
|
+
git checkout -b feat/my-component
|
|
662
|
+
|
|
663
|
+
# 2. Develop với Storybook
|
|
664
|
+
pnpm storybook
|
|
665
|
+
|
|
666
|
+
# 3. Type-check
|
|
667
|
+
pnpm type-check
|
|
668
|
+
|
|
669
|
+
# 4. Lint
|
|
670
|
+
pnpm lint
|
|
671
|
+
|
|
672
|
+
# 5. Build
|
|
673
|
+
pnpm build
|
|
674
|
+
|
|
675
|
+
# 6. Commit & push
|
|
676
|
+
git add .
|
|
677
|
+
git commit -m "feat: add MyComponent"
|
|
678
|
+
git push origin feat/my-component
|
|
679
|
+
|
|
680
|
+
# 7. Create PR
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
---
|
|
684
|
+
|
|
685
|
+
## Support
|
|
686
|
+
|
|
687
|
+
Để được hỗ trợ hoặc báo lỗi, liên hệ team Janbox qua internal channels.
|
|
688
|
+
|
|
689
|
+
---
|
|
690
|
+
|
|
691
|
+
**Phiên bản:** v2.0.29
|
|
692
|
+
**Last updated:** 2026-06-02
|