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
@@ -23,44 +23,36 @@ import {
23
23
  DocsP,
24
24
  DocsUl,
25
25
  ExampleGrid,
26
- ExampleSection,
26
+ ShowcaseExample,
27
27
  Showcase,
28
28
  ShowcaseDocs
29
29
  } from "../../dev/components/showcase";
30
30
  import { type Size } from "../../lib/types";
31
31
 
32
- // ──────────────────────────────────────────────────────────
33
- // SECTION 1: Macro Content
34
- // ──────────────────────────────────────────────────────────
35
32
  function InputMacroShowcase({ globalSize }: { globalSize: Size }) {
36
33
  return (
37
- <div className="space-y-10 mt-6">
34
+ <div className="space-y-10">
38
35
  <ExampleGrid>
39
- <ExampleSection
40
- label="Tiêu chuẩn"
41
- description="Trường nhập văn bản hoàn chỉnh có nhãn và mô tả."
42
- codeString={`<InputPreset
36
+ <ShowcaseExample title="Tiêu chuẩn" description="Trường nhập văn bản hoàn chỉnh có nhãn và mô tả." code={`<InputPreset
43
37
  size="${globalSize}"
44
38
  label="Tên đăng nhập"
45
39
  description="Đây sẽ là tên hiển thị công khai của bạn."
46
40
  placeholder="johndoe"
47
41
  className="w-full"
48
42
  />
49
- `}
50
- >
51
- <InputPreset
52
- size={globalSize}
53
- label="Tên đăng nhập"
54
- description="Đây sẽ là tên hiển thị công khai của bạn."
55
- placeholder="johndoe"
56
- className="w-full"
57
- />
58
- </ExampleSection>
43
+ `} preview={
44
+ <>
45
+ <InputPreset
46
+ size={globalSize}
47
+ label="Tên đăng nhập"
48
+ description="Đây sẽ là tên hiển thị công khai của bạn."
49
+ placeholder="johndoe"
50
+ className="w-full"
51
+ />
52
+ </>
53
+ } />
59
54
 
60
- <ExampleSection
61
- label="Lỗi xác thực (Validation Error)"
62
- description="Hiển thị thông báo lỗi và viền đỏ báo hiệu khi truyền errorMessage."
63
- codeString={`<InputPreset
55
+ <ShowcaseExample title="Lỗi xác thực (Validation Error)" description="Hiển thị thông báo lỗi và viền đỏ báo hiệu khi truyền errorMessage." code={`<InputPreset
64
56
  size="${globalSize}"
65
57
  label="Mật khẩu"
66
58
  type="password"
@@ -68,24 +60,22 @@ function InputMacroShowcase({ globalSize }: { globalSize: Size }) {
68
60
  errorMessage="Mật khẩu phải chứa ít nhất 8 ký tự."
69
61
  className="w-full"
70
62
  />
71
- `}
72
- >
73
- <InputPreset
74
- size={globalSize}
75
- label="Mật khẩu"
76
- type="password"
77
- placeholder="Nhập mật khẩu..."
78
- errorMessage="Mật khẩu phải chứa ít nhất 8 ký tự."
79
- className="w-full"
80
- />
81
- </ExampleSection>
63
+ `} preview={
64
+ <>
65
+ <InputPreset
66
+ size={globalSize}
67
+ label="Mật khẩu"
68
+ type="password"
69
+ placeholder="Nhập mật khẩu..."
70
+ errorMessage="Mật khẩu phải chứa ít nhất 8 ký tự."
71
+ className="w-full"
72
+ />
73
+ </>
74
+ } />
82
75
  </ExampleGrid>
83
76
 
84
77
  <ExampleGrid>
85
- <ExampleSection
86
- label="Với Tiền tố / Hậu tố (Adornments)"
87
- description="Tự động bọc bằng InputGroup, có thể truyền chuỗi hoặc icon."
88
- codeString={`<InputPreset
78
+ <ShowcaseExample title="Với Tiền tố / Hậu tố (Adornments)" description="Tự động bọc bằng InputGroup, có thể truyền chuỗi hoặc icon." code={`<InputPreset
89
79
  size="${globalSize}"
90
80
  label="Website URL"
91
81
  type="url"
@@ -94,23 +84,21 @@ function InputMacroShowcase({ globalSize }: { globalSize: Size }) {
94
84
  endAdornment=".com"
95
85
  className="w-full"
96
86
  />
97
- `}
98
- >
99
- <InputPreset
100
- size={globalSize}
101
- label="Website URL"
102
- type="url"
103
- placeholder="example"
104
- startAdornment="https://"
105
- endAdornment=".com"
106
- className="w-full"
107
- />
108
- </ExampleSection>
87
+ `} preview={
88
+ <>
89
+ <InputPreset
90
+ size={globalSize}
91
+ label="Website URL"
92
+ type="url"
93
+ placeholder="example"
94
+ startAdornment="https://"
95
+ endAdornment=".com"
96
+ className="w-full"
97
+ />
98
+ </>
99
+ } />
109
100
 
110
- <ExampleSection
111
- label="Khóa / Bất hoạt (Disabled)"
112
- description="Người dùng không thể tương tác với form."
113
- codeString={`<InputPreset
101
+ <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={`<InputPreset
114
102
  size="${globalSize}"
115
103
  label="Tên dự án"
116
104
  description="Tên dự án không thể thay đổi sau khi khởi tạo."
@@ -118,24 +106,21 @@ function InputMacroShowcase({ globalSize }: { globalSize: Size }) {
118
106
  disabled
119
107
  className="w-full"
120
108
  />
121
- `}
122
- >
123
- <InputPreset
124
- size={globalSize}
125
- label="Tên dự án"
126
- description="Tên dự án không thể thay đổi sau khi khởi tạo."
127
- defaultValue="my-awesome-project"
128
- disabled
129
- className="w-full"
130
- />
131
- </ExampleSection>
109
+ `} preview={
110
+ <>
111
+ <InputPreset
112
+ size={globalSize}
113
+ label="Tên dự án"
114
+ description="Tên dự án không thể thay đổi sau khi khởi tạo."
115
+ defaultValue="my-awesome-project"
116
+ disabled
117
+ className="w-full"
118
+ />
119
+ </>
120
+ } />
132
121
  </ExampleGrid>
133
122
 
134
- <ExampleSection
135
- label="Thực tế sử dụng (Real-world Snippets)"
136
- description="Tuỳ biến Label với ReactNode để tạo các nhãn phức tạp."
137
- fullWidth
138
- codeString={`<InputPreset
123
+ <ShowcaseExample title="Thực tế sử dụng (Real-world Snippets)" description="Tuỳ biến Label với ReactNode để tạo các nhãn phức tạp." code={`<InputPreset
139
124
  size="${globalSize}"
140
125
  label={
141
126
  <span className="flex items-center gap-2">
@@ -159,39 +144,40 @@ function InputMacroShowcase({ globalSize }: { globalSize: Size }) {
159
144
  </kbd>
160
145
  }
161
146
  className="w-full"
162
- />`}
163
- >
164
- <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
165
- <InputPreset
166
- size={globalSize}
167
- label={
168
- <span className="flex items-center gap-2">
169
- Mã API (API Key){" "}
170
- <span className="rounded bg-destructive/20 px-1.5 py-0.5 text-[10px] font-semibold text-destructive uppercase">
171
- Bảo mật
172
- </span>
173
- </span>
174
- }
175
- type="password"
176
- description="Tuyệt đối không chia sẻ mã này với bất kỳ ai."
177
- defaultValue="sk_test_1234567890abcdef"
178
- className="w-full"
179
- />
147
+ />`} preview={
148
+ <>
149
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
150
+ <InputPreset
151
+ size={globalSize}
152
+ label={
153
+ <span className="flex items-center gap-2">
154
+ Mã API (API Key){" "}
155
+ <span className="rounded bg-destructive/20 px-1.5 py-0.5 text-[10px] font-semibold text-destructive uppercase">
156
+ Bảo mật
157
+ </span>
158
+ </span>
159
+ }
160
+ type="password"
161
+ description="Tuyệt đối không chia sẻ mã này với bất kỳ ai."
162
+ defaultValue="sk_test_1234567890abcdef"
163
+ className="w-full"
164
+ />
180
165
 
181
- <InputPreset
182
- size={globalSize}
183
- label="Tìm kiếm nhanh"
184
- placeholder="Gõ từ khoá..."
185
- startAdornment={<SearchIcon className="size-4" />}
186
- endAdornment={
187
- <kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground">
188
- <span className="text-xs">⌘</span>K
189
- </kbd>
190
- }
191
- className="w-full"
192
- />
193
- </div>
194
- </ExampleSection>
166
+ <InputPreset
167
+ size={globalSize}
168
+ label="Tìm kiếm nhanh"
169
+ placeholder="Gõ từ khoá..."
170
+ startAdornment={<SearchIcon className="size-4" />}
171
+ endAdornment={
172
+ <kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground">
173
+ <span className="text-xs">⌘</span>K
174
+ </kbd>
175
+ }
176
+ className="w-full"
177
+ />
178
+ </div>
179
+ </>
180
+ } />
195
181
  </div>
196
182
  );
197
183
  }
@@ -201,29 +187,24 @@ function InputMacroShowcase({ globalSize }: { globalSize: Size }) {
201
187
  // ──────────────────────────────────────────────────────────
202
188
  function InputMicroShowcase({ globalSize }: { globalSize: Size }) {
203
189
  return (
204
- <div className="space-y-10 mt-6">
190
+ <div className="space-y-10">
205
191
  <ExampleGrid>
206
- <ExampleSection
207
- label="Cơ bản (Primitive)"
208
- description="Thẻ input đơn giản không có nhãn."
209
- codeString={`<Input
192
+ <ShowcaseExample title="Cơ bản (Primitive)" description="Thẻ input đơn giản không có nhãn." code={`<Input
210
193
  size="${globalSize}"
211
194
  placeholder="Nhập địa chỉ email..."
212
195
  className="w-full"
213
196
  />
214
- `}
215
- >
216
- <Input
217
- size={globalSize}
218
- placeholder="Nhập địa chỉ email..."
219
- className="w-full"
220
- />
221
- </ExampleSection>
197
+ `} preview={
198
+ <>
199
+ <Input
200
+ size={globalSize}
201
+ placeholder="Nhập địa chỉ email..."
202
+ className="w-full"
203
+ />
204
+ </>
205
+ } />
222
206
 
223
- <ExampleSection
224
- label="Ghép nối với Field"
225
- description="Lắp ráp thủ công các thành phần Field để tạo form control."
226
- codeString={`<Field size="${globalSize}" className="w-full">
207
+ <ShowcaseExample title="Ghép nối với Field" description="Lắp ráp thủ công các thành phần Field để tạo form control." code={`<Field size="${globalSize}" className="w-full">
227
208
  <FieldLabel htmlFor="tf-input">Email</FieldLabel>
228
209
  <FieldDescription>
229
210
  Chúng tôi sẽ không bao giờ chia sẻ email của bạn.
@@ -236,29 +217,27 @@ function InputMicroShowcase({ globalSize }: { globalSize: Size }) {
236
217
  />
237
218
  </FieldContent>
238
219
  </Field>
239
- `}
240
- >
241
- <Field size={globalSize} className="w-full">
242
- <FieldLabel htmlFor="tf-input">Email</FieldLabel>
243
- <FieldDescription>
244
- Chúng tôi sẽ không bao giờ chia sẻ email của bạn.
245
- </FieldDescription>
246
- <FieldContent>
247
- <Input
248
- id="tf-input"
249
- size={globalSize}
250
- placeholder="you@example.com"
251
- />
252
- </FieldContent>
253
- </Field>
254
- </ExampleSection>
220
+ `} preview={
221
+ <>
222
+ <Field size={globalSize} className="w-full">
223
+ <FieldLabel htmlFor="tf-input">Email</FieldLabel>
224
+ <FieldDescription>
225
+ Chúng tôi sẽ không bao giờ chia sẻ email của bạn.
226
+ </FieldDescription>
227
+ <FieldContent>
228
+ <Input
229
+ id="tf-input"
230
+ size={globalSize}
231
+ placeholder="you@example.com"
232
+ />
233
+ </FieldContent>
234
+ </Field>
235
+ </>
236
+ } />
255
237
  </ExampleGrid>
256
238
 
257
239
  <ExampleGrid>
258
- <ExampleSection
259
- label="Trạng thái Lỗi (Error)"
260
- description="Sử dụng thuộc tính aria-invalid để báo lỗi."
261
- codeString={`<Field size="${globalSize}" className="w-full">
240
+ <ShowcaseExample title="Trạng thái Lỗi (Error)" description="Sử dụng thuộc tính aria-invalid để báo lỗi." code={`<Field size="${globalSize}" className="w-full">
262
241
  <FieldLabel htmlFor="tf-error">Tên tài khoản</FieldLabel>
263
242
  <FieldContent>
264
243
  <Input
@@ -272,28 +251,26 @@ function InputMicroShowcase({ globalSize }: { globalSize: Size }) {
272
251
  Tên tài khoản không được chứa ký tự đặc biệt.
273
252
  </FieldError>
274
253
  </Field>
275
- `}
276
- >
277
- <Field size={globalSize} className="w-full">
278
- <FieldLabel htmlFor="tf-error">Tên tài khoản</FieldLabel>
279
- <FieldContent>
280
- <Input
281
- id="tf-error"
282
- size={globalSize}
283
- defaultValue="admin!@#"
284
- aria-invalid="true"
285
- />
286
- </FieldContent>
287
- <FieldError>
288
- Tên tài khoản không được chứa ký tự đặc biệt.
289
- </FieldError>
290
- </Field>
291
- </ExampleSection>
254
+ `} preview={
255
+ <>
256
+ <Field size={globalSize} className="w-full">
257
+ <FieldLabel htmlFor="tf-error">Tên tài khoản</FieldLabel>
258
+ <FieldContent>
259
+ <Input
260
+ id="tf-error"
261
+ size={globalSize}
262
+ defaultValue="admin!@#"
263
+ aria-invalid="true"
264
+ />
265
+ </FieldContent>
266
+ <FieldError>
267
+ Tên tài khoản không được chứa ký tự đặc biệt.
268
+ </FieldError>
269
+ </Field>
270
+ </>
271
+ } />
292
272
 
293
- <ExampleSection
294
- label="Input Group"
295
- description="Ghép nối với các Addon linh hoạt (Slot tuỳ ý)."
296
- codeString={`<Field size="${globalSize}" className="w-full">
273
+ <ShowcaseExample title="Input Group" description="Ghép nối với các Addon linh hoạt (Slot tuỳ ý)." code={`<Field size="${globalSize}" className="w-full">
297
274
  <FieldLabel htmlFor="tf-group">Trang cá nhân</FieldLabel>
298
275
  <FieldContent>
299
276
  <InputGroup size="${globalSize}">
@@ -307,57 +284,49 @@ function InputMicroShowcase({ globalSize }: { globalSize: Size }) {
307
284
  </InputGroup>
308
285
  </FieldContent>
309
286
  </Field>
310
- `}
311
- >
312
- <Field size={globalSize} className="w-full">
313
- <FieldLabel htmlFor="tf-group">Trang cá nhân</FieldLabel>
314
- <FieldContent>
315
- <InputGroup size={globalSize}>
316
- <InputGroupAddon>
317
- <LinkIcon className="size-4 text-muted-foreground" />
318
- </InputGroupAddon>
319
- <InputGroupAddon>
320
- <InputGroupText>github.com/</InputGroupText>
321
- </InputGroupAddon>
322
- <InputGroupInput id="tf-group" placeholder="username" />
323
- </InputGroup>
324
- </FieldContent>
325
- </Field>
326
- </ExampleSection>
287
+ `} preview={
288
+ <>
289
+ <Field size={globalSize} className="w-full">
290
+ <FieldLabel htmlFor="tf-group">Trang cá nhân</FieldLabel>
291
+ <FieldContent>
292
+ <InputGroup size={globalSize}>
293
+ <InputGroupAddon>
294
+ <LinkIcon className="size-4 text-muted-foreground" />
295
+ </InputGroupAddon>
296
+ <InputGroupAddon>
297
+ <InputGroupText>github.com/</InputGroupText>
298
+ </InputGroupAddon>
299
+ <InputGroupInput id="tf-group" placeholder="username" />
300
+ </InputGroup>
301
+ </FieldContent>
302
+ </Field>
303
+ </>
304
+ } />
327
305
  </ExampleGrid>
328
- <ExampleSection
329
- label="Input Kiểu Tệp (File)"
330
- description="Input có hỗ trợ style gốc cho type file."
331
- codeString={`<Input size="${globalSize}" type="file" className="w-full pt-0.5" />
332
- `}
333
- >
334
- <Input size={globalSize} type="file" className="w-full pt-0.5" />
335
- </ExampleSection>
306
+ <ShowcaseExample title="Input Kiểu Tệp (File)" description="Input có hỗ trợ style gốc cho type file." code={`<Input size="${globalSize}" type="file" className="w-full pt-0.5" />
307
+ `} preview={
308
+ <>
309
+ <Input size={globalSize} type="file" className="w-full pt-0.5" />
310
+ </>
311
+ } />
336
312
 
337
- <ExampleSection
338
- label="Khóa (Disabled)"
339
- description="Trạng thái không thể tương tác."
340
- codeString={`<Input
313
+ <ShowcaseExample title="Khóa (Disabled)" description="Trạng thái không thể tương tác." code={`<Input
341
314
  size="${globalSize}"
342
315
  disabled
343
316
  defaultValue="Chỉ đọc"
344
317
  className="w-full"
345
318
  />
346
- `}
347
- >
348
- <Input
349
- size={globalSize}
350
- disabled
351
- defaultValue="Chỉ đọc"
352
- className="w-full"
353
- />
354
- </ExampleSection>
355
- <ExampleSection
356
- label="🧭 Use Case Comparison"
357
- description="So sánh nhanh khi nào dùng Micro và Macro."
358
- fullWidth
359
- codeString={`<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
360
- {/* Story 1: Macro wins */}
319
+ `} preview={
320
+ <>
321
+ <Input
322
+ size={globalSize}
323
+ disabled
324
+ defaultValue="Chỉ đọc"
325
+ className="w-full"
326
+ />
327
+ </>
328
+ } />
329
+ <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">
361
330
  <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
362
331
  <div className="flex items-start gap-3">
363
332
  <span className="mt-0.5 shrink-0 rounded-full bg-green-500/10 p-1.5 text-green-600">
@@ -392,7 +361,6 @@ function InputMicroShowcase({ globalSize }: { globalSize: Size }) {
392
361
  </p>
393
362
  </div>
394
363
 
395
- {/* Story 2: Micro wins */}
396
364
  <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
397
365
  <div className="flex items-start gap-3">
398
366
  <span className="mt-0.5 shrink-0 rounded-full bg-blue-500/10 p-1.5 text-blue-600">
@@ -426,76 +394,77 @@ function InputMicroShowcase({ globalSize }: { globalSize: Size }) {
426
394
  khác.
427
395
  </p>
428
396
  </div>
429
- </div>`}
430
- >
431
- <div className="grid grid-cols-1 gap-6 md:grid-cols-2">
432
- <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
433
- <div className="flex items-start gap-3">
434
- <span className="mt-0.5 shrink-0 rounded-full bg-green-500/10 p-1.5 text-green-600">
435
- <svg
436
- xmlns="http://www.w3.org/2000/svg"
437
- className="size-4"
438
- viewBox="0 0 24 24"
439
- fill="none"
440
- stroke="currentColor"
441
- strokeWidth="2"
442
- strokeLinecap="round"
443
- strokeLinejoin="round"
444
- aria-hidden="true"
445
- >
446
- <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
447
- </svg>
448
- </span>
449
- <div>
450
- <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
451
- Story 1 · Dùng Macro
452
- </p>
453
- <h3 className="mt-0.5 text-sm font-semibold text-foreground">
454
- Form nhập liệu tiêu chuẩn
455
- </h3>
456
- </div>
457
- </div>
458
- <p className="text-xs text-muted-foreground leading-relaxed">
459
- Khi bạn cần một trường nhập liệu đầy đủ nhãn (Label), mô tả
460
- (Description), báo lỗi (Error) mà không muốn phải lắp ráp thủ công
461
- bằng <DocsCode>Field</DocsCode>.
462
- </p>
463
- </div>
397
+ </div>`} preview={
398
+ <>
399
+ <div className="grid grid-cols-1 gap-6 md:grid-cols-2">
400
+ <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
401
+ <div className="flex items-start gap-3">
402
+ <span className="mt-0.5 shrink-0 rounded-full bg-green-500/10 p-1.5 text-green-600">
403
+ <svg
404
+ xmlns="http://www.w3.org/2000/svg"
405
+ className="size-4"
406
+ viewBox="0 0 24 24"
407
+ fill="none"
408
+ stroke="currentColor"
409
+ strokeWidth="2"
410
+ strokeLinecap="round"
411
+ strokeLinejoin="round"
412
+ aria-hidden="true"
413
+ >
414
+ <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
415
+ </svg>
416
+ </span>
417
+ <div>
418
+ <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
419
+ Story 1 · Dùng Macro
420
+ </p>
421
+ <h3 className="mt-0.5 text-sm font-semibold text-foreground">
422
+ Form nhập liệu tiêu chuẩn
423
+ </h3>
424
+ </div>
425
+ </div>
426
+ <p className="text-xs text-muted-foreground leading-relaxed">
427
+ Khi bạn cần một trường nhập liệu đầy đủ nhãn (Label), mô tả
428
+ (Description), báo lỗi (Error) mà không muốn phải lắp ráp thủ công
429
+ bằng <DocsCode>Field</DocsCode>.
430
+ </p>
431
+ </div>
464
432
 
465
- <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
466
- <div className="flex items-start gap-3">
467
- <span className="mt-0.5 shrink-0 rounded-full bg-blue-500/10 p-1.5 text-blue-600">
468
- <svg
469
- xmlns="http://www.w3.org/2000/svg"
470
- className="size-4"
471
- viewBox="0 0 24 24"
472
- fill="none"
473
- stroke="currentColor"
474
- strokeWidth="2"
475
- strokeLinecap="round"
476
- strokeLinejoin="round"
477
- aria-hidden="true"
478
- >
479
- <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" />
480
- </svg>
481
- </span>
482
- <div>
483
- <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
484
- Story 2 · Dùng Micro
485
- </p>
486
- <h3 className="mt-0.5 text-sm font-semibold text-foreground">
487
- Input nằm trong Navbar hoặc Toolbar
488
- </h3>
489
- </div>
490
- </div>
491
- <p className="text-xs text-muted-foreground leading-relaxed">
492
- Chỉ cần một thẻ <DocsCode>Input</DocsCode> đơn giản để tìm kiếm
493
- nhanh, không cần nhãn hay mô tả cầu kỳ, hoặc khi phải nhúng nó vào
494
- một component phức tạp khác.
495
- </p>
496
- </div>
497
- </div>
498
- </ExampleSection>
433
+ <div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
434
+ <div className="flex items-start gap-3">
435
+ <span className="mt-0.5 shrink-0 rounded-full bg-blue-500/10 p-1.5 text-blue-600">
436
+ <svg
437
+ xmlns="http://www.w3.org/2000/svg"
438
+ className="size-4"
439
+ viewBox="0 0 24 24"
440
+ fill="none"
441
+ stroke="currentColor"
442
+ strokeWidth="2"
443
+ strokeLinecap="round"
444
+ strokeLinejoin="round"
445
+ aria-hidden="true"
446
+ >
447
+ <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" />
448
+ </svg>
449
+ </span>
450
+ <div>
451
+ <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
452
+ Story 2 · Dùng Micro
453
+ </p>
454
+ <h3 className="mt-0.5 text-sm font-semibold text-foreground">
455
+ Input nằm trong Navbar hoặc Toolbar
456
+ </h3>
457
+ </div>
458
+ </div>
459
+ <p className="text-xs text-muted-foreground leading-relaxed">
460
+ Chỉ cần một thẻ <DocsCode>Input</DocsCode> đơn giản để tìm kiếm
461
+ nhanh, không cần nhãn hay mô tả cầu kỳ, hoặc khi phải nhúng nó vào
462
+ một component phức tạp khác.
463
+ </p>
464
+ </div>
465
+ </div>
466
+ </>
467
+ } />
499
468
  </div>
500
469
  );
501
470
  }
@@ -507,58 +476,10 @@ export default function InputShowcase() {
507
476
  <Showcase
508
477
  title="Input"
509
478
  description="Trường nhập văn bản cho phép người dùng điền dữ liệu."
510
- generalConcept={
511
- <ShowcaseDocs>
512
- <DocsH3>Khi nào nên dùng Macro</DocsH3>
513
- <DocsP>
514
- Bản Macro (<DocsCode>InputPreset</DocsCode>) đóng gói sẵn toàn bộ
515
- các thành phần thường thấy của một Form Control: Nhãn (Label), Mô tả
516
- (Description), Lỗi (Error Message) và phần trang trí (Adornments).
517
- Việc này giúp giảm thiểu lượng code lặp đi lặp lại khi xây dựng
518
- form.
519
- </DocsP>
520
-
521
- <DocsH3>Tự động hoá Layout (Macro)</DocsH3>
522
- <DocsUl>
523
- <DocsLi>
524
- Tự động bọc Input vào trong <DocsCode>InputGroup</DocsCode> nếu
525
- bạn truyền <DocsCode>startAdornment</DocsCode> hoặc{" "}
526
- <DocsCode>endAdornment</DocsCode>.
527
- </DocsLi>
528
- <DocsLi>
529
- Tự động hiện Icon con mắt (Toggle ẩn/hiện) nếu{" "}
530
- <DocsCode>type="password"</DocsCode>.
531
- </DocsLi>
532
- <DocsLi>
533
- Tự động thêm class <DocsCode>aria-invalid</DocsCode> vào input nếu
534
- bạn truyền <DocsCode>errorMessage</DocsCode>.
535
- </DocsLi>
536
- </DocsUl>
537
-
538
- <DocsH3>Khi nào nên dùng Micro</DocsH3>
539
- <DocsP>
540
- Thành phần <DocsCode>Input</DocsCode> nguyên thuỷ chỉ là một thẻ{" "}
541
- <DocsCode>input</DocsCode> duy nhất. Để có được một Form Control
542
- đúng chuẩn WCAG, bạn cần phải tự bọc nó bằng{" "}
543
- <DocsCode>Field</DocsCode>, kết nối <DocsCode>FieldLabel</DocsCode>{" "}
544
- và <DocsCode>FieldDescription</DocsCode>.
545
- </DocsP>
546
- <DocsP>
547
- Dùng Micro khi bạn cần layout form dị biệt (ví dụ: label nằm ngang
548
- bên trái input) hoặc khi cần nhúng Input vào một component phức tạp
549
- (như dropdown tìm kiếm).
550
- </DocsP>
551
- </ShowcaseDocs>
552
- }
479
+
553
480
 
554
- tabs={[
555
- {
556
- label: "Micro (Primitive)",
557
- content: <InputMicroShowcase globalSize={globalSize} /> },
558
- {
559
- label: "Macro (Preset)",
560
- content: <InputMacroShowcase globalSize={globalSize} /> },
561
- ]}
481
+ micro={{ content: <InputMicroShowcase globalSize={globalSize} /> }}
482
+ macro={{ content: <InputMacroShowcase globalSize={globalSize} /> }}
562
483
  />
563
484
  );
564
485
  }