@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.
Files changed (76) hide show
  1. package/README.md +692 -0
  2. package/dist/lib/accordion/README.md +81 -0
  3. package/dist/lib/avatar/README.md +74 -0
  4. package/dist/lib/badge/README.md +58 -0
  5. package/dist/lib/box/README.md +69 -0
  6. package/dist/lib/breadcrumbs/README.md +70 -0
  7. package/dist/lib/button/README.md +115 -0
  8. package/dist/lib/cascader/README.md +128 -0
  9. package/dist/lib/checkbox/README.md +74 -0
  10. package/dist/lib/checkbox/checkbox.js +107 -12
  11. package/dist/lib/checkbox/types.d.ts +2 -2
  12. package/dist/lib/chip/README.md +72 -0
  13. package/dist/lib/collapse/README.md +78 -0
  14. package/dist/lib/container/README.md +59 -0
  15. package/dist/lib/count-up/README.md +52 -0
  16. package/dist/lib/countdown-timer/README.md +77 -0
  17. package/dist/lib/date-picker/README.md +94 -0
  18. package/dist/lib/dialog/README.md +109 -0
  19. package/dist/lib/drawer/README.md +97 -0
  20. package/dist/lib/filter-panel/README.md +146 -0
  21. package/dist/lib/flag/README.md +58 -0
  22. package/dist/lib/flexbox/README.md +59 -0
  23. package/dist/lib/floating/README.md +109 -0
  24. package/dist/lib/form-helper-text/README.md +54 -0
  25. package/dist/lib/form-label/README.md +50 -0
  26. package/dist/lib/grid/README.md +72 -0
  27. package/dist/lib/highlight-words/README.md +64 -0
  28. package/dist/lib/highlight-words/highlight-words.js +1 -2
  29. package/dist/lib/icon/README.md +69 -0
  30. package/dist/lib/icon-button/README.md +92 -0
  31. package/dist/lib/image/README.md +80 -0
  32. package/dist/lib/input/README.md +118 -0
  33. package/dist/lib/input-mask/README.md +88 -0
  34. package/dist/lib/input-number/README.md +92 -0
  35. package/dist/lib/input-range/README.md +85 -0
  36. package/dist/lib/lightbox/README.md +107 -0
  37. package/dist/lib/linear-progress/README.md +54 -0
  38. package/dist/lib/link/README.md +67 -0
  39. package/dist/lib/loading/README.md +65 -0
  40. package/dist/lib/marquee/README.md +83 -0
  41. package/dist/lib/marquee/marquee/marquee.js +1 -1
  42. package/dist/lib/menu/README.md +92 -0
  43. package/dist/lib/multiple-select/README.md +108 -0
  44. package/dist/lib/nav-link/README.md +61 -0
  45. package/dist/lib/notifications/README.md +103 -0
  46. package/dist/lib/otp-input/README.md +71 -0
  47. package/dist/lib/pagination/README.md +84 -0
  48. package/dist/lib/phone-input/README.md +80 -0
  49. package/dist/lib/popover/README.md +93 -0
  50. package/dist/lib/price-label/README.md +78 -0
  51. package/dist/lib/primitive/README.md +80 -0
  52. package/dist/lib/progress/README.md +50 -0
  53. package/dist/lib/radio-button/README.md +89 -0
  54. package/dist/lib/radio-button/radio-button.js +98 -7
  55. package/dist/lib/ripple-effect/README.md +66 -0
  56. package/dist/lib/select/README.md +124 -0
  57. package/dist/lib/star-rating/README.md +67 -0
  58. package/dist/lib/stepper/README.md +99 -0
  59. package/dist/lib/suspense-query/README.md +78 -0
  60. package/dist/lib/swiper/README.md +99 -0
  61. package/dist/lib/switch/README.md +73 -0
  62. package/dist/lib/switch/switch.d.ts +1 -1
  63. package/dist/lib/switch/switch.js +110 -11
  64. package/dist/lib/table/README.md +115 -0
  65. package/dist/lib/tabs/README.md +103 -0
  66. package/dist/lib/text/README.md +59 -0
  67. package/dist/lib/textarea/README.md +76 -0
  68. package/dist/lib/time-picker/README.md +100 -0
  69. package/dist/lib/tooltip/README.md +106 -0
  70. package/dist/lib/unordered-list/README.md +85 -0
  71. package/dist/lib/video/README.md +88 -0
  72. package/dist/style.css +1 -244
  73. package/package.json +5 -5
  74. package/dist/lib/checkbox/checkbox.module.scss.js +0 -23
  75. package/dist/lib/radio-button/radio-button.module.scss.js +0 -17
  76. 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