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
@@ -6,12 +6,11 @@ import {
6
6
  DocsCode,
7
7
  DocsP,
8
8
  ExampleGrid,
9
- ExampleSection,
9
+ ShowcaseExample,
10
10
  Showcase,
11
11
  ShowcaseDocs
12
12
  } from "../../dev/components/showcase";
13
13
 
14
- // Simulated async operation for Promise demo
15
14
  const mockSave = () =>
16
15
  new Promise<{ name: string }>((resolve) =>
17
16
  setTimeout(() => resolve({ name: "Sonner" }), 1500),
@@ -22,120 +21,114 @@ const mockFail = () =>
22
21
  setTimeout(() => reject(new Error("Server error")), 1500),
23
22
  );
24
23
 
25
- // ──────────────────────────────────────────────────────────
26
- // SECTION 2: Micro Content (không export)
27
- // ──────────────────────────────────────────────────────────
28
24
  function SonnerMicroShowcase() {
29
25
  return (
30
- <div className="space-y-10 mt-6">
31
- {/* Toaster phải mount ở đây để toast() hoạt động trong showcase */}
26
+ <div className="space-y-10">
27
+
32
28
  <Toaster position="bottom-right" />
33
- {/* ── Toast Types ── */}
34
- <ExampleSection
35
- label="Loại Toast"
36
- description="Năm loại toast cơ bản: default, success, error, warning, info."
37
- codeString={`import { toast } from "sonner";
29
+
30
+ <ShowcaseExample title="Loại Toast" description="Năm loại toast cơ bản: default, success, error, warning, info." code={`import { toast } from "sonner";
38
31
 
39
32
  // Default
40
- toast("Event has been created", {
41
- description: "Sunday, December 03, 2023 at 9:00 AM",
42
- action: { label: "Undo", onClick: () => console.log("Undo") } });
33
+ toast("Sự kiện đã được tạo", {
34
+ description: "Chủ nhật, ngày 03 tháng 12 năm 2023 lúc 9:00 sáng",
35
+ action: { label: "Hoàn tác", onClick: () => console.log("Hoàn tác") } });
43
36
 
44
37
  // Typed variants
45
38
  toast.success("Successfully saved!");
46
39
  toast.error("An error occurred.");
47
40
  toast.warning("Connection is unstable.");
48
- toast.info("Update is available.");`}
49
- >
50
- <div className="flex flex-wrap gap-2">
51
- <Button
52
- variant="outline"
53
- onClick={() =>
54
- toast("Event has been created", {
55
- description: "Sunday, December 03, 2023 at 9:00 AM",
56
- action: { label: "Undo", onClick: () => console.log("Undo") } })
57
- }
58
- >
59
- Default
60
- </Button>
61
- <Button
62
- variant="outline"
63
- color="success"
64
- onClick={() => toast.success("Successfully saved!")}
65
- >
66
- Success
67
- </Button>
68
- <Button
69
- variant="outline"
70
- color="destructive"
71
- onClick={() => toast.error("An error occurred.")}
72
- >
73
- Error
74
- </Button>
75
- <Button
76
- variant="outline"
77
- color="warning"
78
- onClick={() => toast.warning("Connection is unstable.")}
79
- >
80
- Warning
81
- </Button>
82
- <Button
83
- variant="outline"
84
- color="info"
85
- onClick={() => toast.info("Update is available.")}
86
- >
87
- Info
88
- </Button>
89
- </div>
90
- </ExampleSection>
41
+ toast.info("Update is available.");`} preview={
42
+ <>
43
+ <div className="flex flex-wrap gap-2">
44
+ <Button
45
+ variant="outline"
46
+ onClick={() =>
47
+ toast("Sự kiện đã được tạo", {
48
+ description: "Chủ nhật, ngày 03 tháng 12 năm 2023 lúc 9:00 sáng",
49
+ action: { label: "Hoàn tác", onClick: () => console.log("Hoàn tác") }
50
+ })
51
+ }
52
+ >
53
+ Default
54
+ </Button>
55
+ <Button
56
+ variant="outline"
57
+ color="success"
58
+ onClick={() => toast.success("Successfully saved!")}
59
+ >
60
+ Success
61
+ </Button>
62
+ <Button
63
+ variant="outline"
64
+ color="destructive"
65
+ onClick={() => toast.error("An error occurred.")}
66
+ >
67
+ Error
68
+ </Button>
69
+ <Button
70
+ variant="outline"
71
+ color="warning"
72
+ onClick={() => toast.warning("Connection is unstable.")}
73
+ >
74
+ Warning
75
+ </Button>
76
+ <Button
77
+ variant="outline"
78
+ color="info"
79
+ onClick={() => toast.info("Update is available.")}
80
+ >
81
+ Info
82
+ </Button>
83
+ </div>
84
+ </>
85
+ } />
91
86
 
92
- {/* ── Mô tả & Action ── */}
93
- <ExampleSection
94
- label="Mô tả & Action Button"
95
- description="Toast kèm description phụ và action button — pattern phổ biến cho undo/redo, navigation."
96
- codeString={`toast("File deleted", {
87
+ <ShowcaseExample title="Mô tả & Action Button" description="Toast kèm description phụ và action button — pattern phổ biến cho undo/redo, navigation." code={`toast("File deleted", {
97
88
  description: "draft-v2.docx has been moved to trash.",
98
89
  action: {
99
- label: "Undo",
90
+ label: "Hoàn tác",
100
91
  onClick: () => console.log("Undo delete") },
101
92
  cancel: {
102
93
  label: "Dismiss",
103
- onClick: () => {} } });`}
104
- >
105
- <div className="flex flex-wrap gap-2">
106
- <Button
107
- variant="outline"
108
- onClick={() =>
109
- toast("File deleted", {
110
- description: "draft-v2.docx has been moved to trash.",
111
- action: {
112
- label: "Undo",
113
- onClick: () => console.log("Undo delete") },
114
- cancel: {
115
- label: "Dismiss",
116
- onClick: () => {} } })
117
- }
118
- >
119
- File Deleted (with Action)
120
- </Button>
121
- <Button
122
- variant="outline"
123
- onClick={() =>
124
- toast.success("Profile updated", {
125
- description: "Your changes have been saved successfully." })
126
- }
127
- >
128
- Success with Description
129
- </Button>
130
- </div>
131
- </ExampleSection>
94
+ onClick: () => {} } });`} preview={
95
+ <>
96
+ <div className="flex flex-wrap gap-2">
97
+ <Button
98
+ variant="outline"
99
+ onClick={() =>
100
+ toast("File deleted", {
101
+ description: "draft-v2.docx has been moved to trash.",
102
+ action: {
103
+ label: "Hoàn tác",
104
+ onClick: () => console.log("Undo delete")
105
+ },
106
+ cancel: {
107
+ label: "Dismiss",
108
+ onClick: () => { }
109
+ }
110
+ })
111
+ }
112
+ >
113
+ File Deleted (with Action)
114
+ </Button>
115
+ <Button
116
+ variant="outline"
117
+ onClick={() =>
118
+ toast.success("Profile updated", {
119
+ description: "Your changes have been saved successfully."
120
+ })
121
+ }
122
+ >
123
+ Success with Description
124
+ </Button>
125
+ </div>
126
+ </>
127
+ } />
132
128
 
133
- {/* ── Promise ── */}
129
+ { }
134
130
  <ExampleGrid>
135
- <ExampleSection
136
- label="Promise — Thành công"
137
- description="toast.promise() tự quản lý trạng thái loading → success/error theo kết quả của Promise."
138
- codeString={`const saveData = () =>
131
+ <ShowcaseExample title="Promise — Thành công" description="toast.promise() tự quản lý trạng thái loading → success/error theo kết quả của Promise." code={`const saveData = () =>
139
132
  new Promise<{ name: string }>((resolve) =>
140
133
  setTimeout(() => resolve({ name: "Sonner" }), 1500),
141
134
  );
@@ -143,25 +136,24 @@ toast.info("Update is available.");`}
143
136
  toast.promise(saveData(), {
144
137
  loading: "Đang lưu...",
145
138
  success: (data) => \`Đã lưu \${data.name} thành công!\`,
146
- error: "Lưu thất bại!" });`}
147
- >
148
- <Button
149
- variant="outline"
150
- onClick={() =>
151
- toast.promise(mockSave(), {
152
- loading: "Đang lưu...",
153
- success: (data) => `Đã lưu ${data.name} thành công!`,
154
- error: "Lưu thất bại!" })
155
- }
156
- >
157
- Promise (Success)
158
- </Button>
159
- </ExampleSection>
139
+ error: "Lưu thất bại!" });`} preview={
140
+ <>
141
+ <Button
142
+ variant="outline"
143
+ onClick={() =>
144
+ toast.promise(mockSave(), {
145
+ loading: "Đang lưu...",
146
+ success: (data) => `Đã lưu ${data.name} thành công!`,
147
+ error: "Lưu thất bại!"
148
+ })
149
+ }
150
+ >
151
+ Promise (Success)
152
+ </Button>
153
+ </>
154
+ } />
160
155
 
161
- <ExampleSection
162
- label="Promise — Thất bại"
163
- description="Promise bị reject sẽ tự chuyển sang trạng thái error toast."
164
- codeString={`const failRequest = () =>
156
+ <ShowcaseExample title="Promise — Thất bại" description="Promise bị reject sẽ tự chuyển sang trạng thái error toast." code={`const failRequest = () =>
165
157
  new Promise<void>((_, reject) =>
166
158
  setTimeout(() => reject(new Error("Server error")), 1500),
167
159
  );
@@ -169,157 +161,158 @@ toast.promise(saveData(), {
169
161
  toast.promise(failRequest(), {
170
162
  loading: "Đang gửi yêu cầu...",
171
163
  success: "Yêu cầu thành công!",
172
- error: "Yêu cầu thất bại!" });`}
173
- >
174
- <Button
175
- variant="outline"
176
- color="destructive"
177
- onClick={() =>
178
- toast.promise(mockFail(), {
179
- loading: "Đang gửi yêu cầu...",
180
- success: "Yêu cầu thành công!",
181
- error: "Yêu cầu thất bại!" })
182
- }
183
- >
184
- Promise (Error)
185
- </Button>
186
- </ExampleSection>
164
+ error: "Yêu cầu thất bại!" });`} preview={
165
+ <>
166
+ <Button
167
+ variant="outline"
168
+ color="destructive"
169
+ onClick={() =>
170
+ toast.promise(mockFail(), {
171
+ loading: "Đang gửi yêu cầu...",
172
+ success: "Yêu cầu thành công!",
173
+ error: "Yêu cầu thất bại!"
174
+ })
175
+ }
176
+ >
177
+ Promise (Error)
178
+ </Button>
179
+ </>
180
+ } />
187
181
  </ExampleGrid>
188
182
 
189
183
  {/* ── Loading & Dismiss ── */}
190
- <ExampleSection
191
- label="Loading & Dismiss"
192
- description="toast.loading() tạo toast thủ công, sau đó dùng toast.success/error(id) để cập nhật, hoặc toast.dismiss(id) để huỷ."
193
- codeString={`// Tạo loading toast và giữ id
184
+ <ShowcaseExample title="Loading & Dismiss" description="toast.loading() tạo toast thủ công, sau đó dùng toast.success/error(id) để cập nhật, hoặc toast.dismiss(id) để huỷ." code={`
194
185
  const toastId = toast.loading("Đang xử lý...");
195
186
 
196
- // Sau khi async xong — cập nhật cùng toast
197
187
  setTimeout(() => {
198
188
  toast.success("Hoàn tất!", { id: toastId });
199
189
  }, 2000);
200
190
 
201
- // Hoặc huỷ thủ công
202
- toast.dismiss(toastId);`}
203
- >
204
- <div className="flex flex-wrap gap-2">
205
- <Button
206
- variant="outline"
207
- onClick={() => {
208
- const id = toast.loading("Đang xử lý...");
209
- setTimeout(() => toast.success("Hoàn tất!", { id }), 2000);
210
- }}
211
- >
212
- Loading → Success (2s)
213
- </Button>
214
- <Button
215
- variant="outline"
216
- onClick={() => {
217
- const id = toast.loading("Đang tải dữ liệu...");
218
- setTimeout(() => toast.error("Mất kết nối!", { id }), 2000);
219
- }}
220
- >
221
- Loading → Error (2s)
222
- </Button>
223
- <Button
224
- variant="outline"
225
- color="destructive"
226
- onClick={() => toast.dismiss()}
227
- >
228
- Dismiss All
229
- </Button>
230
- </div>
231
- </ExampleSection>
191
+ toast.dismiss(toastId);`} preview={
192
+ <>
193
+ <div className="flex flex-wrap gap-2">
194
+ <Button
195
+ variant="outline"
196
+ onClick={() => {
197
+ const id = toast.loading("Đang xử lý...");
198
+ setTimeout(() => toast.success("Hoàn tất!", { id }), 2000);
199
+ }}
200
+ >
201
+ Loading → Success (2s)
202
+ </Button>
203
+ <Button
204
+ variant="outline"
205
+ onClick={() => {
206
+ const id = toast.loading("Đang tải dữ liệu...");
207
+ setTimeout(() => toast.error("Mất kết nối!", { id }), 2000);
208
+ }}
209
+ >
210
+ Loading → Error (2s)
211
+ </Button>
212
+ <Button
213
+ variant="outline"
214
+ color="destructive"
215
+ onClick={() => toast.dismiss()}
216
+ >
217
+ Dismiss All
218
+ </Button>
219
+ </div>
220
+ </>
221
+ } />
232
222
 
233
223
  {/* ── Position ── */}
234
- <ExampleSection
235
- label="Position"
236
- description="Toaster nhận prop position để xác định vị trí hiển thị — cấu hình một lần ở root layout. Nhấn vào từng vùng để xem toast xuất hiện ở đâu."
237
- codeString={`// Trong root layout (app/layout.tsx):
238
- <Toaster position="bottom-right" /> // mặc định // Các vị
239
- trí hỗ trợ: // "top-left" | "top-center" | "top-right" //
240
- "bottom-left" | "bottom-center" | "bottom-right"`}
241
- >
242
- {/* Visual 3×2 position grid */}
243
- <div className="w-full max-w-sm">
244
- <p className="mb-3 text-xs text-muted-foreground">
245
- Nhấn từng ô để xem toast xuất hiện đúng vị trí tương ứng.
246
- </p>
247
- <div className="grid grid-cols-3 gap-1.5">
248
- <Button
249
- variant="outline"
250
- size="sm"
251
- className="text-xs"
252
- onClick={() =>
253
- toast("Toast: top-left", {
254
- description: 'position="top-left"',
255
- position: "top-left" })
256
- }
257
- >
258
- top-left
259
- </Button>
260
- <Button
261
- variant="outline"
262
- size="sm"
263
- className="text-xs"
264
- onClick={() =>
265
- toast("Toast: top-center", {
266
- description: 'position="top-center"',
267
- position: "top-center" })
268
- }
269
- >
270
- top-center
271
- </Button>
272
- <Button
273
- variant="outline"
274
- size="sm"
275
- className="text-xs"
276
- onClick={() =>
277
- toast("Toast: top-right", {
278
- description: 'position="top-right"',
279
- position: "top-right" })
280
- }
281
- >
282
- top-right
283
- </Button>
284
- <Button
285
- variant="outline"
286
- size="sm"
287
- className="text-xs"
288
- onClick={() =>
289
- toast("Toast: bottom-left", {
290
- description: 'position="bottom-left"',
291
- position: "bottom-left" })
292
- }
293
- >
294
- bottom-left
295
- </Button>
296
- <Button
297
- variant="outline"
298
- size="sm"
299
- className="text-xs"
300
- onClick={() =>
301
- toast("Toast: bottom-center", {
302
- description: 'position="bottom-center"',
303
- position: "bottom-center" })
304
- }
305
- >
306
- bottom-center
307
- </Button>
308
- <Button
309
- variant="outline"
310
- size="sm"
311
- className="text-xs"
312
- onClick={() =>
313
- toast("Toast: bottom-right", {
314
- description: 'position="bottom-right"',
315
- position: "bottom-right" })
316
- }
317
- >
318
- bottom-right
319
- </Button>
320
- </div>
321
- </div>
322
- </ExampleSection>
224
+ <ShowcaseExample title="Position" description="Toaster nhận prop position để xác định vị trí hiển thị — cấu hình một lần ở root layout. Nhấn vào từng vùng để xem toast xuất hiện ở đâu." code={`
225
+ <Toaster position="bottom-right" />
226
+ trí hỗ trợ:
227
+ "bottom-left" | "bottom-center" | "bottom-right"`} preview={
228
+ <>
229
+ {/* Visual 3×2 position grid */}<div className="w-full max-w-sm">
230
+ <p className="mb-3 text-xs text-muted-foreground">
231
+ Nhấn từng ô để xem toast xuất hiện đúng vị trí tương ứng.
232
+ </p>
233
+ <div className="grid grid-cols-3 gap-1.5">
234
+ <Button
235
+ variant="outline"
236
+ size="sm"
237
+ className="text-xs"
238
+ onClick={() =>
239
+ toast("Toast: top-left", {
240
+ description: 'position="top-left"',
241
+ position: "top-left"
242
+ })
243
+ }
244
+ >
245
+ top-left
246
+ </Button>
247
+ <Button
248
+ variant="outline"
249
+ size="sm"
250
+ className="text-xs"
251
+ onClick={() =>
252
+ toast("Toast: top-center", {
253
+ description: 'position="top-center"',
254
+ position: "top-center"
255
+ })
256
+ }
257
+ >
258
+ top-center
259
+ </Button>
260
+ <Button
261
+ variant="outline"
262
+ size="sm"
263
+ className="text-xs"
264
+ onClick={() =>
265
+ toast("Toast: top-right", {
266
+ description: 'position="top-right"',
267
+ position: "top-right"
268
+ })
269
+ }
270
+ >
271
+ top-right
272
+ </Button>
273
+ <Button
274
+ variant="outline"
275
+ size="sm"
276
+ className="text-xs"
277
+ onClick={() =>
278
+ toast("Toast: bottom-left", {
279
+ description: 'position="bottom-left"',
280
+ position: "bottom-left"
281
+ })
282
+ }
283
+ >
284
+ bottom-left
285
+ </Button>
286
+ <Button
287
+ variant="outline"
288
+ size="sm"
289
+ className="text-xs"
290
+ onClick={() =>
291
+ toast("Toast: bottom-center", {
292
+ description: 'position="bottom-center"',
293
+ position: "bottom-center"
294
+ })
295
+ }
296
+ >
297
+ bottom-center
298
+ </Button>
299
+ <Button
300
+ variant="outline"
301
+ size="sm"
302
+ className="text-xs"
303
+ onClick={() =>
304
+ toast("Toast: bottom-right", {
305
+ description: 'position="bottom-right"',
306
+ position: "bottom-right"
307
+ })
308
+ }
309
+ >
310
+ bottom-right
311
+ </Button>
312
+ </div>
313
+ </div>
314
+ </>
315
+ } />
323
316
  </div>
324
317
  );
325
318
  }
@@ -332,7 +325,7 @@ export default function SonnerShowcase() {
332
325
  <Showcase
333
326
  title="Sonner"
334
327
  description="Hệ thống thông báo toast nhẹ, đẹp, và linh hoạt — tích hợp với design system qua CSS Variables."
335
- generalConcept={
328
+ guideline={
336
329
  <ShowcaseDocs>
337
330
  <DocsP>
338
331
  <DocsCode>Toaster</DocsCode> là wrapper của thư viện{" "}
@@ -349,7 +342,7 @@ export default function SonnerShowcase() {
349
342
  </DocsP>
350
343
  </ShowcaseDocs>
351
344
  }
352
- tabs={[{ label: "Micro (Primitive)", content: <SonnerMicroShowcase /> }]}
345
+ micro={{ content: <SonnerMicroShowcase /> }}
353
346
  />
354
347
  );
355
348
  }