gladvn 0.2.36 → 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 +1 -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
@@ -13,15 +13,12 @@ import {
13
13
  DocsH3,
14
14
  DocsP,
15
15
  ExampleGrid,
16
- ExampleSection,
16
+ ShowcaseExample,
17
17
  Showcase,
18
18
  ShowcaseDocs
19
19
  } from "../../dev/components/showcase";
20
20
  import { type Size } from "../../lib/types";
21
21
 
22
- // ──────────────────────────────────────────────────────────
23
- // RHF Form Demo (Macro)
24
- // ──────────────────────────────────────────────────────────
25
22
  const formSchema = z.object({
26
23
  notify: z.string().min(1, "Vui lòng chọn phương thức thông báo.") });
27
24
  type FormValues = z.infer<typeof formSchema>;
@@ -93,17 +90,11 @@ function RadioGroupForm({ size }: { size: Size }) {
93
90
  );
94
91
  }`;
95
92
 
96
- // ──────────────────────────────────────────────────────────
97
- // SECTION 1: Macro Content
98
- // ──────────────────────────────────────────────────────────
99
93
  function RadioGroupMacroShowcase({ globalSize }: { globalSize: Size }) {
100
94
  return (
101
- <div className="space-y-10 mt-6">
95
+ <div className="space-y-10">
102
96
  <ExampleGrid>
103
- <ExampleSection
104
- label="Tiêu chuẩn"
105
- description="Nhóm radio cơ bản với mảng options."
106
- codeString={`<RadioGroupPreset
97
+ <ShowcaseExample title="Tiêu chuẩn" description="Nhóm radio cơ bản với mảng options." code={`<RadioGroupPreset
107
98
  className="w-full"
108
99
  label="Sở thích"
109
100
  description="Chọn một ngôn ngữ lập trình bạn yêu thích nhất."
@@ -113,26 +104,24 @@ function RadioGroupMacroShowcase({ globalSize }: { globalSize: Size }) {
113
104
  { value: "rust", label: "Rust" },
114
105
  ]}
115
106
  defaultValue="ts"
116
- />`}
117
- >
118
- <RadioGroupPreset
119
- className="w-full"
120
- size={globalSize}
121
- label="Sở thích"
122
- description="Chọn một ngôn ngữ lập trình bạn yêu thích nhất."
123
- options={[
124
- { value: "ts", label: "TypeScript" },
125
- { value: "go", label: "Golang" },
126
- { value: "rust", label: "Rust" },
127
- ]}
128
- defaultValue="ts"
129
- />
130
- </ExampleSection>
107
+ />`} preview={
108
+ <>
109
+ <RadioGroupPreset
110
+ className="w-full"
111
+ size={globalSize}
112
+ label="Sở thích"
113
+ description="Chọn một ngôn ngữ lập trình bạn yêu thích nhất."
114
+ options={[
115
+ { value: "ts", label: "TypeScript" },
116
+ { value: "go", label: "Golang" },
117
+ { value: "rust", label: "Rust" },
118
+ ]}
119
+ defaultValue="ts"
120
+ />
121
+ </>
122
+ } />
131
123
 
132
- <ExampleSection
133
- label="Trạng thái Lỗi (Error)"
134
- description="Báo lỗi khi form submit mà user chưa chọn."
135
- codeString={`<div className="w-full flex flex-col gap-6">
124
+ <ShowcaseExample title="Trạng thái Lỗi (Error)" description="Báo lỗi khi form submit mà user chưa chọn." code={`<div className="w-full flex flex-col gap-6">
136
125
  <RadioGroupPreset
137
126
  label="Gói dịch vụ (Lỗi)"
138
127
  options={[
@@ -141,27 +130,25 @@ function RadioGroupMacroShowcase({ globalSize }: { globalSize: Size }) {
141
130
  ]}
142
131
  errorMessage="Vui lòng chọn một gói dịch vụ để tiếp tục."
143
132
  />
144
- </div>`}
145
- >
146
- <div className="w-full flex flex-col gap-6">
147
- <RadioGroupPreset
148
- size={globalSize}
149
- label="Gói dịch vụ (Lỗi)"
150
- options={[
151
- { value: "free", label: "Miễn phí" },
152
- { value: "pro", label: "Trả phí" },
153
- ]}
154
- errorMessage="Vui lòng chọn một gói dịch vụ để tiếp tục."
155
- />
156
- </div>
157
- </ExampleSection>
133
+ </div>`} preview={
134
+ <>
135
+ <div className="w-full flex flex-col gap-6">
136
+ <RadioGroupPreset
137
+ size={globalSize}
138
+ label="Gói dịch vụ (Lỗi)"
139
+ options={[
140
+ { value: "free", label: "Miễn phí" },
141
+ { value: "pro", label: "Trả phí" },
142
+ ]}
143
+ errorMessage="Vui lòng chọn một gói dịch vụ để tiếp tục."
144
+ />
145
+ </div>
146
+ </>
147
+ } />
158
148
  </ExampleGrid>
159
149
 
160
150
  <ExampleGrid>
161
- <ExampleSection
162
- label="Mô tả cho từng Option"
163
- description="Truyền description vào mảng options để chú thích chi tiết."
164
- codeString={`<RadioGroupPreset
151
+ <ShowcaseExample title="Mô tả cho từng Option" description="Truyền description vào mảng options để chú thích chi tiết." code={`<RadioGroupPreset
165
152
  className="w-full"
166
153
  label="Giao diện (Theme)"
167
154
  description="Chế độ Mặc định hệ thống sẽ tự động đồng bộ theo OS."
@@ -174,29 +161,27 @@ function RadioGroupMacroShowcase({ globalSize }: { globalSize: Size }) {
174
161
  description: "Khuyên dùng để tiết kiệm pin" },
175
162
  ]}
176
163
  defaultValue="system"
177
- />`}
178
- >
179
- <RadioGroupPreset
180
- className="w-full"
181
- size={globalSize}
182
- label="Giao diện (Theme)"
183
- description="Chế độ Mặc định hệ thống sẽ tự động đồng bộ theo OS."
184
- options={[
185
- { value: "light", label: "Sáng (Light)" },
186
- { value: "dark", label: "Tối (Dark)" },
187
- {
188
- value: "system",
189
- label: "Theo hệ thống",
190
- description: "Khuyên dùng để tiết kiệm pin" },
191
- ]}
192
- defaultValue="system"
193
- />
194
- </ExampleSection>
164
+ />`} preview={
165
+ <>
166
+ <RadioGroupPreset
167
+ className="w-full"
168
+ size={globalSize}
169
+ label="Giao diện (Theme)"
170
+ description="Chế độ Mặc định hệ thống sẽ tự động đồng bộ theo OS."
171
+ options={[
172
+ { value: "light", label: "Sáng (Light)" },
173
+ { value: "dark", label: "Tối (Dark)" },
174
+ {
175
+ value: "system",
176
+ label: "Theo hệ thống",
177
+ description: "Khuyên dùng để tiết kiệm pin" },
178
+ ]}
179
+ defaultValue="system"
180
+ />
181
+ </>
182
+ } />
195
183
 
196
- <ExampleSection
197
- label="Khóa / Bất hoạt (Disabled)"
198
- description="Người dùng không thể tương tác với form."
199
- codeString={`<RadioGroupPreset
184
+ <ShowcaseExample title="Khóa / Bất hoạt (Disabled)" description="Người dùng không thể tương tác với form." code={`<RadioGroupPreset
200
185
  className="w-full"
201
186
  label="Phiên bản (Disabled)"
202
187
  description="Bạn không thể hạ cấp phiên bản tại thời điểm này."
@@ -206,47 +191,40 @@ function RadioGroupMacroShowcase({ globalSize }: { globalSize: Size }) {
206
191
  ]}
207
192
  defaultValue="v2"
208
193
  disabled
209
- />`}
210
- >
211
- <RadioGroupPreset
212
- className="w-full"
213
- size={globalSize}
214
- label="Phiên bản (Disabled)"
215
- description="Bạn không thể hạ cấp phiên bản tại thời điểm này."
216
- options={[
217
- { value: "v1", label: "v1.0.0 (Legacy)" },
218
- { value: "v2", label: "v2.0.0 (Current)" },
219
- ]}
220
- defaultValue="v2"
221
- disabled
222
- />
223
- </ExampleSection>
194
+ />`} preview={
195
+ <>
196
+ <RadioGroupPreset
197
+ className="w-full"
198
+ size={globalSize}
199
+ label="Phiên bản (Disabled)"
200
+ description="Bạn không thể hạ cấp phiên bản tại thời điểm này."
201
+ options={[
202
+ { value: "v1", label: "v1.0.0 (Legacy)" },
203
+ { value: "v2", label: "v2.0.0 (Current)" },
204
+ ]}
205
+ defaultValue="v2"
206
+ disabled
207
+ />
208
+ </>
209
+ } />
224
210
  </ExampleGrid>
225
211
 
226
212
  <ExampleGrid>
227
- <ExampleSection
228
- label="Tích hợp React Hook Form"
229
- description="Sử dụng Controller để bắt giá trị."
230
- codeString={rhfCode}
231
- >
232
- <RadioGroupForm size={globalSize} />
233
- </ExampleSection>
213
+ <ShowcaseExample title="Tích hợp React Hook Form" description="Sử dụng Controller để bắt giá trị." code={rhfCode} preview={
214
+ <>
215
+ <RadioGroupForm size={globalSize} />
216
+ </>
217
+ } />
234
218
  </ExampleGrid>
235
219
  </div>
236
220
  );
237
221
  }
238
222
 
239
- // ──────────────────────────────────────────────────────────
240
- // SECTION 2: Micro Content
241
- // ──────────────────────────────────────────────────────────
242
223
  function RadioGroupMicroShowcase({ globalSize }: { globalSize: Size }) {
243
224
  return (
244
- <div className="space-y-10 mt-6">
225
+ <div className="space-y-10">
245
226
  <ExampleGrid>
246
- <ExampleSection
247
- label="Cơ bản (Primitive)"
248
- description="Ghép nối thủ công RadioGroupItem và Label."
249
- codeString={`<RadioGroup
227
+ <ShowcaseExample title="Cơ bản (Primitive)" description="Ghép nối thủ công RadioGroupItem và Label." code={`<RadioGroup
250
228
  defaultValue="comfortable"
251
229
  className="flex flex-col gap-2 w-full"
252
230
  >
@@ -268,35 +246,33 @@ function RadioGroupMicroShowcase({ globalSize }: { globalSize: Size }) {
268
246
  Thoải mái
269
247
  </Label>
270
248
  </div>
271
- </RadioGroup>`}
272
- >
273
- <RadioGroup
274
- defaultValue="comfortable"
275
- className="flex flex-col gap-2 w-full"
276
- >
277
- <div className="flex items-center gap-3">
278
- <RadioGroupItem size={globalSize} value="default" id="rg-m-1" />
279
- <Label htmlFor="rg-m-1" className="cursor-pointer font-normal">
280
- Mặc định
281
- </Label>
282
- </div>
283
- <div className="flex items-center gap-3">
284
- <RadioGroupItem
285
- size={globalSize}
286
- value="comfortable"
287
- id="rg-m-2"
288
- />
289
- <Label htmlFor="rg-m-2" className="cursor-pointer font-normal">
290
- Thoải mái
291
- </Label>
292
- </div>
293
- </RadioGroup>
294
- </ExampleSection>
249
+ </RadioGroup>`} preview={
250
+ <>
251
+ <RadioGroup
252
+ defaultValue="comfortable"
253
+ className="flex flex-col gap-2 w-full"
254
+ >
255
+ <div className="flex items-center gap-3">
256
+ <RadioGroupItem size={globalSize} value="default" id="rg-m-1" />
257
+ <Label htmlFor="rg-m-1" className="cursor-pointer font-normal">
258
+ Mặc định
259
+ </Label>
260
+ </div>
261
+ <div className="flex items-center gap-3">
262
+ <RadioGroupItem
263
+ size={globalSize}
264
+ value="comfortable"
265
+ id="rg-m-2"
266
+ />
267
+ <Label htmlFor="rg-m-2" className="cursor-pointer font-normal">
268
+ Thoải mái
269
+ </Label>
270
+ </div>
271
+ </RadioGroup>
272
+ </>
273
+ } />
295
274
 
296
- <ExampleSection
297
- label="Bố cục Ngang (Horizontal)"
298
- description="Hiển thị các tuỳ chọn trên một hàng ngang."
299
- codeString={`<div className="space-y-3 w-full">
275
+ <ShowcaseExample title="Bố cục Ngang (Horizontal)" description="Hiển thị các tuỳ chọn trên một hàng ngang." code={`<div className="space-y-3 w-full">
300
276
  <Label className="block text-muted-foreground">
301
277
  Kích thước
302
278
  </Label>
@@ -332,39 +308,37 @@ function RadioGroupMicroShowcase({ globalSize }: { globalSize: Size }) {
332
308
  </Label>
333
309
  </div>
334
310
  </RadioGroup>
335
- </div>`}
336
- >
337
- <div className="space-y-3 w-full">
338
- <Label className="block text-muted-foreground">Kích thước</Label>
339
- <RadioGroup defaultValue="m" className="flex items-center gap-6">
340
- <div className="flex items-center gap-2">
341
- <RadioGroupItem size={globalSize} value="s" id="rg-s" />
342
- <Label htmlFor="rg-s" className="cursor-pointer font-normal">
343
- S
344
- </Label>
345
- </div>
346
- <div className="flex items-center gap-2">
347
- <RadioGroupItem size={globalSize} value="m" id="rg-m" />
348
- <Label htmlFor="rg-m" className="cursor-pointer font-normal">
349
- M
350
- </Label>
351
- </div>
352
- <div className="flex items-center gap-2">
353
- <RadioGroupItem size={globalSize} value="l" id="rg-l" />
354
- <Label htmlFor="rg-l" className="cursor-pointer font-normal">
355
- L
356
- </Label>
357
- </div>
358
- </RadioGroup>
359
- </div>
360
- </ExampleSection>
311
+ </div>`} preview={
312
+ <>
313
+ <div className="space-y-3 w-full">
314
+ <Label className="block text-muted-foreground">Kích thước</Label>
315
+ <RadioGroup defaultValue="m" className="flex items-center gap-6">
316
+ <div className="flex items-center gap-2">
317
+ <RadioGroupItem size={globalSize} value="s" id="rg-s" />
318
+ <Label htmlFor="rg-s" className="cursor-pointer font-normal">
319
+ S
320
+ </Label>
321
+ </div>
322
+ <div className="flex items-center gap-2">
323
+ <RadioGroupItem size={globalSize} value="m" id="rg-m" />
324
+ <Label htmlFor="rg-m" className="cursor-pointer font-normal">
325
+ M
326
+ </Label>
327
+ </div>
328
+ <div className="flex items-center gap-2">
329
+ <RadioGroupItem size={globalSize} value="l" id="rg-l" />
330
+ <Label htmlFor="rg-l" className="cursor-pointer font-normal">
331
+ L
332
+ </Label>
333
+ </div>
334
+ </RadioGroup>
335
+ </div>
336
+ </>
337
+ } />
361
338
  </ExampleGrid>
362
339
 
363
340
  <ExampleGrid>
364
- <ExampleSection
365
- label="Ghép nối Field thủ công"
366
- description="Tạo layout RadioGroup phức tạp với Field."
367
- codeString={`<Field data-invalid={true} className="w-full gap-4">
341
+ <ShowcaseExample title="Ghép nối Field thủ công" description="Tạo layout RadioGroup phức tạp với Field." code={`<Field data-invalid={true} className="w-full gap-4">
368
342
  <FieldLabel>Gói cước của bạn</FieldLabel>
369
343
  <RadioGroup
370
344
  defaultValue="monthly"
@@ -398,48 +372,46 @@ function RadioGroupMicroShowcase({ globalSize }: { globalSize: Size }) {
398
372
  </Field>
399
373
  </RadioGroup>
400
374
  <FieldError>Thẻ của bạn đã bị từ chối.</FieldError>
401
- </Field>`}
402
- >
403
- <Field data-invalid={true} className="w-full gap-4">
404
- <FieldLabel>Gói cước của bạn</FieldLabel>
405
- <RadioGroup defaultValue="monthly" className="flex flex-col gap-2">
406
- <Field orientation="horizontal" size={globalSize}>
407
- <RadioGroupItem
408
- size={globalSize}
409
- value="monthly"
410
- id="plan-1"
411
- aria-invalid={true}
412
- />
413
- <FieldLabel
414
- htmlFor="plan-1"
415
- className="font-normal cursor-pointer"
416
- >
417
- Thanh toán tháng ($10/mo)
418
- </FieldLabel>
419
- </Field>
420
- <Field orientation="horizontal" size={globalSize}>
421
- <RadioGroupItem
422
- size={globalSize}
423
- value="yearly"
424
- id="plan-2"
425
- aria-invalid={true}
426
- />
427
- <FieldLabel
428
- htmlFor="plan-2"
429
- className="font-normal cursor-pointer"
430
- >
431
- Thanh toán năm ($100/yr)
432
- </FieldLabel>
433
- </Field>
434
- </RadioGroup>
435
- <FieldError>Thẻ của bạn đã bị từ chối.</FieldError>
436
- </Field>
437
- </ExampleSection>
375
+ </Field>`} preview={
376
+ <>
377
+ <Field data-invalid={true} className="w-full gap-4">
378
+ <FieldLabel>Gói cước của bạn</FieldLabel>
379
+ <RadioGroup defaultValue="monthly" className="flex flex-col gap-2">
380
+ <Field orientation="horizontal" size={globalSize}>
381
+ <RadioGroupItem
382
+ size={globalSize}
383
+ value="monthly"
384
+ id="plan-1"
385
+ aria-invalid={true}
386
+ />
387
+ <FieldLabel
388
+ htmlFor="plan-1"
389
+ className="font-normal cursor-pointer"
390
+ >
391
+ Thanh toán tháng ($10/mo)
392
+ </FieldLabel>
393
+ </Field>
394
+ <Field orientation="horizontal" size={globalSize}>
395
+ <RadioGroupItem
396
+ size={globalSize}
397
+ value="yearly"
398
+ id="plan-2"
399
+ aria-invalid={true}
400
+ />
401
+ <FieldLabel
402
+ htmlFor="plan-2"
403
+ className="font-normal cursor-pointer"
404
+ >
405
+ Thanh toán năm ($100/yr)
406
+ </FieldLabel>
407
+ </Field>
408
+ </RadioGroup>
409
+ <FieldError>Thẻ của bạn đã bị từ chối.</FieldError>
410
+ </Field>
411
+ </>
412
+ } />
438
413
 
439
- <ExampleSection
440
- label="Card Layout (UI Nâng cao)"
441
- description="Radio nhưng thiết kế dưới dạng Card để bấm."
442
- codeString={`<RadioGroup
414
+ <ShowcaseExample title="Card Layout (UI Nâng cao)" description="Radio nhưng thiết kế dưới dạng Card để bấm." code={`<RadioGroup
443
415
  defaultValue="card-2"
444
416
  className="grid grid-cols-2 gap-4 w-full"
445
417
  >
@@ -467,37 +439,34 @@ function RadioGroupMicroShowcase({ globalSize }: { globalSize: Size }) {
467
439
  <div className="text-xl">🌙</div>
468
440
  <span>Tối</span>
469
441
  </Label>
470
- </RadioGroup>`}
471
- >
472
- <RadioGroup
473
- defaultValue="card-2"
474
- className="grid grid-cols-2 gap-4 w-full"
475
- >
476
- <Label
477
- htmlFor="card-1"
478
- className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground [&:has([data-state=checked])]:border-primary cursor-pointer gap-4"
479
- >
480
- <RadioGroupItem value="card-1" id="card-1" className="sr-only" />
481
- <div className="text-xl">☀️</div>
482
- <span>Sáng</span>
483
- </Label>
484
- <Label
485
- htmlFor="card-2"
486
- className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground [&:has([data-state=checked])]:border-primary cursor-pointer gap-4"
487
- >
488
- <RadioGroupItem value="card-2" id="card-2" className="sr-only" />
489
- <div className="text-xl">🌙</div>
490
- <span>Tối</span>
491
- </Label>
492
- </RadioGroup>
493
- </ExampleSection>
442
+ </RadioGroup>`} preview={
443
+ <>
444
+ <RadioGroup
445
+ defaultValue="card-2"
446
+ className="grid grid-cols-2 gap-4 w-full"
447
+ >
448
+ <Label
449
+ htmlFor="card-1"
450
+ className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground [&:has([data-state=checked])]:border-primary cursor-pointer gap-4"
451
+ >
452
+ <RadioGroupItem value="card-1" id="card-1" className="sr-only" />
453
+ <div className="text-xl">☀️</div>
454
+ <span>Sáng</span>
455
+ </Label>
456
+ <Label
457
+ htmlFor="card-2"
458
+ className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground [&:has([data-state=checked])]:border-primary cursor-pointer gap-4"
459
+ >
460
+ <RadioGroupItem value="card-2" id="card-2" className="sr-only" />
461
+ <div className="text-xl">🌙</div>
462
+ <span>Tối</span>
463
+ </Label>
464
+ </RadioGroup>
465
+ </>
466
+ } />
494
467
  </ExampleGrid>
495
468
 
496
- <ExampleSection
497
- label="🧭 Use Case Comparison"
498
- description="So sánh nhanh khi nào dùng Micro và Macro."
499
- fullWidth
500
- codeString={`<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
469
+ <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">
501
470
  {/* Story 1: Macro wins */}
502
471
  <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
503
472
  <div className="flex items-start gap-3">
@@ -569,120 +538,91 @@ function RadioGroupMicroShowcase({ globalSize }: { globalSize: Size }) {
569
538
  <DocsCode>Label</DocsCode> thành 1 cái thẻ Card.
570
539
  </p>
571
540
  </div>
572
- </div>`}
573
- >
574
- <div className="grid grid-cols-1 gap-6 md:grid-cols-2">
575
- {/* Story 1: Macro wins */}
576
- <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
577
- <div className="flex items-start gap-3">
578
- <span className="mt-0.5 shrink-0 rounded-full bg-green-500/10 p-1.5 text-green-600">
579
- <svg
580
- xmlns="http://www.w3.org/2000/svg"
581
- className="size-4"
582
- viewBox="0 0 24 24"
583
- fill="none"
584
- stroke="currentColor"
585
- strokeWidth="2"
586
- strokeLinecap="round"
587
- strokeLinejoin="round"
588
- aria-hidden="true"
589
- >
590
- <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
591
- </svg>
592
- </span>
593
- <div>
594
- <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
595
- Story 1 · Dùng Macro
596
- </p>
597
- <h3 className="mt-0.5 text-sm font-semibold text-foreground">
598
- Câu hỏi khảo sát
599
- </h3>
600
- </div>
601
- </div>
602
- <p className="text-xs text-muted-foreground leading-relaxed">
603
- Bạn cần làm một danh sách dài các tuỳ chọn dạng chữ từ trên xuống
604
- dưới. Macro <DocsCode>RadioGroupPreset</DocsCode> sinh ra để xử lý
605
- việc này nhanh gọn qua thuộc tính <DocsCode>options</DocsCode>.
606
- </p>
607
- </div>
541
+ </div>`} preview={
542
+ <>
543
+ <div className="grid grid-cols-1 gap-6 md:grid-cols-2">
544
+ <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
545
+ <div className="flex items-start gap-3">
546
+ <span className="mt-0.5 shrink-0 rounded-full bg-green-500/10 p-1.5 text-green-600">
547
+ <svg
548
+ xmlns="http://www.w3.org/2000/svg"
549
+ className="size-4"
550
+ viewBox="0 0 24 24"
551
+ fill="none"
552
+ stroke="currentColor"
553
+ strokeWidth="2"
554
+ strokeLinecap="round"
555
+ strokeLinejoin="round"
556
+ aria-hidden="true"
557
+ >
558
+ <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
559
+ </svg>
560
+ </span>
561
+ <div>
562
+ <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
563
+ Story 1 · Dùng Macro
564
+ </p>
565
+ <h3 className="mt-0.5 text-sm font-semibold text-foreground">
566
+ Câu hỏi khảo sát
567
+ </h3>
568
+ </div>
569
+ </div>
570
+ <p className="text-xs text-muted-foreground leading-relaxed">
571
+ Bạn cần làm một danh sách dài các tuỳ chọn dạng chữ từ trên xuống
572
+ dưới. Macro <DocsCode>RadioGroupPreset</DocsCode> sinh ra để xử
573
+ việc này nhanh gọn qua thuộc tính <DocsCode>options</DocsCode>.
574
+ </p>
575
+ </div>
608
576
 
609
- {/* Story 2: Micro wins */}
610
- <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
611
- <div className="flex items-start gap-3">
612
- <span className="mt-0.5 shrink-0 rounded-full bg-blue-500/10 p-1.5 text-blue-600">
613
- <svg
614
- xmlns="http://www.w3.org/2000/svg"
615
- className="size-4"
616
- viewBox="0 0 24 24"
617
- fill="none"
618
- stroke="currentColor"
619
- strokeWidth="2"
620
- strokeLinecap="round"
621
- strokeLinejoin="round"
622
- aria-hidden="true"
623
- >
624
- <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" />
625
- </svg>
626
- </span>
627
- <div>
628
- <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
629
- Story 2 · Dùng Micro
630
- </p>
631
- <h3 className="mt-0.5 text-sm font-semibold text-foreground">
632
- Radio Ẩn (Hidden Radio Card)
633
- </h3>
634
- </div>
635
- </div>
636
- <p className="text-xs text-muted-foreground leading-relaxed">
637
- Bạn muốn người dùng click vào một khối Card lớn (chứa ảnh sản
638
- phẩm, tả) thay vì click vào nút tròn. Bạn sẽ dùng Micro để ẩn
639
- đi <DocsCode>RadioGroupItem</DocsCode> style{" "}
640
- <DocsCode>Label</DocsCode> thành 1 cái thẻ Card.
641
- </p>
642
- </div>
643
- </div>
644
- </ExampleSection>
577
+ <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
578
+ <div className="flex items-start gap-3">
579
+ <span className="mt-0.5 shrink-0 rounded-full bg-blue-500/10 p-1.5 text-blue-600">
580
+ <svg
581
+ xmlns="http://www.w3.org/2000/svg"
582
+ className="size-4"
583
+ viewBox="0 0 24 24"
584
+ fill="none"
585
+ stroke="currentColor"
586
+ strokeWidth="2"
587
+ strokeLinecap="round"
588
+ strokeLinejoin="round"
589
+ aria-hidden="true"
590
+ >
591
+ <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" />
592
+ </svg>
593
+ </span>
594
+ <div>
595
+ <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
596
+ Story 2 · Dùng Micro
597
+ </p>
598
+ <h3 className="mt-0.5 text-sm font-semibold text-foreground">
599
+ Radio Ẩn (Hidden Radio Card)
600
+ </h3>
601
+ </div>
602
+ </div>
603
+ <p className="text-xs text-muted-foreground leading-relaxed">
604
+ Bạn muốn người dùng click vào một khối Card lớn (chứa ảnh sản
605
+ phẩm, tả) thay click vào nút tròn. Bạn sẽ dùng Micro để ẩn
606
+ đi <DocsCode>RadioGroupItem</DocsCode> style{" "}
607
+ <DocsCode>Label</DocsCode> thành 1 cái thẻ Card.
608
+ </p>
609
+ </div>
610
+ </div>
611
+ </>
612
+ } />
645
613
  </div>
646
614
  );
647
615
  }
648
616
 
649
- // ──────────────────────────────────────────────────────────
650
- // SECTION 3: Entry point
651
- // ──────────────────────────────────────────────────────────
652
617
  export default function RadioGroupShowcase() {
653
618
  const { size: globalSize } = useDevContext();
654
619
  return (
655
620
  <Showcase
656
621
  title="Radio Group"
657
622
  description="Tập hợp các nút chọn một tuỳ chọn duy nhất trong danh sách (Radio Buttons)."
658
- generalConcept={
659
- <ShowcaseDocs>
660
- <DocsH3>Khi nào nên dùng Macro</DocsH3>
661
- <DocsP>
662
- <DocsCode>RadioGroupPreset</DocsCode> đóng gói sẵn cấu trúc form
663
- tiêu chuẩn: Label tổng, Description tổng, Error Message tổng và tự
664
- động render danh sách các <DocsCode>options</DocsCode> thành các
665
- RadioGroupItem. Dùng Macro cho 95% trường hợp làm form trắc nghiệm,
666
- chọn 1 trong nhiều tuỳ chọn.
667
- </DocsP>
668
- <DocsH3>Khi nào nên dùng Micro</DocsH3>
669
- <DocsP>
670
- Dùng <DocsCode>RadioGroup</DocsCode> và{" "}
671
- <DocsCode>RadioGroupItem</DocsCode> nguyên thuỷ khi bạn cần một
672
- layout dị biệt (như hiển thị các radio nằm ngang thay vì dọc) hoặc
673
- khi mỗi option không đơn thuần là text mà chứa layout hình ảnh phức
674
- tạp (như chọn Card hình ảnh thay vì text).
675
- </DocsP>
676
- </ShowcaseDocs>
677
- }
678
- tabs={[
679
- {
680
- label: "Micro (Primitive)",
681
- content: <RadioGroupMicroShowcase globalSize={globalSize} /> },
682
- {
683
- label: "Macro (Preset)",
684
- content: <RadioGroupMacroShowcase globalSize={globalSize} /> },
685
- ]}
623
+
624
+ micro={{ content: <RadioGroupMicroShowcase globalSize={globalSize} /> }}
625
+ macro={{ content: <RadioGroupMacroShowcase globalSize={globalSize} /> }}
686
626
  />
687
627
  );
688
628
  }