gladvn 0.2.35 → 0.2.37

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 (134) hide show
  1. package/README.md +1 -1
  2. package/package.json +2 -1
  3. package/scripts/strip-comments.ts +79 -0
  4. package/src/blocks/auth-form.tsx +34 -30
  5. package/src/blocks/auth-recovery.tsx +9 -13
  6. package/src/blocks/auth-split.tsx +46 -36
  7. package/src/blocks/settings.tsx +84 -117
  8. package/src/components/macro/alert-preset.tsx +3 -1
  9. package/src/components/macro/carousel-preset.tsx +0 -1
  10. package/src/components/macro/checkbox-preset.test.tsx +2 -2
  11. package/src/components/macro/checkbox-preset.tsx +1 -2
  12. package/src/components/macro/command-preset.tsx +1 -1
  13. package/src/components/macro/date-picker.tsx +5 -18
  14. package/src/components/macro/dialog-preset.tsx +5 -3
  15. package/src/components/macro/input-preset.tsx +0 -1
  16. package/src/components/macro/select-preset.tsx +1 -1
  17. package/src/components/macro/switch-preset.test.tsx +1 -1
  18. package/src/components/micro/accordion.test.tsx +6 -12
  19. package/src/components/micro/alert-dialog.tsx +0 -2
  20. package/src/components/micro/alert.test.tsx +5 -8
  21. package/src/components/micro/alert.tsx +0 -2
  22. package/src/components/micro/badge.test.tsx +5 -7
  23. package/src/components/micro/badge.tsx +1 -3
  24. package/src/components/micro/button.test.tsx +19 -26
  25. package/src/components/micro/button.tsx +3 -11
  26. package/src/components/micro/calendar.tsx +12 -13
  27. package/src/components/micro/card.test.tsx +3 -5
  28. package/src/components/micro/carousel.tsx +0 -1
  29. package/src/components/micro/chart.tsx +3 -2
  30. package/src/components/micro/checkbox.test.tsx +9 -18
  31. package/src/components/micro/combobox.tsx +1 -3
  32. package/src/components/micro/command.tsx +23 -11
  33. package/src/components/micro/context-menu.tsx +0 -2
  34. package/src/components/micro/dialog.test.tsx +6 -14
  35. package/src/components/micro/dialog.tsx +0 -2
  36. package/src/components/micro/drawer.tsx +0 -3
  37. package/src/components/micro/dropdown-menu.test.tsx +8 -14
  38. package/src/components/micro/dropdown-menu.tsx +0 -2
  39. package/src/components/micro/field.tsx +3 -3
  40. package/src/components/micro/hover-card.tsx +0 -2
  41. package/src/components/micro/input-group.tsx +9 -42
  42. package/src/components/micro/input.test.tsx +15 -24
  43. package/src/components/micro/navigation-menu.tsx +0 -2
  44. package/src/components/micro/popover.test.tsx +5 -9
  45. package/src/components/micro/progress.tsx +5 -1
  46. package/src/components/micro/select.test.tsx +5 -18
  47. package/src/components/micro/select.tsx +3 -5
  48. package/src/components/micro/separator.tsx +1 -1
  49. package/src/components/micro/sheet.test.tsx +6 -14
  50. package/src/components/micro/sheet.tsx +0 -2
  51. package/src/components/micro/sidebar.tsx +5 -6
  52. package/src/components/micro/sonner.tsx +0 -1
  53. package/src/components/micro/switch.test.tsx +9 -18
  54. package/src/components/micro/switch.tsx +1 -1
  55. package/src/components/micro/tabs.test.tsx +5 -11
  56. package/src/components/micro/theme-provider.tsx +0 -12
  57. package/src/components/micro/toggle-group.tsx +1 -12
  58. package/src/components/micro/tooltip.test.tsx +7 -12
  59. package/src/dev/App.tsx +6 -6
  60. package/src/dev/components/BlockViewer.tsx +15 -4
  61. package/src/dev/components/Container.tsx +20 -0
  62. package/src/dev/components/GladvnLogo.tsx +3 -9
  63. package/src/dev/components/code-highlighter.tsx +5 -3
  64. package/src/dev/components/showcase.tsx +116 -168
  65. package/src/dev/sections/buttons.tsx +4 -9
  66. package/src/dev/sections/display.tsx +68 -72
  67. package/src/dev/sections/feedback.tsx +304 -314
  68. package/src/dev/sections/forms.tsx +10 -14
  69. package/src/dev/sections/interactive.tsx +32 -32
  70. package/src/dev/sections/overview.tsx +2 -10
  71. package/src/dev/showcase/accordion.tsx +512 -554
  72. package/src/dev/showcase/alert-dialog.tsx +525 -565
  73. package/src/dev/showcase/alert.tsx +352 -402
  74. package/src/dev/showcase/aspect-ratio.tsx +167 -193
  75. package/src/dev/showcase/avatar.tsx +231 -269
  76. package/src/dev/showcase/badge.tsx +92 -140
  77. package/src/dev/showcase/breadcrumb.tsx +113 -135
  78. package/src/dev/showcase/button.tsx +140 -173
  79. package/src/dev/showcase/calendar.tsx +187 -237
  80. package/src/dev/showcase/card.tsx +229 -261
  81. package/src/dev/showcase/carousel.tsx +288 -315
  82. package/src/dev/showcase/chart.tsx +44 -50
  83. package/src/dev/showcase/checkbox.tsx +286 -330
  84. package/src/dev/showcase/collapsible.tsx +143 -160
  85. package/src/dev/showcase/combobox.tsx +327 -369
  86. package/src/dev/showcase/command.tsx +106 -120
  87. package/src/dev/showcase/context-menu.tsx +93 -107
  88. package/src/dev/showcase/dialog.tsx +585 -630
  89. package/src/dev/showcase/drawer.tsx +176 -196
  90. package/src/dev/showcase/dropdown-menu.tsx +183 -201
  91. package/src/dev/showcase/empty.tsx +232 -274
  92. package/src/dev/showcase/hover-card.tsx +153 -180
  93. package/src/dev/showcase/input-group.tsx +221 -253
  94. package/src/dev/showcase/input-otp.tsx +204 -250
  95. package/src/dev/showcase/input.tsx +246 -325
  96. package/src/dev/showcase/item.tsx +134 -152
  97. package/src/dev/showcase/kbd.tsx +149 -172
  98. package/src/dev/showcase/label.tsx +50 -68
  99. package/src/dev/showcase/menubar.tsx +194 -213
  100. package/src/dev/showcase/navigation-menu.tsx +119 -133
  101. package/src/dev/showcase/overview-components/ArchitectureSection.tsx +126 -0
  102. package/src/dev/showcase/overview-components/CodeBlock.tsx +50 -0
  103. package/src/dev/showcase/overview-components/ColorPaletteSection.tsx +44 -0
  104. package/src/dev/showcase/overview-components/DashboardPreview.tsx +159 -0
  105. package/src/dev/showcase/overview-components/FeatureGridSection.tsx +535 -0
  106. package/src/dev/showcase/overview-components/FooterCTA.tsx +137 -0
  107. package/src/dev/showcase/overview-components/HeroSection.tsx +65 -0
  108. package/src/dev/showcase/overview-components/PrinciplesSection.tsx +128 -0
  109. package/src/dev/showcase/overview.tsx +21 -1163
  110. package/src/dev/showcase/pagination.tsx +144 -190
  111. package/src/dev/showcase/popover.tsx +181 -196
  112. package/src/dev/showcase/progress.tsx +141 -189
  113. package/src/dev/showcase/radio-group.tsx +272 -332
  114. package/src/dev/showcase/resizable.tsx +119 -141
  115. package/src/dev/showcase/scroll-area.tsx +21 -36
  116. package/src/dev/showcase/select.tsx +262 -322
  117. package/src/dev/showcase/separator.tsx +75 -73
  118. package/src/dev/showcase/sheet.tsx +333 -361
  119. package/src/dev/showcase/sidebar.tsx +53 -59
  120. package/src/dev/showcase/skeleton.tsx +93 -112
  121. package/src/dev/showcase/slider.tsx +244 -296
  122. package/src/dev/showcase/sonner.tsx +251 -258
  123. package/src/dev/showcase/spinner.tsx +46 -67
  124. package/src/dev/showcase/switch.tsx +298 -362
  125. package/src/dev/showcase/table.tsx +76 -80
  126. package/src/dev/showcase/tabs.tsx +302 -355
  127. package/src/dev/showcase/textarea.tsx +240 -293
  128. package/src/dev/showcase/toast.tsx +48 -54
  129. package/src/dev/showcase/toggle-group.tsx +104 -129
  130. package/src/dev/showcase/toggle.tsx +82 -102
  131. package/src/dev/showcase/tooltip.tsx +173 -192
  132. package/src/dev/showcase/why.tsx +6 -12
  133. package/src/hooks/use-mobile.test.ts +3 -2
  134. package/src/lib/utils.test.ts +5 -4
@@ -21,49 +21,41 @@ import {
21
21
  DocsH3,
22
22
  DocsP,
23
23
  ExampleGrid,
24
- ExampleSection,
24
+ ShowcaseExample,
25
25
  Showcase,
26
26
  ShowcaseDocs
27
27
  } from "../../dev/components/showcase";
28
28
  import { type Size } from "../../lib/types";
29
29
 
30
- // ──────────────────────────────────────────────────────────
31
- // SECTION 1: Macro Content
32
- // ──────────────────────────────────────────────────────────
33
30
  function SliderMacroShowcase({ globalSize }: { globalSize: Size }) {
34
31
  const [val, setVal] = useState([50]);
35
32
  const [rangeVal, setRangeVal] = useState([20, 80]);
36
33
 
37
34
  return (
38
- <div className="space-y-10 mt-6">
35
+ <div className="space-y-10">
39
36
  <ExampleGrid>
40
- <ExampleSection
41
- label="Tiêu chuẩn"
42
- description="Thanh trượt cơ bản có nhãn và mô tả."
43
- codeString={`<SliderPreset
37
+ <ShowcaseExample title="Tiêu chuẩn" description="Thanh trượt cơ bản có nhãn và mô tả." code={`<SliderPreset
44
38
  className="w-full"
45
39
  label="Âm lượng"
46
40
  description="Điều chỉnh âm lượng hệ thống."
47
41
  defaultValue={[50]}
48
42
  max={100}
49
43
  step={1}
50
- />`}
51
- >
52
- <SliderPreset
53
- className="w-full"
54
- size={globalSize}
55
- label="Âm lượng"
56
- description="Điều chỉnh âm lượng hệ thống."
57
- defaultValue={[50]}
58
- max={100}
59
- step={1}
60
- />
61
- </ExampleSection>
44
+ />`} preview={
45
+ <>
46
+ <SliderPreset
47
+ className="w-full"
48
+ size={globalSize}
49
+ label="Âm lượng"
50
+ description="Điều chỉnh âm lượng hệ thống."
51
+ defaultValue={[50]}
52
+ max={100}
53
+ step={1}
54
+ />
55
+ </>
56
+ } />
62
57
 
63
- <ExampleSection
64
- label="Trạng thái Lỗi (Error)"
65
- description="Báo lỗi khi giá trị không hợp lệ."
66
- codeString={`<div className="w-full flex flex-col gap-6">
58
+ <ShowcaseExample title="Trạng thái Lỗi (Error)" description="Báo lỗi khi giá trị không hợp lệ." code={`<div className="w-full flex flex-col gap-6">
67
59
  <SliderPreset
68
60
  label="Mức âm lượng (Lỗi)"
69
61
  defaultValue={[110]}
@@ -71,26 +63,24 @@ function SliderMacroShowcase({ globalSize }: { globalSize: Size }) {
71
63
  step={1}
72
64
  errorMessage="Mức âm lượng không được vượt quá 100."
73
65
  />
74
- </div>`}
75
- >
76
- <div className="w-full flex flex-col gap-6">
77
- <SliderPreset
78
- size={globalSize}
79
- label="Mức âm lượng (Lỗi)"
80
- defaultValue={[110]}
81
- max={100}
82
- step={1}
83
- errorMessage="Mức âm lượng không được vượt quá 100."
84
- />
85
- </div>
86
- </ExampleSection>
66
+ </div>`} preview={
67
+ <>
68
+ <div className="w-full flex flex-col gap-6">
69
+ <SliderPreset
70
+ size={globalSize}
71
+ label="Mức âm lượng (Lỗi)"
72
+ defaultValue={[110]}
73
+ max={100}
74
+ step={1}
75
+ errorMessage="Mức âm lượng không được vượt quá 100."
76
+ />
77
+ </div>
78
+ </>
79
+ } />
87
80
  </ExampleGrid>
88
81
 
89
82
  <ExampleGrid>
90
- <ExampleSection
91
- label="Thanh trượt Khoảng (Range Slider)"
92
- description="Truyền mảng 2 giá trị vào defaultValue hoặc value để tạo Range Slider."
93
- codeString={`const [rangeVal, setRangeVal] = useState([20, 80]); return
83
+ <ShowcaseExample title="Thanh trượt Khoảng (Range Slider)" description="Truyền mảng 2 giá trị vào defaultValue hoặc value để tạo Range Slider." code={`const [rangeVal, setRangeVal] = useState([20, 80]); return
94
84
  (
95
85
  <SliderPreset
96
86
  label="Khoảng giá"
@@ -100,67 +90,64 @@ function SliderMacroShowcase({ globalSize }: { globalSize: Size }) {
100
90
  step={5}
101
91
  description={\`Từ $\${rangeVal[0]} đến $\${rangeVal[1]}\`}
102
92
  />
103
- );`}
104
- >
105
- <SliderPreset
106
- className="w-full"
107
- size={globalSize}
108
- label="Khoảng giá"
109
- description={`Hiển thị sản phẩm từ $${rangeVal[0]} đến $${rangeVal[1]}`}
110
- value={rangeVal}
111
- onValueChange={(v) => setRangeVal(v as number[])}
112
- max={100}
113
- step={5}
114
- />
115
- </ExampleSection>
93
+ );`} preview={
94
+ <>
95
+ <SliderPreset
96
+ className="w-full"
97
+ size={globalSize}
98
+ label="Khoảng giá"
99
+ description={`Hiển thị sản phẩm từ $${rangeVal[0]} đến $${rangeVal[1]}`}
100
+ value={rangeVal}
101
+ onValueChange={(v) => setRangeVal(v as number[])}
102
+ max={100}
103
+ step={5}
104
+ />
105
+ </>
106
+ } />
116
107
 
117
- <ExampleSection
118
- label="Khóa / Bất hoạt (Disabled)"
119
- description="Người dùng không thể tương tác với thanh trượt."
120
- codeString={`<SliderPreset
108
+ <ShowcaseExample title="Khóa / Bất hoạt (Disabled)" description="Người dùng không thể tương tác với thanh trượt." code={`<SliderPreset
121
109
  className="w-full"
122
110
  label="Độ sáng màn hình"
123
111
  description="Độ sáng đang được hệ thống điều khiển tự động (Auto-brightness)."
124
112
  defaultValue={[75]}
125
113
  max={100}
126
114
  disabled
127
- />`}
128
- >
129
- <SliderPreset
130
- className="w-full"
131
- size={globalSize}
132
- label="Độ sáng màn hình"
133
- description="Độ sáng đang được hệ thống điều khiển tự động (Auto-brightness)."
134
- defaultValue={[75]}
135
- max={100}
136
- disabled
137
- />
138
- </ExampleSection>
115
+ />`} preview={
116
+ <>
117
+ <SliderPreset
118
+ className="w-full"
119
+ size={globalSize}
120
+ label="Độ sáng màn hình"
121
+ description="Độ sáng đang được hệ thống điều khiển tự động (Auto-brightness)."
122
+ defaultValue={[75]}
123
+ max={100}
124
+ disabled
125
+ />
126
+ </>
127
+ } />
139
128
  </ExampleGrid>
140
129
 
141
130
  <ExampleGrid>
142
- <ExampleSection
143
- label="Controlled Mode"
144
- description="Sử dụng biến state của React để điều khiển."
145
- codeString={`const [val, setVal] = useState([50]); return (
131
+ <ShowcaseExample title="Controlled Mode" description="Sử dụng biến state của React để điều khiển." code={`const [val, setVal] = useState([50]); return (
146
132
  <SliderPreset
147
133
  value={val}
148
134
  onValueChange={setVal}
149
135
  label="Giá trị có kiểm soát"
150
136
  description={\`Giá trị hiện tại là: \${val[0]}\`}
151
137
  />
152
- );`}
153
- >
154
- <div className="w-full max-w-sm flex flex-col gap-4">
155
- <SliderPreset
156
- size={globalSize}
157
- value={val}
158
- onValueChange={(v) => setVal(v as number[])}
159
- label="Giá trị có kiểm soát"
160
- description={`Giá trị hiện tại là: ${val[0]}`}
161
- />
162
- </div>
163
- </ExampleSection>
138
+ );`} preview={
139
+ <>
140
+ <div className="w-full max-w-sm flex flex-col gap-4">
141
+ <SliderPreset
142
+ size={globalSize}
143
+ value={val}
144
+ onValueChange={(v) => setVal(v as number[])}
145
+ label="Giá trị có kiểm soát"
146
+ description={`Giá trị hiện tại là: ${val[0]}`}
147
+ />
148
+ </div>
149
+ </>
150
+ } />
164
151
  </ExampleGrid>
165
152
  </div>
166
153
  );
@@ -171,12 +158,9 @@ function SliderMacroShowcase({ globalSize }: { globalSize: Size }) {
171
158
  // ──────────────────────────────────────────────────────────
172
159
  function SliderMicroShowcase({ globalSize }: { globalSize: Size }) {
173
160
  return (
174
- <div className="space-y-10 mt-6">
161
+ <div className="space-y-10">
175
162
  <ExampleGrid>
176
- <ExampleSection
177
- label="Cơ bản (Primitive)"
178
- description="Slider đơn giản không có Field hay Label bọc ngoài."
179
- codeString={`<CompositionalSlider
163
+ <ShowcaseExample title="Cơ bản (Primitive)" description="Slider đơn giản không có Field hay Label bọc ngoài." code={`<CompositionalSlider
180
164
  defaultValue={[40]}
181
165
  max={100}
182
166
  step={1}
@@ -188,28 +172,26 @@ function SliderMicroShowcase({ globalSize }: { globalSize: Size }) {
188
172
  </SliderTrack>
189
173
  <SliderThumb />
190
174
  </SliderControl>
191
- </CompositionalSlider>`}
192
- >
193
- <CompositionalSlider
194
- size={globalSize}
195
- defaultValue={[40]}
196
- max={100}
197
- step={1}
198
- className="w-full"
199
- >
200
- <SliderControl>
201
- <SliderTrack>
202
- <SliderIndicator />
203
- </SliderTrack>
204
- <SliderThumb />
205
- </SliderControl>
206
- </CompositionalSlider>
207
- </ExampleSection>
175
+ </CompositionalSlider>`} preview={
176
+ <>
177
+ <CompositionalSlider
178
+ size={globalSize}
179
+ defaultValue={[40]}
180
+ max={100}
181
+ step={1}
182
+ className="w-full"
183
+ >
184
+ <SliderControl>
185
+ <SliderTrack>
186
+ <SliderIndicator />
187
+ </SliderTrack>
188
+ <SliderThumb />
189
+ </SliderControl>
190
+ </CompositionalSlider>
191
+ </>
192
+ } />
208
193
 
209
- <ExampleSection
210
- label="Nhiều Thumb (Multi-thumb)"
211
- description="Chỉ cần render nhiều SliderThumb, hệ thống sẽ tự chia."
212
- codeString={`<CompositionalSlider
194
+ <ShowcaseExample title="Nhiều Thumb (Multi-thumb)" description="Chỉ cần render nhiều SliderThumb, hệ thống sẽ tự chia." code={`<CompositionalSlider
213
195
  defaultValue={[20, 50, 80]}
214
196
  max={100}
215
197
  step={1}
@@ -223,32 +205,30 @@ function SliderMicroShowcase({ globalSize }: { globalSize: Size }) {
223
205
  <SliderThumb />
224
206
  <SliderThumb />
225
207
  </SliderControl>
226
- </CompositionalSlider>`}
227
- >
228
- <CompositionalSlider
229
- size={globalSize}
230
- defaultValue={[20, 50, 80]}
231
- max={100}
232
- step={1}
233
- className="w-full"
234
- >
235
- <SliderControl>
236
- <SliderTrack>
237
- <SliderIndicator />
238
- </SliderTrack>
239
- <SliderThumb />
240
- <SliderThumb />
241
- <SliderThumb />
242
- </SliderControl>
243
- </CompositionalSlider>
244
- </ExampleSection>
208
+ </CompositionalSlider>`} preview={
209
+ <>
210
+ <CompositionalSlider
211
+ size={globalSize}
212
+ defaultValue={[20, 50, 80]}
213
+ max={100}
214
+ step={1}
215
+ className="w-full"
216
+ >
217
+ <SliderControl>
218
+ <SliderTrack>
219
+ <SliderIndicator />
220
+ </SliderTrack>
221
+ <SliderThumb />
222
+ <SliderThumb />
223
+ <SliderThumb />
224
+ </SliderControl>
225
+ </CompositionalSlider>
226
+ </>
227
+ } />
245
228
  </ExampleGrid>
246
229
 
247
230
  <ExampleGrid>
248
- <ExampleSection
249
- label="Ghép nối Field thủ công"
250
- description="Lắp ráp với Field để có nhãn và mô tả."
251
- codeString={`<Field className="w-full">
231
+ <ShowcaseExample title="Ghép nối Field thủ công" description="Lắp ráp với Field để có nhãn và mô tả." code={`<Field className="w-full">
252
232
  <FieldLabel>Mật độ hiển thị</FieldLabel>
253
233
  <FieldContent>
254
234
  <CompositionalSlider
@@ -267,35 +247,33 @@ function SliderMicroShowcase({ globalSize }: { globalSize: Size }) {
267
247
  <FieldDescription>
268
248
  Điều chỉnh khoảng cách giữa các phần tử.
269
249
  </FieldDescription>
270
- </Field>`}
271
- >
272
- <Field size={globalSize} className="w-full">
273
- <FieldLabel>Mật độ hiển thị</FieldLabel>
274
- <FieldContent>
275
- <CompositionalSlider
276
- size={globalSize}
277
- defaultValue={[50]}
278
- max={100}
279
- step={1}
280
- >
281
- <SliderControl>
282
- <SliderTrack>
283
- <SliderIndicator />
284
- </SliderTrack>
285
- <SliderThumb />
286
- </SliderControl>
287
- </CompositionalSlider>
288
- </FieldContent>
289
- <FieldDescription>
290
- Điều chỉnh khoảng cách giữa các phần tử.
291
- </FieldDescription>
292
- </Field>
293
- </ExampleSection>
250
+ </Field>`} preview={
251
+ <>
252
+ <Field size={globalSize} className="w-full">
253
+ <FieldLabel>Mật độ hiển thị</FieldLabel>
254
+ <FieldContent>
255
+ <CompositionalSlider
256
+ size={globalSize}
257
+ defaultValue={[50]}
258
+ max={100}
259
+ step={1}
260
+ >
261
+ <SliderControl>
262
+ <SliderTrack>
263
+ <SliderIndicator />
264
+ </SliderTrack>
265
+ <SliderThumb />
266
+ </SliderControl>
267
+ </CompositionalSlider>
268
+ </FieldContent>
269
+ <FieldDescription>
270
+ Điều chỉnh khoảng cách giữa các phần tử.
271
+ </FieldDescription>
272
+ </Field>
273
+ </>
274
+ } />
294
275
 
295
- <ExampleSection
296
- label="Trạng thái Lỗi thủ công"
297
- description="Tự gắn aria-invalid vào Slider và dùng FieldError."
298
- codeString={`<Field className="w-full gap-2" data-invalid={true}>
276
+ <ShowcaseExample title="Trạng thái Lỗi thủ công" description="Tự gắn aria-invalid vào Slider và dùng FieldError." code={`<Field className="w-full gap-2" data-invalid={true}>
299
277
  <FieldLabel>Ngân sách tối đa</FieldLabel>
300
278
  <FieldContent>
301
279
  <CompositionalSlider
@@ -313,37 +291,34 @@ function SliderMicroShowcase({ globalSize }: { globalSize: Size }) {
313
291
  </CompositionalSlider>
314
292
  </FieldContent>
315
293
  <FieldError>Ngân sách của bạn chỉ còn $100.</FieldError>
316
- </Field>`}
317
- >
318
- <Field size={globalSize} className="w-full gap-2" data-invalid={true}>
319
- <FieldLabel>Ngân sách tối đa</FieldLabel>
320
- <FieldContent>
321
- <CompositionalSlider
322
- size={globalSize}
323
- defaultValue={[120]}
324
- max={100}
325
- step={1}
326
- aria-invalid={true}
327
- >
328
- <SliderControl>
329
- <SliderTrack>
330
- <SliderIndicator />
331
- </SliderTrack>
332
- <SliderThumb />
333
- </SliderControl>
334
- </CompositionalSlider>
335
- </FieldContent>
336
- <FieldError>Ngân sách của bạn chỉ còn $100.</FieldError>
337
- </Field>
338
- </ExampleSection>
294
+ </Field>`} preview={
295
+ <>
296
+ <Field size={globalSize} className="w-full gap-2" data-invalid={true}>
297
+ <FieldLabel>Ngân sách tối đa</FieldLabel>
298
+ <FieldContent>
299
+ <CompositionalSlider
300
+ size={globalSize}
301
+ defaultValue={[120]}
302
+ max={100}
303
+ step={1}
304
+ aria-invalid={true}
305
+ >
306
+ <SliderControl>
307
+ <SliderTrack>
308
+ <SliderIndicator />
309
+ </SliderTrack>
310
+ <SliderThumb />
311
+ </SliderControl>
312
+ </CompositionalSlider>
313
+ </FieldContent>
314
+ <FieldError>Ngân sách của bạn chỉ còn $100.</FieldError>
315
+ </Field>
316
+ </>
317
+ } />
339
318
  </ExampleGrid>
340
319
 
341
- <ExampleSection
342
- label="🧭 Use Case Comparison"
343
- description="So sánh nhanh khi nào dùng Micro và Macro."
344
- fullWidth
345
- codeString={`<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
346
- {/* Story 1: Macro wins */}
320
+ <ShowcaseExample title="🧭 So sánh Use Case" description="So sánh nhanh khi nào dùng Micro và Macro." code={`<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
321
+
347
322
  <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
348
323
  <div className="flex items-start gap-3">
349
324
  <span className="mt-0.5 shrink-0 rounded-full bg-green-500/10 p-1.5 text-green-600">
@@ -378,7 +353,7 @@ function SliderMicroShowcase({ globalSize }: { globalSize: Size }) {
378
353
  </p>
379
354
  </div>
380
355
 
381
- {/* Story 2: Micro wins */}
356
+
382
357
  <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
383
358
  <div className="flex items-start gap-3">
384
359
  <span className="mt-0.5 shrink-0 rounded-full bg-blue-500/10 p-1.5 text-blue-600">
@@ -412,78 +387,79 @@ function SliderMicroShowcase({ globalSize }: { globalSize: Size }) {
412
387
  độc lập.
413
388
  </p>
414
389
  </div>
415
- </div>`}
416
- >
417
- <div className="grid grid-cols-1 gap-6 md:grid-cols-2">
418
- {/* Story 1: Macro wins */}
419
- <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
420
- <div className="flex items-start gap-3">
421
- <span className="mt-0.5 shrink-0 rounded-full bg-green-500/10 p-1.5 text-green-600">
422
- <svg
423
- xmlns="http://www.w3.org/2000/svg"
424
- className="size-4"
425
- viewBox="0 0 24 24"
426
- fill="none"
427
- stroke="currentColor"
428
- strokeWidth="2"
429
- strokeLinecap="round"
430
- strokeLinejoin="round"
431
- aria-hidden="true"
432
- >
433
- <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
434
- </svg>
435
- </span>
436
- <div>
437
- <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
438
- Story 1 · Dùng Macro
439
- </p>
440
- <h3 className="mt-0.5 text-sm font-semibold text-foreground">
441
- Bộ lọc sản phẩm
442
- </h3>
443
- </div>
444
- </div>
445
- <p className="text-xs text-muted-foreground leading-relaxed">
446
- Bạn cần làm bộ lọc "Khoảng giá" ở cột Sidebar cho trang Ecommerce.{" "}
447
- <DocsCode>SliderPreset</DocsCode> sẽ giúp bạn tiết kiệm hàng tá
448
- dòng code bọc Field loằng ngoằng.
449
- </p>
450
- </div>
390
+ </div>`} preview={
391
+ <>
392
+ <div className="grid grid-cols-1 gap-6 md:grid-cols-2">
393
+ {/* Story 1: Macro wins */}
394
+ <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
395
+ <div className="flex items-start gap-3">
396
+ <span className="mt-0.5 shrink-0 rounded-full bg-green-500/10 p-1.5 text-green-600">
397
+ <svg
398
+ xmlns="http://www.w3.org/2000/svg"
399
+ className="size-4"
400
+ viewBox="0 0 24 24"
401
+ fill="none"
402
+ stroke="currentColor"
403
+ strokeWidth="2"
404
+ strokeLinecap="round"
405
+ strokeLinejoin="round"
406
+ aria-hidden="true"
407
+ >
408
+ <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
409
+ </svg>
410
+ </span>
411
+ <div>
412
+ <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
413
+ Story 1 · Dùng Macro
414
+ </p>
415
+ <h3 className="mt-0.5 text-sm font-semibold text-foreground">
416
+ Bộ lọc sản phẩm
417
+ </h3>
418
+ </div>
419
+ </div>
420
+ <p className="text-xs text-muted-foreground leading-relaxed">
421
+ Bạn cần làm bộ lọc "Khoảng giá" ở cột Sidebar cho trang Ecommerce.{" "}
422
+ <DocsCode>SliderPreset</DocsCode> sẽ giúp bạn tiết kiệm hàng tá
423
+ dòng code bọc Field loằng ngoằng.
424
+ </p>
425
+ </div>
451
426
 
452
- {/* Story 2: Micro wins */}
453
- <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
454
- <div className="flex items-start gap-3">
455
- <span className="mt-0.5 shrink-0 rounded-full bg-blue-500/10 p-1.5 text-blue-600">
456
- <svg
457
- xmlns="http://www.w3.org/2000/svg"
458
- className="size-4"
459
- viewBox="0 0 24 24"
460
- fill="none"
461
- stroke="currentColor"
462
- strokeWidth="2"
463
- strokeLinecap="round"
464
- strokeLinejoin="round"
465
- aria-hidden="true"
466
- >
467
- <path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" />
468
- </svg>
469
- </span>
470
- <div>
471
- <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
472
- Story 2 · Dùng Micro
473
- </p>
474
- <h3 className="mt-0.5 text-sm font-semibold text-foreground">
475
- Thanh thời lượng Video (Video Player)
476
- </h3>
477
- </div>
478
- </div>
479
- <p className="text-xs text-muted-foreground leading-relaxed">
480
- Bạn đang làm một trình phát Video giống Youtube. Thanh Timeline
481
- chạy dưới đáy không hề có Label hay Description. Ở đây bạn BẮT
482
- BUỘC dùng Micro để dựng độc lập.
483
- </p>
484
- </div>
485
- </div>
486
- </ExampleSection>
427
+ {/* Story 2: Micro wins */}
428
+ <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
429
+ <div className="flex items-start gap-3">
430
+ <span className="mt-0.5 shrink-0 rounded-full bg-blue-500/10 p-1.5 text-blue-600">
431
+ <svg
432
+ xmlns="http://www.w3.org/2000/svg"
433
+ className="size-4"
434
+ viewBox="0 0 24 24"
435
+ fill="none"
436
+ stroke="currentColor"
437
+ strokeWidth="2"
438
+ strokeLinecap="round"
439
+ strokeLinejoin="round"
440
+ aria-hidden="true"
441
+ >
442
+ <path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" />
443
+ </svg>
444
+ </span>
445
+ <div>
446
+ <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
447
+ Story 2 · Dùng Micro
448
+ </p>
449
+ <h3 className="mt-0.5 text-sm font-semibold text-foreground">
450
+ Thanh thời lượng Video (Video Player)
451
+ </h3>
452
+ </div>
453
+ </div>
454
+ <p className="text-xs text-muted-foreground leading-relaxed">
455
+ Bạn đang làm một trình phát Video giống Youtube. Thanh Timeline
456
+ chạy dưới đáy không hề có Label hay Description. Ở đây bạn BẮT
457
+ BUỘC dùng Micro để dựng độc lập.
458
+ </p>
459
+ </div>
460
+ </div>
461
+ </>
462
+ } />
487
463
  </div>
488
464
  );
489
465
  }
@@ -497,37 +473,9 @@ export default function SliderShowcase() {
497
473
  <Showcase
498
474
  title="Slider"
499
475
  description="Thành phần điều khiển cho phép người dùng chọn một hoặc nhiều giá trị trong một phạm vi (range) nhất định."
500
- generalConcept={
501
- <div className="space-y-4">
502
- <ShowcaseDocs>
503
- <DocsH3>Khi nào nên dùng Macro</DocsH3>
504
- <DocsP>
505
- <DocsCode>SliderPreset</DocsCode> đóng gói sẵn Slider + Label +
506
- Description + Error Message. Nó tự động xử lý ID linking cho khả
507
- năng truy cập (Accessibility). Dùng Macro cho 95% trường hợp làm
508
- form lấy giá trị số hoặc bộ lọc (filter).
509
- </DocsP>
510
- </ShowcaseDocs>
511
- <ShowcaseDocs>
512
- <DocsH3>Khi nào nên dùng Micro</DocsH3>
513
- <DocsP>
514
- Dùng <DocsCode>CompositionalSlider</DocsCode> và các thành phần
515
- con (<DocsCode>SliderControl</DocsCode>,{" "}
516
- <DocsCode>SliderTrack</DocsCode>, <DocsCode>SliderThumb</DocsCode>
517
- ) khi bạn cần tuỳ biến giao diện cực hạn (ví dụ: track đổi màu
518
- theo giá trị, thumb có hình dáng đặc biệt) hoặc không cần label.
519
- </DocsP>
520
- </ShowcaseDocs>
521
- </div>
522
- }
523
- tabs={[
524
- {
525
- label: "Micro (Primitive)",
526
- content: <SliderMicroShowcase globalSize={globalSize} /> },
527
- {
528
- label: "Macro (Preset)",
529
- content: <SliderMacroShowcase globalSize={globalSize} /> },
530
- ]}
476
+
477
+ micro={{ content: <SliderMicroShowcase globalSize={globalSize} /> }}
478
+ macro={{ content: <SliderMacroShowcase globalSize={globalSize} /> }}
531
479
  />
532
480
  );
533
481
  }