@janbox/storefront-ui 2.0.29 → 2.0.30

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