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.
- package/README.md +1 -1
- package/package.json +1 -1
- package/scripts/strip-comments.ts +79 -0
- package/src/blocks/auth-form.tsx +34 -30
- package/src/blocks/auth-recovery.tsx +9 -13
- package/src/blocks/auth-split.tsx +46 -36
- package/src/blocks/settings.tsx +84 -117
- package/src/components/macro/alert-preset.tsx +3 -1
- package/src/components/macro/carousel-preset.tsx +0 -1
- package/src/components/macro/checkbox-preset.test.tsx +2 -2
- package/src/components/macro/checkbox-preset.tsx +1 -2
- package/src/components/macro/command-preset.tsx +1 -1
- package/src/components/macro/date-picker.tsx +5 -18
- package/src/components/macro/dialog-preset.tsx +5 -3
- package/src/components/macro/input-preset.tsx +0 -1
- package/src/components/macro/select-preset.tsx +1 -1
- package/src/components/macro/switch-preset.test.tsx +1 -1
- package/src/components/micro/accordion.test.tsx +6 -12
- package/src/components/micro/alert-dialog.tsx +0 -2
- package/src/components/micro/alert.test.tsx +5 -8
- package/src/components/micro/alert.tsx +0 -2
- package/src/components/micro/badge.test.tsx +5 -7
- package/src/components/micro/badge.tsx +1 -3
- package/src/components/micro/button.test.tsx +19 -26
- package/src/components/micro/button.tsx +3 -11
- package/src/components/micro/calendar.tsx +12 -13
- package/src/components/micro/card.test.tsx +3 -5
- package/src/components/micro/carousel.tsx +0 -1
- package/src/components/micro/chart.tsx +3 -2
- package/src/components/micro/checkbox.test.tsx +9 -18
- package/src/components/micro/combobox.tsx +1 -3
- package/src/components/micro/command.tsx +23 -11
- package/src/components/micro/context-menu.tsx +0 -2
- package/src/components/micro/dialog.test.tsx +6 -14
- package/src/components/micro/dialog.tsx +0 -2
- package/src/components/micro/drawer.tsx +0 -3
- package/src/components/micro/dropdown-menu.test.tsx +8 -14
- package/src/components/micro/dropdown-menu.tsx +0 -2
- package/src/components/micro/field.tsx +3 -3
- package/src/components/micro/hover-card.tsx +0 -2
- package/src/components/micro/input-group.tsx +9 -42
- package/src/components/micro/input.test.tsx +15 -24
- package/src/components/micro/navigation-menu.tsx +0 -2
- package/src/components/micro/popover.test.tsx +5 -9
- package/src/components/micro/progress.tsx +5 -1
- package/src/components/micro/select.test.tsx +5 -18
- package/src/components/micro/select.tsx +3 -5
- package/src/components/micro/separator.tsx +1 -1
- package/src/components/micro/sheet.test.tsx +6 -14
- package/src/components/micro/sheet.tsx +0 -2
- package/src/components/micro/sidebar.tsx +5 -6
- package/src/components/micro/sonner.tsx +0 -1
- package/src/components/micro/switch.test.tsx +9 -18
- package/src/components/micro/switch.tsx +1 -1
- package/src/components/micro/tabs.test.tsx +5 -11
- package/src/components/micro/theme-provider.tsx +0 -12
- package/src/components/micro/toggle-group.tsx +1 -12
- package/src/components/micro/tooltip.test.tsx +7 -12
- package/src/dev/App.tsx +6 -6
- package/src/dev/components/BlockViewer.tsx +15 -4
- package/src/dev/components/Container.tsx +20 -0
- package/src/dev/components/GladvnLogo.tsx +3 -9
- package/src/dev/components/code-highlighter.tsx +5 -3
- package/src/dev/components/showcase.tsx +116 -168
- package/src/dev/sections/buttons.tsx +4 -9
- package/src/dev/sections/display.tsx +68 -72
- package/src/dev/sections/feedback.tsx +304 -314
- package/src/dev/sections/forms.tsx +10 -14
- package/src/dev/sections/interactive.tsx +32 -32
- package/src/dev/sections/overview.tsx +2 -10
- package/src/dev/showcase/accordion.tsx +512 -554
- package/src/dev/showcase/alert-dialog.tsx +525 -565
- package/src/dev/showcase/alert.tsx +352 -402
- package/src/dev/showcase/aspect-ratio.tsx +167 -193
- package/src/dev/showcase/avatar.tsx +231 -269
- package/src/dev/showcase/badge.tsx +92 -140
- package/src/dev/showcase/breadcrumb.tsx +113 -135
- package/src/dev/showcase/button.tsx +140 -173
- package/src/dev/showcase/calendar.tsx +187 -237
- package/src/dev/showcase/card.tsx +229 -261
- package/src/dev/showcase/carousel.tsx +288 -315
- package/src/dev/showcase/chart.tsx +44 -50
- package/src/dev/showcase/checkbox.tsx +286 -330
- package/src/dev/showcase/collapsible.tsx +143 -160
- package/src/dev/showcase/combobox.tsx +327 -369
- package/src/dev/showcase/command.tsx +106 -120
- package/src/dev/showcase/context-menu.tsx +93 -107
- package/src/dev/showcase/dialog.tsx +585 -630
- package/src/dev/showcase/drawer.tsx +176 -196
- package/src/dev/showcase/dropdown-menu.tsx +183 -201
- package/src/dev/showcase/empty.tsx +232 -274
- package/src/dev/showcase/hover-card.tsx +153 -180
- package/src/dev/showcase/input-group.tsx +221 -253
- package/src/dev/showcase/input-otp.tsx +204 -250
- package/src/dev/showcase/input.tsx +246 -325
- package/src/dev/showcase/item.tsx +134 -152
- package/src/dev/showcase/kbd.tsx +149 -172
- package/src/dev/showcase/label.tsx +50 -68
- package/src/dev/showcase/menubar.tsx +194 -213
- package/src/dev/showcase/navigation-menu.tsx +119 -133
- package/src/dev/showcase/overview-components/ArchitectureSection.tsx +126 -0
- package/src/dev/showcase/overview-components/CodeBlock.tsx +50 -0
- package/src/dev/showcase/overview-components/ColorPaletteSection.tsx +44 -0
- package/src/dev/showcase/overview-components/DashboardPreview.tsx +159 -0
- package/src/dev/showcase/overview-components/FeatureGridSection.tsx +535 -0
- package/src/dev/showcase/overview-components/FooterCTA.tsx +137 -0
- package/src/dev/showcase/overview-components/HeroSection.tsx +65 -0
- package/src/dev/showcase/overview-components/PrinciplesSection.tsx +128 -0
- package/src/dev/showcase/overview.tsx +21 -1163
- package/src/dev/showcase/pagination.tsx +144 -190
- package/src/dev/showcase/popover.tsx +181 -196
- package/src/dev/showcase/progress.tsx +141 -189
- package/src/dev/showcase/radio-group.tsx +272 -332
- package/src/dev/showcase/resizable.tsx +119 -141
- package/src/dev/showcase/scroll-area.tsx +21 -36
- package/src/dev/showcase/select.tsx +262 -322
- package/src/dev/showcase/separator.tsx +75 -73
- package/src/dev/showcase/sheet.tsx +333 -361
- package/src/dev/showcase/sidebar.tsx +53 -59
- package/src/dev/showcase/skeleton.tsx +93 -112
- package/src/dev/showcase/slider.tsx +244 -296
- package/src/dev/showcase/sonner.tsx +251 -258
- package/src/dev/showcase/spinner.tsx +46 -67
- package/src/dev/showcase/switch.tsx +298 -362
- package/src/dev/showcase/table.tsx +76 -80
- package/src/dev/showcase/tabs.tsx +302 -355
- package/src/dev/showcase/textarea.tsx +240 -293
- package/src/dev/showcase/toast.tsx +48 -54
- package/src/dev/showcase/toggle-group.tsx +104 -129
- package/src/dev/showcase/toggle.tsx +82 -102
- package/src/dev/showcase/tooltip.tsx +173 -192
- package/src/dev/showcase/why.tsx +6 -12
- package/src/hooks/use-mobile.test.ts +3 -2
- package/src/lib/utils.test.ts +5 -4
|
@@ -20,68 +20,58 @@ import {
|
|
|
20
20
|
DocsH3,
|
|
21
21
|
DocsP,
|
|
22
22
|
ExampleGrid,
|
|
23
|
-
|
|
23
|
+
ShowcaseExample,
|
|
24
24
|
Showcase,
|
|
25
25
|
ShowcaseDocs
|
|
26
26
|
} from "../../dev/components/showcase";
|
|
27
27
|
import { type Size } from "../../lib/types";
|
|
28
28
|
|
|
29
|
-
// ──────────────────────────────────────────────────────────
|
|
30
|
-
// SECTION 1: Macro Content
|
|
31
|
-
// ──────────────────────────────────────────────────────────
|
|
32
29
|
function TextareaMacroShowcase({ globalSize }: { globalSize: Size }) {
|
|
33
30
|
const [bio, setBio] = useState("");
|
|
34
31
|
const maxLength = 280;
|
|
35
32
|
|
|
36
33
|
return (
|
|
37
|
-
<div className="space-y-10
|
|
34
|
+
<div className="space-y-10">
|
|
38
35
|
<ExampleGrid>
|
|
39
|
-
<
|
|
40
|
-
label="Tiêu chuẩn"
|
|
41
|
-
description="Trường văn bản nhiều dòng với nhãn và mô tả."
|
|
42
|
-
codeString={`<TextareaPreset
|
|
36
|
+
<ShowcaseExample title="Tiêu chuẩn" description="Trường văn bản nhiều dòng với nhãn và mô tả." code={`<TextareaPreset
|
|
43
37
|
label="Phản hồi (Feedback)"
|
|
44
38
|
description="Đóng góp ý kiến của bạn về sản phẩm."
|
|
45
39
|
placeholder="Viết phản hồi..."
|
|
46
40
|
className="w-full"
|
|
47
|
-
/>`}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
41
|
+
/>`} preview={
|
|
42
|
+
<>
|
|
43
|
+
<TextareaPreset
|
|
44
|
+
label="Phản hồi (Feedback)"
|
|
45
|
+
description="Đóng góp ý kiến của bạn về sản phẩm."
|
|
46
|
+
placeholder="Viết phản hồi..."
|
|
47
|
+
size={globalSize}
|
|
48
|
+
className="w-full"
|
|
49
|
+
/>
|
|
50
|
+
</>
|
|
51
|
+
} />
|
|
57
52
|
|
|
58
|
-
<
|
|
59
|
-
label="Lỗi xác thực (Validation Error)"
|
|
60
|
-
description="Hiển thị thông báo lỗi khi đầu vào không hợp lệ."
|
|
61
|
-
codeString={`<TextareaPreset
|
|
53
|
+
<ShowcaseExample title="Lỗi xác thực (Validation Error)" description="Hiển thị thông báo lỗi khi đầu vào không hợp lệ." code={`<TextareaPreset
|
|
62
54
|
label="Khiếu nại"
|
|
63
55
|
placeholder="Mô tả vấn đề..."
|
|
64
56
|
errorMessage="Vui lòng cung cấp ít nhất 20 ký tự để chúng tôi hỗ trợ tốt hơn."
|
|
65
57
|
className="w-full"
|
|
66
58
|
rows={3}
|
|
67
|
-
/>`}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
59
|
+
/>`} preview={
|
|
60
|
+
<>
|
|
61
|
+
<TextareaPreset
|
|
62
|
+
label="Khiếu nại"
|
|
63
|
+
placeholder="Mô tả vấn đề..."
|
|
64
|
+
errorMessage="Vui lòng cung cấp ít nhất 20 ký tự để chúng tôi hỗ trợ tốt hơn."
|
|
65
|
+
size={globalSize}
|
|
66
|
+
className="w-full"
|
|
67
|
+
rows={3}
|
|
68
|
+
/>
|
|
69
|
+
</>
|
|
70
|
+
} />
|
|
78
71
|
</ExampleGrid>
|
|
79
72
|
|
|
80
73
|
<ExampleGrid>
|
|
81
|
-
<
|
|
82
|
-
label="Giới hạn ký tự (Character Count)"
|
|
83
|
-
description="Sử dụng React state và slot description để đếm ngược số ký tự."
|
|
84
|
-
codeString={`const [bio, setBio] = useState(""); const maxLength = 280;
|
|
74
|
+
<ShowcaseExample title="Giới hạn ký tự (Character Count)" description="Sử dụng React state và slot description để đếm ngược số ký tự." code={`const [bio, setBio] = useState(""); const maxLength = 280;
|
|
85
75
|
return (
|
|
86
76
|
<TextareaPreset
|
|
87
77
|
label="Tiểu sử"
|
|
@@ -110,65 +100,60 @@ function TextareaMacroShowcase({ globalSize }: { globalSize: Size }) {
|
|
|
110
100
|
}
|
|
111
101
|
rows={4}
|
|
112
102
|
/>
|
|
113
|
-
);`}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
103
|
+
);`} preview={
|
|
104
|
+
<>
|
|
105
|
+
<TextareaPreset
|
|
106
|
+
label="Tiểu sử"
|
|
107
|
+
description={
|
|
108
|
+
<span className="flex justify-between">
|
|
109
|
+
<span>Mô tả ngắn gọn về bản thân bạn.</span>
|
|
110
|
+
<span
|
|
111
|
+
data-invalid={bio.length > maxLength ? "" : undefined}
|
|
112
|
+
className="data-invalid:text-destructive data-invalid:font-medium"
|
|
113
|
+
>
|
|
114
|
+
{bio.length}/{maxLength}
|
|
115
|
+
</span>
|
|
116
|
+
</span>
|
|
117
|
+
}
|
|
118
|
+
placeholder="I'm a developer who loves..."
|
|
119
|
+
value={bio}
|
|
120
|
+
onChange={(e) => setBio(e.target.value)}
|
|
121
|
+
maxLength={maxLength}
|
|
122
|
+
errorMessage={
|
|
123
|
+
bio.length > maxLength
|
|
124
|
+
? `Vượt quá ${bio.length - maxLength} ký tự.`
|
|
125
|
+
: undefined
|
|
126
|
+
}
|
|
127
|
+
size={globalSize}
|
|
128
|
+
className="w-full"
|
|
129
|
+
rows={4}
|
|
130
|
+
/>
|
|
131
|
+
</>
|
|
132
|
+
} />
|
|
142
133
|
|
|
143
|
-
<
|
|
144
|
-
label="Khóa / Bất hoạt (Disabled)"
|
|
145
|
-
description="Trường văn bản không thể tương tác."
|
|
146
|
-
codeString={`<TextareaPreset
|
|
134
|
+
<ShowcaseExample title="Khóa / Bất hoạt (Disabled)" description="Trường văn bản không thể tương tác." code={`<TextareaPreset
|
|
147
135
|
label="Ghi chú lưu trữ"
|
|
148
136
|
description="Những ghi chú này ở dạng chỉ đọc."
|
|
149
137
|
defaultValue="Dự án này đã hoàn thành vào năm 2023. Không thể thay đổi nội dung."
|
|
150
138
|
disabled
|
|
151
139
|
className="w-full"
|
|
152
140
|
rows={4}
|
|
153
|
-
/>`}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
141
|
+
/>`} preview={
|
|
142
|
+
<>
|
|
143
|
+
<TextareaPreset
|
|
144
|
+
label="Ghi chú lưu trữ"
|
|
145
|
+
description="Những ghi chú này ở dạng chỉ đọc."
|
|
146
|
+
defaultValue="Dự án này đã hoàn thành vào năm 2023. Không thể thay đổi nội dung."
|
|
147
|
+
disabled
|
|
148
|
+
size={globalSize}
|
|
149
|
+
className="w-full"
|
|
150
|
+
rows={4}
|
|
151
|
+
/>
|
|
152
|
+
</>
|
|
153
|
+
} />
|
|
165
154
|
</ExampleGrid>
|
|
166
155
|
|
|
167
|
-
<
|
|
168
|
-
label="Thực tế sử dụng (Real-world Form)"
|
|
169
|
-
description="Bố cục thực tế trong một form hoàn chỉnh."
|
|
170
|
-
fullWidth
|
|
171
|
-
codeString={`<div className="w-full max-w-lg rounded-xl border border-border bg-card p-5 shadow-sm">
|
|
156
|
+
<ShowcaseExample title="Thực tế sử dụng (Real-world Form)" description="Bố cục thực tế trong một form hoàn chỉnh." code={`<div className="w-full max-w-lg rounded-xl border border-border bg-card p-5 shadow-sm">
|
|
172
157
|
<h3 className="mb-4 font-semibold">
|
|
173
158
|
Tạo Ticket Hỗ Trợ
|
|
174
159
|
</h3>
|
|
@@ -179,20 +164,21 @@ function TextareaMacroShowcase({ globalSize }: { globalSize: Size }) {
|
|
|
179
164
|
className="w-full"
|
|
180
165
|
rows={6}
|
|
181
166
|
/>
|
|
182
|
-
</div>`}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
167
|
+
</div>`} preview={
|
|
168
|
+
<>
|
|
169
|
+
<div className="w-full max-w-lg rounded-xl border border-border bg-card p-5 shadow-sm">
|
|
170
|
+
<h3 className="mb-4 font-semibold">Tạo Ticket Hỗ Trợ</h3>
|
|
171
|
+
<TextareaPreset
|
|
172
|
+
label="Mô tả sự cố"
|
|
173
|
+
description="Vui lòng cung cấp chi tiết lỗi, các bước tái hiện và cấu hình môi trường."
|
|
174
|
+
placeholder="Ví dụ: Khi tôi click vào nút Submit, hệ thống báo lỗi 500..."
|
|
175
|
+
size={globalSize}
|
|
176
|
+
className="w-full"
|
|
177
|
+
rows={6}
|
|
178
|
+
/>
|
|
179
|
+
</div>
|
|
180
|
+
</>
|
|
181
|
+
} />
|
|
196
182
|
</div>
|
|
197
183
|
);
|
|
198
184
|
}
|
|
@@ -202,49 +188,42 @@ function TextareaMacroShowcase({ globalSize }: { globalSize: Size }) {
|
|
|
202
188
|
// ──────────────────────────────────────────────────────────
|
|
203
189
|
function TextareaMicroShowcase({ globalSize }: { globalSize: Size }) {
|
|
204
190
|
return (
|
|
205
|
-
<div className="space-y-10
|
|
191
|
+
<div className="space-y-10">
|
|
206
192
|
<ExampleGrid>
|
|
207
|
-
<
|
|
208
|
-
label="Cơ bản (Primitive)"
|
|
209
|
-
description="Khung nhập văn bản nhiều dòng không có nhãn."
|
|
210
|
-
codeString={`<Textarea
|
|
193
|
+
<ShowcaseExample title="Cơ bản (Primitive)" description="Khung nhập văn bản nhiều dòng không có nhãn." code={`<Textarea
|
|
211
194
|
rows={4}
|
|
212
195
|
placeholder="Viết một đoạn văn dài ở đây..."
|
|
213
196
|
className="w-full"
|
|
214
|
-
/>`}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
197
|
+
/>`} preview={
|
|
198
|
+
<>
|
|
199
|
+
<Textarea
|
|
200
|
+
size={globalSize}
|
|
201
|
+
rows={4}
|
|
202
|
+
placeholder="Viết một đoạn văn dài ở đây..."
|
|
203
|
+
className="w-full"
|
|
204
|
+
/>
|
|
205
|
+
</>
|
|
206
|
+
} />
|
|
223
207
|
|
|
224
|
-
<
|
|
225
|
-
label="Auto Resize (CSS content)"
|
|
226
|
-
description="Giãn chiều cao tự động nhờ class field-sizing-content (nếu trình duyệt hỗ trợ)."
|
|
227
|
-
codeString={`<Textarea
|
|
208
|
+
<ShowcaseExample title="Auto Resize (CSS content)" description="Giãn chiều cao tự động nhờ class field-sizing-content (nếu trình duyệt hỗ trợ)." code={`<Textarea
|
|
228
209
|
placeholder="Gõ nhiều dòng để xem nó tự giãn..."
|
|
229
210
|
defaultValue={"Dòng 1\nDòng 2\nDòng 3\nDòng 4"}
|
|
230
211
|
className="w-full"
|
|
231
212
|
/>
|
|
232
|
-
`}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
213
|
+
`} preview={
|
|
214
|
+
<>
|
|
215
|
+
<Textarea
|
|
216
|
+
size={globalSize}
|
|
217
|
+
placeholder="Gõ nhiều dòng để xem nó tự giãn..."
|
|
218
|
+
defaultValue={"Dòng 1\nDòng 2\nDòng 3\nDòng 4"}
|
|
219
|
+
className="w-full"
|
|
220
|
+
/>
|
|
221
|
+
</>
|
|
222
|
+
} />
|
|
241
223
|
</ExampleGrid>
|
|
242
224
|
|
|
243
225
|
<ExampleGrid>
|
|
244
|
-
<
|
|
245
|
-
label="InputGroup + Textarea"
|
|
246
|
-
description="Textarea bên trong InputGroup với Addon. Sử dụng InputGroupTextarea."
|
|
247
|
-
codeString={`<Field className="w-full">
|
|
226
|
+
<ShowcaseExample title="InputGroup + Textarea" description="Textarea bên trong InputGroup với Addon. Sử dụng InputGroupTextarea." code={`<Field className="w-full">
|
|
248
227
|
<FieldLabel htmlFor="tf-group-textarea">
|
|
249
228
|
Bình luận
|
|
250
229
|
</FieldLabel>
|
|
@@ -260,29 +239,27 @@ function TextareaMicroShowcase({ globalSize }: { globalSize: Size }) {
|
|
|
260
239
|
/>
|
|
261
240
|
</InputGroup>
|
|
262
241
|
</FieldContent>
|
|
263
|
-
</Field>`}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
242
|
+
</Field>`} preview={
|
|
243
|
+
<>
|
|
244
|
+
<Field size={globalSize} className="w-full">
|
|
245
|
+
<FieldLabel htmlFor="tf-group-textarea">Bình luận</FieldLabel>
|
|
246
|
+
<FieldContent>
|
|
247
|
+
<InputGroup size={globalSize} className="items-start">
|
|
248
|
+
<InputGroupAddon align="start" className="mt-2">
|
|
249
|
+
<InputGroupText>💬</InputGroupText>
|
|
250
|
+
</InputGroupAddon>
|
|
251
|
+
<InputGroupTextarea
|
|
252
|
+
id="tf-group-textarea"
|
|
253
|
+
rows={3}
|
|
254
|
+
placeholder="Để lại bình luận của bạn..."
|
|
255
|
+
/>
|
|
256
|
+
</InputGroup>
|
|
257
|
+
</FieldContent>
|
|
258
|
+
</Field>
|
|
259
|
+
</>
|
|
260
|
+
} />
|
|
281
261
|
|
|
282
|
-
<
|
|
283
|
-
label="Trạng thái Lỗi thủ công"
|
|
284
|
-
description="Tự gắn aria-invalid vào Textarea và dùng FieldError."
|
|
285
|
-
codeString={`<Field className="w-full">
|
|
262
|
+
<ShowcaseExample title="Trạng thái Lỗi thủ công" description="Tự gắn aria-invalid vào Textarea và dùng FieldError." code={`<Field className="w-full">
|
|
286
263
|
<FieldLabel htmlFor="tf-invalid">
|
|
287
264
|
Mô tả hệ thống
|
|
288
265
|
</FieldLabel>
|
|
@@ -298,31 +275,27 @@ function TextareaMicroShowcase({ globalSize }: { globalSize: Size }) {
|
|
|
298
275
|
<FieldError>
|
|
299
276
|
Mô tả không đạt đủ độ dài tối thiểu.
|
|
300
277
|
</FieldError>
|
|
301
|
-
</Field>`}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
278
|
+
</Field>`} preview={
|
|
279
|
+
<>
|
|
280
|
+
<Field size={globalSize} className="w-full">
|
|
281
|
+
<FieldLabel htmlFor="tf-invalid">Mô tả hệ thống</FieldLabel>
|
|
282
|
+
<FieldContent>
|
|
283
|
+
<Textarea
|
|
284
|
+
id="tf-invalid"
|
|
285
|
+
size={globalSize}
|
|
286
|
+
rows={3}
|
|
287
|
+
aria-invalid
|
|
288
|
+
placeholder="Mô tả..."
|
|
289
|
+
defaultValue="Quá ngắn"
|
|
290
|
+
/>
|
|
291
|
+
</FieldContent>
|
|
292
|
+
<FieldError>Mô tả không đạt đủ độ dài tối thiểu.</FieldError>
|
|
293
|
+
</Field>
|
|
294
|
+
</>
|
|
295
|
+
} />
|
|
318
296
|
</ExampleGrid>
|
|
319
297
|
|
|
320
|
-
<
|
|
321
|
-
label="🧭 Use Case Comparison"
|
|
322
|
-
description="So sánh nhanh khi nào dùng Micro và Macro."
|
|
323
|
-
fullWidth
|
|
324
|
-
codeString={`<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
|
|
325
|
-
{/* Story 1: Macro wins */}
|
|
298
|
+
<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">
|
|
326
299
|
<div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
|
|
327
300
|
<div className="flex items-start gap-3">
|
|
328
301
|
<span className="mt-0.5 shrink-0 rounded-full bg-green-500/10 p-1.5 text-green-600">
|
|
@@ -364,7 +337,6 @@ function TextareaMicroShowcase({ globalSize }: { globalSize: Size }) {
|
|
|
364
337
|
</div>
|
|
365
338
|
</div>
|
|
366
339
|
|
|
367
|
-
{/* Story 2: Micro wins */}
|
|
368
340
|
<div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
|
|
369
341
|
<div className="flex items-start gap-3">
|
|
370
342
|
<span className="mt-0.5 shrink-0 rounded-full bg-blue-500/10 p-1.5 text-blue-600">
|
|
@@ -408,92 +380,93 @@ function TextareaMicroShowcase({ globalSize }: { globalSize: Size }) {
|
|
|
408
380
|
</InputGroup>
|
|
409
381
|
</div>
|
|
410
382
|
</div>
|
|
411
|
-
</div>`}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
383
|
+
</div>`} preview={
|
|
384
|
+
<>
|
|
385
|
+
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
|
|
386
|
+
{/* Story 1: Macro wins */}
|
|
387
|
+
<div className="rounded-xl border border-border bg-card p-5 flex flex-col gap-4">
|
|
388
|
+
<div className="flex items-start gap-3">
|
|
389
|
+
<span className="mt-0.5 shrink-0 rounded-full bg-green-500/10 p-1.5 text-green-600">
|
|
390
|
+
<svg
|
|
391
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
392
|
+
className="size-4"
|
|
393
|
+
viewBox="0 0 24 24"
|
|
394
|
+
fill="none"
|
|
395
|
+
stroke="currentColor"
|
|
396
|
+
strokeWidth="2"
|
|
397
|
+
strokeLinecap="round"
|
|
398
|
+
strokeLinejoin="round"
|
|
399
|
+
aria-hidden="true"
|
|
400
|
+
>
|
|
401
|
+
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
|
|
402
|
+
</svg>
|
|
403
|
+
</span>
|
|
404
|
+
<div>
|
|
405
|
+
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
|
406
|
+
Story 1 · Dùng Macro
|
|
407
|
+
</p>
|
|
408
|
+
<h3 className="mt-0.5 text-sm font-semibold text-foreground">
|
|
409
|
+
Form lấy thông tin thông thường
|
|
410
|
+
</h3>
|
|
411
|
+
</div>
|
|
412
|
+
</div>
|
|
413
|
+
<p className="text-xs text-muted-foreground leading-relaxed">
|
|
414
|
+
Bạn cần ô nhập có tên trường rõ ràng, có gợi ý nhập liệu. Chỉ việc
|
|
415
|
+
truyền props vào <DocsCode>TextareaPreset</DocsCode> là xong.
|
|
416
|
+
</p>
|
|
417
|
+
<div className="rounded-lg bg-muted/50 p-3">
|
|
418
|
+
<TextareaPreset
|
|
419
|
+
size="sm"
|
|
420
|
+
label="Mục tiêu nghề nghiệp"
|
|
421
|
+
description="Tối đa 500 từ."
|
|
422
|
+
className="w-full"
|
|
423
|
+
/>
|
|
424
|
+
</div>
|
|
425
|
+
</div>
|
|
454
426
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
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
|
+
Layout kết hợp Addon đặc thù
|
|
451
|
+
</h3>
|
|
452
|
+
</div>
|
|
453
|
+
</div>
|
|
454
|
+
<p className="text-xs text-muted-foreground leading-relaxed">
|
|
455
|
+
Khi bạn cần nối một icon vào ngay bên cạnh khung textarea giống
|
|
456
|
+
như giao diện chat. Macro không hỗ trợ layout này cho Textarea.
|
|
457
|
+
</p>
|
|
458
|
+
<div className="rounded-lg bg-muted/50 p-3">
|
|
459
|
+
<InputGroup size="sm" className="items-end w-full">
|
|
460
|
+
<InputGroupTextarea rows={2} placeholder="Tin nhắn..." />
|
|
461
|
+
<button className="h-full px-3 shrink-0 rounded-r-md border-l border-input bg-muted/50 text-xs font-semibold text-primary transition-colors hover:bg-muted">
|
|
462
|
+
GỬI
|
|
463
|
+
</button>
|
|
464
|
+
</InputGroup>
|
|
465
|
+
</div>
|
|
466
|
+
</div>
|
|
467
|
+
</div>
|
|
468
|
+
</>
|
|
469
|
+
} />
|
|
497
470
|
</div>
|
|
498
471
|
);
|
|
499
472
|
}
|
|
@@ -507,36 +480,10 @@ export default function TextareaShowcase() {
|
|
|
507
480
|
<Showcase
|
|
508
481
|
title="Textarea"
|
|
509
482
|
description="Trường văn bản nhiều dòng dành cho nội dung dài, phản hồi hoặc mô tả."
|
|
510
|
-
|
|
511
|
-
<div className="space-y-4">
|
|
512
|
-
<ShowcaseDocs>
|
|
513
|
-
<DocsH3>Khi nào nên dùng Macro</DocsH3>
|
|
514
|
-
<DocsP>
|
|
515
|
-
<DocsCode>TextareaPreset</DocsCode> là một component hoàn chỉnh,
|
|
516
|
-
tích hợp sẵn Label, Description và Error Message. Sử dụng nó cho
|
|
517
|
-
đa số các trường hợp để giữ code ngắn gọn và đảm bảo tính nhất
|
|
518
|
-
quán (Accessibility).
|
|
519
|
-
</DocsP>
|
|
520
|
-
</ShowcaseDocs>
|
|
521
|
-
<ShowcaseDocs>
|
|
522
|
-
<DocsH3>Khi nào nên dùng Micro</DocsH3>
|
|
523
|
-
<DocsP>
|
|
524
|
-
<DocsCode>Textarea</DocsCode> chỉ là một ô nhập liệu độc lập. Dùng
|
|
525
|
-
nó khi bạn tự quản lý <DocsCode>Field</DocsCode> thủ công hoặc khi
|
|
526
|
-
chèn Textarea vào bên trong một <DocsCode>InputGroup</DocsCode>.
|
|
527
|
-
</DocsP>
|
|
528
|
-
</ShowcaseDocs>
|
|
529
|
-
</div>
|
|
530
|
-
}
|
|
483
|
+
|
|
531
484
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
label: "Micro (Primitive)",
|
|
535
|
-
content: <TextareaMicroShowcase globalSize={globalSize} /> },
|
|
536
|
-
{
|
|
537
|
-
label: "Macro (Preset)",
|
|
538
|
-
content: <TextareaMacroShowcase globalSize={globalSize} /> },
|
|
539
|
-
]}
|
|
485
|
+
micro={{ content: <TextareaMicroShowcase globalSize={globalSize} /> }}
|
|
486
|
+
macro={{ content: <TextareaMacroShowcase globalSize={globalSize} /> }}
|
|
540
487
|
/>
|
|
541
488
|
);
|
|
542
489
|
}
|