gladvn 0.2.16 → 0.2.18

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 (315) hide show
  1. package/bin/cli.js +9 -6
  2. package/dist/components/macro/accordion-preset.d.ts.map +1 -1
  3. package/dist/components/macro/alert-dialog-preset.d.ts.map +1 -1
  4. package/dist/components/macro/alert-preset.d.ts.map +1 -1
  5. package/dist/components/macro/avatar-preset.d.ts.map +1 -1
  6. package/dist/components/macro/breadcrumb-preset.d.ts.map +1 -1
  7. package/dist/components/macro/card-preset.d.ts.map +1 -1
  8. package/dist/components/macro/carousel-preset.d.ts.map +1 -1
  9. package/dist/components/macro/checkbox-preset.d.ts.map +1 -1
  10. package/dist/components/macro/combobox-preset.d.ts.map +1 -1
  11. package/dist/components/macro/command-preset.d.ts +1 -1
  12. package/dist/components/macro/command-preset.d.ts.map +1 -1
  13. package/dist/components/macro/date-picker.d.ts.map +1 -1
  14. package/dist/components/macro/dialog-preset.d.ts.map +1 -1
  15. package/dist/components/macro/empty-preset.d.ts.map +1 -1
  16. package/dist/components/macro/field-preset.d.ts.map +1 -1
  17. package/dist/components/macro/input-otp-preset.d.ts +6 -0
  18. package/dist/components/macro/input-otp-preset.d.ts.map +1 -1
  19. package/dist/components/macro/input-preset.d.ts +1 -1
  20. package/dist/components/macro/input-preset.d.ts.map +1 -1
  21. package/dist/components/macro/pagination-preset.d.ts.map +1 -1
  22. package/dist/components/macro/progress-preset.d.ts.map +1 -1
  23. package/dist/components/macro/radio-group-preset.d.ts.map +1 -1
  24. package/dist/components/macro/select-preset.d.ts.map +1 -1
  25. package/dist/components/macro/slider-preset.d.ts.map +1 -1
  26. package/dist/components/macro/switch-preset.d.ts.map +1 -1
  27. package/dist/components/macro/tabs-preset.d.ts +1 -1
  28. package/dist/components/macro/tabs-preset.d.ts.map +1 -1
  29. package/dist/components/macro/textarea-preset.d.ts +1 -1
  30. package/dist/components/macro/textarea-preset.d.ts.map +1 -1
  31. package/dist/components/micro/accordion.d.ts +7 -0
  32. package/dist/components/micro/accordion.d.ts.map +1 -1
  33. package/dist/components/micro/alert-dialog.d.ts.map +1 -1
  34. package/dist/components/micro/alert.d.ts +7 -0
  35. package/dist/components/micro/alert.d.ts.map +1 -1
  36. package/dist/components/micro/aspect-ratio.d.ts +7 -0
  37. package/dist/components/micro/aspect-ratio.d.ts.map +1 -1
  38. package/dist/components/micro/avatar.d.ts.map +1 -1
  39. package/dist/components/micro/badge.d.ts +8 -1
  40. package/dist/components/micro/badge.d.ts.map +1 -1
  41. package/dist/components/micro/breadcrumb.d.ts +7 -0
  42. package/dist/components/micro/breadcrumb.d.ts.map +1 -1
  43. package/dist/components/micro/button.d.ts +8 -1
  44. package/dist/components/micro/button.d.ts.map +1 -1
  45. package/dist/components/micro/calendar.d.ts +2 -2
  46. package/dist/components/micro/calendar.d.ts.map +1 -1
  47. package/dist/components/micro/carousel.d.ts.map +1 -1
  48. package/dist/components/micro/chart.d.ts.map +1 -1
  49. package/dist/components/micro/checkbox.d.ts.map +1 -1
  50. package/dist/components/micro/collapsible.d.ts.map +1 -1
  51. package/dist/components/micro/combobox.d.ts.map +1 -1
  52. package/dist/components/micro/command.d.ts.map +1 -1
  53. package/dist/components/micro/context-menu.d.ts.map +1 -1
  54. package/dist/components/micro/dialog.d.ts.map +1 -1
  55. package/dist/components/micro/drawer.d.ts.map +1 -1
  56. package/dist/components/micro/dropdown-menu.d.ts.map +1 -1
  57. package/dist/components/micro/empty.d.ts +7 -0
  58. package/dist/components/micro/empty.d.ts.map +1 -1
  59. package/dist/components/micro/field.d.ts.map +1 -1
  60. package/dist/components/micro/hover-card.d.ts +1 -1
  61. package/dist/components/micro/hover-card.d.ts.map +1 -1
  62. package/dist/components/micro/input-group.d.ts.map +1 -1
  63. package/dist/components/micro/input-otp.d.ts.map +1 -1
  64. package/dist/components/micro/input.d.ts +7 -0
  65. package/dist/components/micro/input.d.ts.map +1 -1
  66. package/dist/components/micro/item.d.ts.map +1 -1
  67. package/dist/components/micro/label.d.ts.map +1 -1
  68. package/dist/components/micro/menubar.d.ts.map +1 -1
  69. package/dist/components/micro/navigation-menu.d.ts +8 -1
  70. package/dist/components/micro/navigation-menu.d.ts.map +1 -1
  71. package/dist/components/micro/pagination.d.ts.map +1 -1
  72. package/dist/components/micro/popover.d.ts.map +1 -1
  73. package/dist/components/micro/progress.d.ts.map +1 -1
  74. package/dist/components/micro/radio-group.d.ts.map +1 -1
  75. package/dist/components/micro/select.d.ts +1 -1
  76. package/dist/components/micro/select.d.ts.map +1 -1
  77. package/dist/components/micro/sheet.d.ts.map +1 -1
  78. package/dist/components/micro/sidebar.d.ts.map +1 -1
  79. package/dist/components/micro/skeleton.d.ts +7 -0
  80. package/dist/components/micro/skeleton.d.ts.map +1 -1
  81. package/dist/components/micro/slider.d.ts +7 -0
  82. package/dist/components/micro/slider.d.ts.map +1 -1
  83. package/dist/components/micro/sonner.d.ts.map +1 -1
  84. package/dist/components/micro/spinner.d.ts.map +1 -1
  85. package/dist/components/micro/switch.d.ts.map +1 -1
  86. package/dist/components/micro/table.d.ts.map +1 -1
  87. package/dist/components/micro/tabs.d.ts +1 -1
  88. package/dist/components/micro/tabs.d.ts.map +1 -1
  89. package/dist/components/micro/textarea.d.ts +7 -0
  90. package/dist/components/micro/textarea.d.ts.map +1 -1
  91. package/dist/components/micro/toggle-group.d.ts.map +1 -1
  92. package/dist/components/micro/toggle.d.ts.map +1 -1
  93. package/dist/components/micro/tooltip.d.ts +1 -1
  94. package/dist/components/micro/tooltip.d.ts.map +1 -1
  95. package/dist/dev/App.d.ts.map +1 -1
  96. package/dist/dev/components/code-highlighter.d.ts.map +1 -1
  97. package/dist/dev/components/dev-context.d.ts.map +1 -1
  98. package/dist/dev/components/showcase.d.ts +1 -1
  99. package/dist/dev/components/showcase.d.ts.map +1 -1
  100. package/dist/dev/data.d.ts.map +1 -1
  101. package/dist/dev/main.d.ts.map +1 -1
  102. package/dist/dev/sections/buttons.d.ts.map +1 -1
  103. package/dist/dev/sections/feedback.d.ts.map +1 -1
  104. package/dist/dev/sections/overview.d.ts.map +1 -1
  105. package/dist/dev/showcase/accordion.d.ts.map +1 -1
  106. package/dist/dev/showcase/alert-dialog.d.ts.map +1 -1
  107. package/dist/dev/showcase/alert.d.ts.map +1 -1
  108. package/dist/dev/showcase/aspect-ratio.d.ts.map +1 -1
  109. package/dist/dev/showcase/avatar.d.ts.map +1 -1
  110. package/dist/dev/showcase/breadcrumb.d.ts.map +1 -1
  111. package/dist/dev/showcase/button.d.ts.map +1 -1
  112. package/dist/dev/showcase/calendar.d.ts.map +1 -1
  113. package/dist/dev/showcase/card.d.ts.map +1 -1
  114. package/dist/dev/showcase/carousel.d.ts.map +1 -1
  115. package/dist/dev/showcase/chart.d.ts.map +1 -1
  116. package/dist/dev/showcase/checkbox.d.ts.map +1 -1
  117. package/dist/dev/showcase/collapsible.d.ts.map +1 -1
  118. package/dist/dev/showcase/combobox.d.ts.map +1 -1
  119. package/dist/dev/showcase/command.d.ts.map +1 -1
  120. package/dist/dev/showcase/context-menu.d.ts.map +1 -1
  121. package/dist/dev/showcase/dialog.d.ts.map +1 -1
  122. package/dist/dev/showcase/drawer.d.ts.map +1 -1
  123. package/dist/dev/showcase/dropdown-menu.d.ts.map +1 -1
  124. package/dist/dev/showcase/empty.d.ts.map +1 -1
  125. package/dist/dev/showcase/hover-card.d.ts.map +1 -1
  126. package/dist/dev/showcase/input-group.d.ts.map +1 -1
  127. package/dist/dev/showcase/input-otp.d.ts.map +1 -1
  128. package/dist/dev/showcase/input.d.ts.map +1 -1
  129. package/dist/dev/showcase/item.d.ts.map +1 -1
  130. package/dist/dev/showcase/kbd.d.ts.map +1 -1
  131. package/dist/dev/showcase/label.d.ts.map +1 -1
  132. package/dist/dev/showcase/menubar.d.ts.map +1 -1
  133. package/dist/dev/showcase/navigation-menu.d.ts.map +1 -1
  134. package/dist/dev/showcase/overview.d.ts.map +1 -1
  135. package/dist/dev/showcase/pagination.d.ts.map +1 -1
  136. package/dist/dev/showcase/popover.d.ts.map +1 -1
  137. package/dist/dev/showcase/progress.d.ts.map +1 -1
  138. package/dist/dev/showcase/radio-group.d.ts.map +1 -1
  139. package/dist/dev/showcase/resizable.d.ts.map +1 -1
  140. package/dist/dev/showcase/scroll-area.d.ts.map +1 -1
  141. package/dist/dev/showcase/select.d.ts.map +1 -1
  142. package/dist/dev/showcase/separator.d.ts.map +1 -1
  143. package/dist/dev/showcase/sheet.d.ts.map +1 -1
  144. package/dist/dev/showcase/sidebar.d.ts.map +1 -1
  145. package/dist/dev/showcase/skeleton.d.ts.map +1 -1
  146. package/dist/dev/showcase/slider.d.ts.map +1 -1
  147. package/dist/dev/showcase/sonner.d.ts.map +1 -1
  148. package/dist/dev/showcase/spinner.d.ts.map +1 -1
  149. package/dist/dev/showcase/switch.d.ts.map +1 -1
  150. package/dist/dev/showcase/table.d.ts.map +1 -1
  151. package/dist/dev/showcase/tabs.d.ts.map +1 -1
  152. package/dist/dev/showcase/textarea.d.ts.map +1 -1
  153. package/dist/dev/showcase/theme-provider.d.ts.map +1 -1
  154. package/dist/dev/showcase/toast.d.ts.map +1 -1
  155. package/dist/dev/showcase/toggle-group.d.ts.map +1 -1
  156. package/dist/dev/showcase/toggle.d.ts.map +1 -1
  157. package/dist/dev/showcase/tooltip.d.ts.map +1 -1
  158. package/dist/index.cjs +2 -2
  159. package/dist/index.cjs.map +1 -1
  160. package/dist/index.js +2 -2
  161. package/dist/index.js.map +1 -1
  162. package/dist/lib/utils.d.ts.map +1 -1
  163. package/package.json +3 -1
  164. package/scripts/format-codestrings.ts +87 -0
  165. package/scripts/organize-imports.ts +21 -0
  166. package/scripts/regex-format.cjs +67 -0
  167. package/scripts/tmp.tsx +25 -0
  168. package/src/components/macro/accordion-preset.test.tsx +1 -0
  169. package/src/components/macro/accordion-preset.tsx +2 -1
  170. package/src/components/macro/alert-dialog-preset.tsx +44 -43
  171. package/src/components/macro/alert-preset.tsx +7 -3
  172. package/src/components/macro/avatar-preset.tsx +2 -1
  173. package/src/components/macro/breadcrumb-preset.tsx +2 -1
  174. package/src/components/macro/card-preset.tsx +2 -1
  175. package/src/components/macro/carousel-preset.tsx +5 -2
  176. package/src/components/macro/checkbox-preset.test.tsx +1 -0
  177. package/src/components/macro/checkbox-preset.tsx +6 -2
  178. package/src/components/macro/combobox-preset.tsx +6 -3
  179. package/src/components/macro/command-preset.tsx +7 -3
  180. package/src/components/macro/date-picker.tsx +77 -59
  181. package/src/components/macro/dialog-preset.tsx +42 -38
  182. package/src/components/macro/empty-preset.tsx +2 -1
  183. package/src/components/macro/field-preset.test.tsx +1 -0
  184. package/src/components/macro/field-preset.tsx +2 -1
  185. package/src/components/macro/input-otp-preset.tsx +6 -2
  186. package/src/components/macro/input-preset.test.tsx +1 -0
  187. package/src/components/macro/input-preset.tsx +4 -2
  188. package/src/components/macro/pagination-preset.tsx +3 -1
  189. package/src/components/macro/progress-preset.test.tsx +1 -0
  190. package/src/components/macro/progress-preset.tsx +2 -1
  191. package/src/components/macro/radio-group-preset.tsx +4 -1
  192. package/src/components/macro/select-preset.tsx +35 -30
  193. package/src/components/macro/slider-preset.test.tsx +1 -0
  194. package/src/components/macro/slider-preset.tsx +4 -1
  195. package/src/components/macro/switch-preset.test.tsx +1 -0
  196. package/src/components/macro/switch-preset.tsx +4 -1
  197. package/src/components/macro/tabs-preset.test.tsx +1 -0
  198. package/src/components/macro/tabs-preset.tsx +4 -2
  199. package/src/components/macro/textarea-preset.test.tsx +1 -0
  200. package/src/components/macro/textarea-preset.tsx +4 -1
  201. package/src/components/micro/accordion.tsx +3 -2
  202. package/src/components/micro/alert-dialog.tsx +2 -1
  203. package/src/components/micro/alert.tsx +3 -2
  204. package/src/components/micro/aspect-ratio.tsx +2 -1
  205. package/src/components/micro/avatar.tsx +2 -1
  206. package/src/components/micro/badge.tsx +3 -3
  207. package/src/components/micro/breadcrumb.tsx +3 -2
  208. package/src/components/micro/button.test.tsx +1 -0
  209. package/src/components/micro/button.tsx +3 -3
  210. package/src/components/micro/calendar.tsx +10 -9
  211. package/src/components/micro/carousel.tsx +3 -2
  212. package/src/components/micro/chart.tsx +1 -0
  213. package/src/components/micro/checkbox.tsx +2 -2
  214. package/src/components/micro/collapsible.tsx +4 -2
  215. package/src/components/micro/combobox.tsx +47 -29
  216. package/src/components/micro/command.tsx +23 -16
  217. package/src/components/micro/context-menu.tsx +3 -2
  218. package/src/components/micro/dialog.tsx +2 -1
  219. package/src/components/micro/drawer.tsx +2 -1
  220. package/src/components/micro/dropdown-menu.tsx +3 -2
  221. package/src/components/micro/empty.tsx +2 -1
  222. package/src/components/micro/field.tsx +4 -3
  223. package/src/components/micro/hover-card.tsx +20 -19
  224. package/src/components/micro/input-group.tsx +5 -4
  225. package/src/components/micro/input-otp.tsx +3 -2
  226. package/src/components/micro/input.tsx +3 -2
  227. package/src/components/micro/item.tsx +1 -0
  228. package/src/components/micro/label.tsx +2 -1
  229. package/src/components/micro/menubar.tsx +2 -1
  230. package/src/components/micro/navigation-menu.tsx +18 -17
  231. package/src/components/micro/pagination.tsx +2 -1
  232. package/src/components/micro/popover.tsx +2 -1
  233. package/src/components/micro/progress.tsx +2 -1
  234. package/src/components/micro/radio-group.tsx +3 -3
  235. package/src/components/micro/select.tsx +5 -4
  236. package/src/components/micro/sheet.tsx +2 -1
  237. package/src/components/micro/sidebar.tsx +4 -1
  238. package/src/components/micro/skeleton.tsx +2 -1
  239. package/src/components/micro/slider.tsx +4 -1
  240. package/src/components/micro/sonner.tsx +2 -1
  241. package/src/components/micro/spinner.tsx +1 -2
  242. package/src/components/micro/switch.tsx +2 -2
  243. package/src/components/micro/table.tsx +2 -1
  244. package/src/components/micro/tabs.tsx +4 -3
  245. package/src/components/micro/textarea.tsx +2 -1
  246. package/src/components/micro/toggle-group.tsx +1 -0
  247. package/src/components/micro/toggle.tsx +1 -3
  248. package/src/components/micro/tooltip.tsx +9 -3
  249. package/src/dev/App.tsx +66 -41
  250. package/src/dev/components/code-highlighter.tsx +2 -1
  251. package/src/dev/components/dev-context.tsx +1 -0
  252. package/src/dev/components/showcase.tsx +13 -14
  253. package/src/dev/data.ts +206 -52
  254. package/src/dev/main.tsx +4 -4
  255. package/src/dev/sections/buttons.tsx +14 -12
  256. package/src/dev/sections/feedback.tsx +7 -2
  257. package/src/dev/sections/forms.tsx +11 -11
  258. package/src/dev/sections/overview.tsx +2 -1
  259. package/src/dev/showcase/accordion.tsx +399 -314
  260. package/src/dev/showcase/alert-dialog.tsx +387 -384
  261. package/src/dev/showcase/alert.tsx +271 -258
  262. package/src/dev/showcase/aspect-ratio.tsx +102 -105
  263. package/src/dev/showcase/avatar.tsx +216 -145
  264. package/src/dev/showcase/badge.tsx +78 -50
  265. package/src/dev/showcase/breadcrumb.tsx +88 -85
  266. package/src/dev/showcase/button.tsx +72 -96
  267. package/src/dev/showcase/calendar.tsx +41 -39
  268. package/src/dev/showcase/card.tsx +170 -148
  269. package/src/dev/showcase/carousel.tsx +239 -77
  270. package/src/dev/showcase/chart.tsx +5 -4
  271. package/src/dev/showcase/checkbox.tsx +206 -140
  272. package/src/dev/showcase/collapsible.tsx +108 -84
  273. package/src/dev/showcase/combobox.tsx +272 -199
  274. package/src/dev/showcase/command.tsx +31 -28
  275. package/src/dev/showcase/context-menu.tsx +94 -77
  276. package/src/dev/showcase/dialog.tsx +445 -424
  277. package/src/dev/showcase/drawer.tsx +142 -135
  278. package/src/dev/showcase/dropdown-menu.tsx +165 -161
  279. package/src/dev/showcase/empty.tsx +173 -158
  280. package/src/dev/showcase/hover-card.tsx +92 -52
  281. package/src/dev/showcase/input-group.tsx +193 -160
  282. package/src/dev/showcase/input-otp.tsx +109 -99
  283. package/src/dev/showcase/input.tsx +78 -42
  284. package/src/dev/showcase/item.tsx +101 -98
  285. package/src/dev/showcase/kbd.tsx +78 -62
  286. package/src/dev/showcase/label.tsx +16 -23
  287. package/src/dev/showcase/menubar.tsx +274 -251
  288. package/src/dev/showcase/navigation-menu.tsx +175 -170
  289. package/src/dev/showcase/overview.tsx +164 -148
  290. package/src/dev/showcase/pagination.tsx +101 -69
  291. package/src/dev/showcase/popover.tsx +113 -86
  292. package/src/dev/showcase/progress.tsx +99 -69
  293. package/src/dev/showcase/radio-group.tsx +217 -134
  294. package/src/dev/showcase/resizable.tsx +65 -55
  295. package/src/dev/showcase/scroll-area.tsx +32 -22
  296. package/src/dev/showcase/select.tsx +192 -136
  297. package/src/dev/showcase/separator.tsx +28 -24
  298. package/src/dev/showcase/sheet.tsx +182 -134
  299. package/src/dev/showcase/sidebar.tsx +9 -5
  300. package/src/dev/showcase/skeleton.tsx +54 -59
  301. package/src/dev/showcase/slider.tsx +158 -129
  302. package/src/dev/showcase/sonner.tsx +3 -5
  303. package/src/dev/showcase/spinner.tsx +22 -18
  304. package/src/dev/showcase/switch.tsx +207 -110
  305. package/src/dev/showcase/table.tsx +44 -32
  306. package/src/dev/showcase/tabs.tsx +272 -267
  307. package/src/dev/showcase/textarea.tsx +162 -116
  308. package/src/dev/showcase/theme-provider.tsx +596 -534
  309. package/src/dev/showcase/toast.tsx +37 -38
  310. package/src/dev/showcase/toggle-group.tsx +87 -39
  311. package/src/dev/showcase/toggle.tsx +36 -27
  312. package/src/dev/showcase/tooltip.tsx +154 -119
  313. package/src/lib/utils.test.ts +1 -0
  314. package/src/lib/utils.ts +1 -1
  315. package/src/styles/gladvn.css +1 -1
@@ -1,13 +1,7 @@
1
- import {
2
- Tooltip,
3
- TooltipContent,
4
- TooltipPortal,
5
- TooltipProvider,
6
- TooltipTrigger,
7
- } from "../../components/micro/tooltip";
8
- import { MoonIcon, SunIcon } from "lucide-react";
9
1
  import { useState } from "react";
10
2
 
3
+ import { MoonIcon, SunIcon } from "lucide-react";
4
+
11
5
  import { Button } from "../../components/micro/button";
12
6
  import {
13
7
  Dialog,
@@ -50,19 +44,23 @@ import {
50
44
  SheetTitle,
51
45
  SheetTrigger,
52
46
  } from "../../components/micro/sheet";
53
-
54
-
55
47
  import {
48
+ type ThemeMode,
56
49
  ThemeProvider,
57
50
  ThemeWrapper,
58
51
  useTheme,
59
- type ThemeMode,
60
52
  } from "../../components/micro/theme-provider";
53
+ import {
54
+ Tooltip,
55
+ TooltipContent,
56
+ TooltipPortal,
57
+ TooltipProvider,
58
+ TooltipTrigger,
59
+ } from "../../components/micro/tooltip";
61
60
  import {
62
61
  DocsCode,
63
62
  DocsH3,
64
63
  DocsP,
65
- ExampleGrid,
66
64
  ExampleSection,
67
65
  SectionHeader,
68
66
  Showcase,
@@ -93,8 +91,12 @@ function ThemeAwareCard({ readOnly }: { readOnly?: boolean } = {}) {
93
91
  variant="ghost"
94
92
  size="sm"
95
93
  iconOnly
96
- aria-label={theme?.mode === "dark" ? "Chuyển sang Light" : "Chuyển sang Dark"}
97
- onClick={() => theme?.setMode(theme.mode === "dark" ? "light" : "dark")}
94
+ aria-label={
95
+ theme?.mode === "dark" ? "Chuyển sang Light" : "Chuyển sang Dark"
96
+ }
97
+ onClick={() =>
98
+ theme?.setMode(theme.mode === "dark" ? "light" : "dark")
99
+ }
98
100
  >
99
101
  {theme?.mode === "dark" ? (
100
102
  <SunIcon aria-hidden="true" />
@@ -223,374 +225,444 @@ function ThemeProviderMicroShowcase() {
223
225
  />
224
226
  </div>
225
227
 
226
- {/* Tooltip */}
227
- <ExampleSection
228
- fullWidth
229
- label="Tooltip"
230
- description="Tooltip được định vị gần trigger và hiển thị khi hover. Không có ThemeWrapper, tooltip của bạn sẽ trắng toát giữa một dark section — dười đây là bằng chứng trực quan."
231
- codeString={`<ThemeProvider defaultMode="dark">
232
- <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
233
- <div className="flex-1 flex flex-col items-center gap-4">
234
- <span className="text-sm font-medium text-muted-foreground">
235
- Không dùng ThemeWrapper
236
- </span>
237
- <TooltipProvider>
238
- <Tooltip>
239
- <TooltipTrigger
240
- render={<Button variant="solid">Hover tôi</Button>}
241
- />
242
- <TooltipPortal>
243
- <TooltipContent
244
- sideOffset={8}
245
- className="bg-card text-card-foreground border border-border shadow-md"
246
- >
247
- Trắng toát! Lạc quẻ với nền đen.
248
- </TooltipContent>
249
- </TooltipPortal>
250
- </Tooltip>
251
- </TooltipProvider>
252
- </div>
253
-
254
- <div className="flex-1 flex flex-col items-center gap-4">
255
- <span className="text-sm font-medium text-muted-foreground">
256
- Có ThemeWrapper
257
- </span>
258
- <TooltipProvider>
259
- <Tooltip>
260
- <TooltipTrigger
261
- render={<Button variant="solid">Hover tôi</Button>}
262
- />
263
- <TooltipPortal>
264
- <ThemeWrapper>
228
+ {/* Tooltip */}
229
+ <ExampleSection
230
+ fullWidth
231
+ label="Tooltip"
232
+ description="Tooltip được định vị gần trigger và hiển thị khi hover. Không có ThemeWrapper, tooltip của bạn sẽ trắng toát giữa một dark section — dười đây là bằng chứng trực quan."
233
+ codeString={`<ThemeProvider defaultMode="dark">
234
+ <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
235
+ <div className="flex-1 flex flex-col items-center gap-4">
236
+ <span className="text-sm font-medium text-muted-foreground">
237
+ Không dùng ThemeWrapper
238
+ </span>
239
+ <TooltipProvider>
240
+ <Tooltip>
241
+ <TooltipTrigger
242
+ render={
243
+ <Button variant="solid">Hover tôi</Button>
244
+ }
245
+ />
246
+ <TooltipPortal>
265
247
  <TooltipContent
266
248
  sideOffset={8}
267
249
  className="bg-card text-card-foreground border border-border shadow-md"
268
250
  >
269
- Màu Tối! Đồng bộ với provider cha.
251
+ Trắng toát! Lạc quẻ với nền đen.
270
252
  </TooltipContent>
271
- </ThemeWrapper>
272
- </TooltipPortal>
273
- </Tooltip>
274
- </TooltipProvider>
253
+ </TooltipPortal>
254
+ </Tooltip>
255
+ </TooltipProvider>
256
+ </div>
257
+
258
+ <div className="flex-1 flex flex-col items-center gap-4">
259
+ <span className="text-sm font-medium text-muted-foreground">
260
+ Có ThemeWrapper
261
+ </span>
262
+ <TooltipProvider>
263
+ <Tooltip>
264
+ <TooltipTrigger
265
+ render={
266
+ <Button variant="solid">Hover tôi</Button>
267
+ }
268
+ />
269
+ <TooltipPortal>
270
+ <ThemeWrapper>
271
+ <TooltipContent
272
+ sideOffset={8}
273
+ className="bg-card text-card-foreground border border-border shadow-md"
274
+ >
275
+ Màu Tối! Đồng bộ với provider cha.
276
+ </TooltipContent>
277
+ </ThemeWrapper>
278
+ </TooltipPortal>
279
+ </Tooltip>
280
+ </TooltipProvider>
281
+ </div>
275
282
  </div>
276
- </div>
277
- </ThemeProvider>`}
278
- >
279
- <ThemeProvider defaultMode="dark">
280
- <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
281
- <div className="flex-1 flex flex-col items-center gap-4">
282
- <span className="text-sm font-medium text-muted-foreground">
283
- Không dùng ThemeWrapper
284
- </span>
285
- <TooltipProvider>
286
- <Tooltip>
287
- <TooltipTrigger
288
- render={<Button variant="solid">Hover tôi</Button>}
289
- />
290
- <TooltipPortal>
283
+ </ThemeProvider>`}
284
+ >
285
+ <ThemeProvider defaultMode="dark">
286
+ <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
287
+ <div className="flex-1 flex flex-col items-center gap-4">
288
+ <span className="text-sm font-medium text-muted-foreground">
289
+ Không dùng ThemeWrapper
290
+ </span>
291
+ <TooltipProvider>
292
+ <Tooltip>
293
+ <TooltipTrigger
294
+ render={<Button variant="solid">Hover tôi</Button>}
295
+ />
296
+ <TooltipPortal>
297
+ <TooltipContent
298
+ sideOffset={8}
299
+ className="bg-card text-card-foreground border border-border shadow-md"
300
+ >
301
+ Trắng toát! Lạc quẻ với nền đen.
302
+ </TooltipContent>
303
+ </TooltipPortal>
304
+ </Tooltip>
305
+ </TooltipProvider>
306
+ </div>
307
+
308
+ <div className="flex-1 flex flex-col items-center gap-4">
309
+ <span className="text-sm font-medium text-muted-foreground">
310
+ Có ThemeWrapper
311
+ </span>
312
+ <TooltipProvider>
313
+ <Tooltip>
314
+ <TooltipTrigger
315
+ render={<Button variant="solid">Hover tôi</Button>}
316
+ />
317
+ <TooltipPortal>
318
+ <ThemeWrapper>
291
319
  <TooltipContent
292
320
  sideOffset={8}
293
321
  className="bg-card text-card-foreground border border-border shadow-md"
294
322
  >
295
- Trắng toát! Lạc quẻ với nền đen.
323
+ Màu Tối! Đồng bộ với provider cha.
296
324
  </TooltipContent>
297
- </TooltipPortal>
298
- </Tooltip>
299
- </TooltipProvider>
300
- </div>
301
-
302
- <div className="flex-1 flex flex-col items-center gap-4">
303
- <span className="text-sm font-medium text-muted-foreground">
304
- Có ThemeWrapper
305
- </span>
306
- <TooltipProvider>
307
- <Tooltip>
308
- <TooltipTrigger
309
- render={<Button variant="solid">Hover tôi</Button>}
310
- />
311
- <TooltipPortal>
312
- <ThemeWrapper>
313
- <TooltipContent
314
- sideOffset={8}
315
- className="bg-card text-card-foreground border border-border shadow-md"
316
- >
317
- Màu Tối! Đồng bộ với provider cha.
318
- </TooltipContent>
319
- </ThemeWrapper>
320
- </TooltipPortal>
321
- </Tooltip>
322
- </TooltipProvider>
323
- </div>
324
- </div>
325
- </ThemeProvider>
326
- </ExampleSection>
327
-
328
- {/* Popover */}
329
- <ExampleSection
330
- fullWidth
331
- label="Popover"
332
- description="Popover chứa content phức tạp và mở khi click. Vì portal hướng tới `document.body`, toàn bộ nền popover lấy CSS variable từ root — sẽ trắng hoàn toàn dù trigger đang nằm trong dark section."
333
- codeString={`<ThemeProvider defaultMode="dark">
334
- <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
335
- <div className="flex-1 flex flex-col items-center gap-4">
336
- <span className="text-sm font-medium text-muted-foreground">
337
- Không dùng ThemeWrapper
338
- </span>
339
- <Popover>
340
- <PopoverTrigger
341
- render={<Button variant="outline">Click Popover</Button>}
342
- />
343
- <PopoverPortal>
344
- <PopoverContent className="w-64">
345
- <div className="space-y-2">
346
- <h4 className="font-medium leading-none">
347
- Nội dung Popover
348
- </h4>
349
- <p className="text-sm text-muted-foreground">
350
- Lỗi: Hiển thị giao diện sáng.
351
- </p>
325
+ </ThemeWrapper>
326
+ </TooltipPortal>
327
+ </Tooltip>
328
+ </TooltipProvider>
352
329
  </div>
353
- </PopoverContent>
354
- </PopoverPortal>
355
- </Popover>
356
- </div>
330
+ </div>
331
+ </ThemeProvider>
332
+ </ExampleSection>
357
333
 
358
- <div className="flex-1 flex flex-col items-center gap-4">
359
- <span className="text-sm font-medium text-muted-foreground">
360
- Có ThemeWrapper
361
- </span>
362
- <Popover>
363
- <PopoverTrigger
364
- render={<Button variant="outline">Click Popover</Button>}
365
- />
366
- <PopoverPortal>
367
- <ThemeWrapper>
334
+ {/* Popover */}
335
+ <ExampleSection
336
+ fullWidth
337
+ label="Popover"
338
+ description="Popover chứa content phức tạp và mở khi click. Vì portal hướng tới `document.body`, toàn bộ nền popover lấy CSS variable từ root — sẽ trắng hoàn toàn dù trigger đang nằm trong dark section."
339
+ codeString={`<ThemeProvider defaultMode="dark">
340
+ <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
341
+ <div className="flex-1 flex flex-col items-center gap-4">
342
+ <span className="text-sm font-medium text-muted-foreground">
343
+ Không dùng ThemeWrapper
344
+ </span>
345
+ <Popover>
346
+ <PopoverTrigger
347
+ render={
348
+ <Button variant="outline">
349
+ Click Popover
350
+ </Button>
351
+ }
352
+ />
353
+ <PopoverPortal>
368
354
  <PopoverContent className="w-64">
369
355
  <div className="space-y-2">
370
356
  <h4 className="font-medium leading-none">
371
357
  Nội dung Popover
372
358
  </h4>
373
359
  <p className="text-sm text-muted-foreground">
374
- Lớp Portal Tunnel đã hoạt động chính xác.
360
+ Lỗi: Hiển thị giao diện sáng.
375
361
  </p>
376
362
  </div>
377
363
  </PopoverContent>
378
- </ThemeWrapper>
379
- </PopoverPortal>
380
- </Popover>
364
+ </PopoverPortal>
365
+ </Popover>
366
+ </div>
367
+
368
+ <div className="flex-1 flex flex-col items-center gap-4">
369
+ <span className="text-sm font-medium text-muted-foreground">
370
+ Có ThemeWrapper
371
+ </span>
372
+ <Popover>
373
+ <PopoverTrigger
374
+ render={
375
+ <Button variant="outline">
376
+ Click Popover
377
+ </Button>
378
+ }
379
+ />
380
+ <PopoverPortal>
381
+ <ThemeWrapper>
382
+ <PopoverContent className="w-64">
383
+ <div className="space-y-2">
384
+ <h4 className="font-medium leading-none">
385
+ Nội dung Popover
386
+ </h4>
387
+ <p className="text-sm text-muted-foreground">
388
+ Lớp Portal Tunnel đã hoạt động chính
389
+ xác.
390
+ </p>
391
+ </div>
392
+ </PopoverContent>
393
+ </ThemeWrapper>
394
+ </PopoverPortal>
395
+ </Popover>
396
+ </div>
381
397
  </div>
382
- </div>
383
- </ThemeProvider>`}
384
- >
385
- <ThemeProvider defaultMode="dark">
386
- <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
387
- <div className="flex-1 flex flex-col items-center gap-4">
388
- <span className="text-sm font-medium text-muted-foreground">
389
- Không dùng ThemeWrapper
390
- </span>
391
- <Popover>
392
- <PopoverTrigger
393
- render={<Button variant="outline">Click Popover</Button>}
394
- />
395
- <PopoverPortal>
398
+ </ThemeProvider>`}
399
+ >
400
+ <ThemeProvider defaultMode="dark">
401
+ <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
402
+ <div className="flex-1 flex flex-col items-center gap-4">
403
+ <span className="text-sm font-medium text-muted-foreground">
404
+ Không dùng ThemeWrapper
405
+ </span>
406
+ <Popover>
407
+ <PopoverTrigger
408
+ render={<Button variant="outline">Click Popover</Button>}
409
+ />
410
+ <PopoverPortal>
411
+ <PopoverContent className="w-64">
412
+ <div className="space-y-2">
413
+ <h4 className="font-medium leading-none">
414
+ Nội dung Popover
415
+ </h4>
416
+ <p className="text-sm text-muted-foreground">
417
+ Lỗi: Hiển thị giao diện sáng.
418
+ </p>
419
+ </div>
420
+ </PopoverContent>
421
+ </PopoverPortal>
422
+ </Popover>
423
+ </div>
424
+
425
+ <div className="flex-1 flex flex-col items-center gap-4">
426
+ <span className="text-sm font-medium text-muted-foreground">
427
+ Có ThemeWrapper
428
+ </span>
429
+ <Popover>
430
+ <PopoverTrigger
431
+ render={<Button variant="outline">Click Popover</Button>}
432
+ />
433
+ <PopoverPortal>
434
+ <ThemeWrapper>
396
435
  <PopoverContent className="w-64">
397
436
  <div className="space-y-2">
398
437
  <h4 className="font-medium leading-none">
399
438
  Nội dung Popover
400
439
  </h4>
401
440
  <p className="text-sm text-muted-foreground">
402
- Lỗi: Hiển thị giao diện sáng.
441
+ Lớp Portal Tunnel đã hoạt động chính xác.
403
442
  </p>
404
443
  </div>
405
444
  </PopoverContent>
406
- </PopoverPortal>
407
- </Popover>
408
- </div>
409
-
410
- <div className="flex-1 flex flex-col items-center gap-4">
411
- <span className="text-sm font-medium text-muted-foreground">
412
- Có ThemeWrapper
413
- </span>
414
- <Popover>
415
- <PopoverTrigger
416
- render={<Button variant="outline">Click Popover</Button>}
417
- />
418
- <PopoverPortal>
419
- <ThemeWrapper>
420
- <PopoverContent className="w-64">
421
- <div className="space-y-2">
422
- <h4 className="font-medium leading-none">
423
- Nội dung Popover
424
- </h4>
425
- <p className="text-sm text-muted-foreground">
426
- Lớp Portal Tunnel đã hoạt động chính xác.
427
- </p>
428
- </div>
429
- </PopoverContent>
430
- </ThemeWrapper>
431
- </PopoverPortal>
432
- </Popover>
433
- </div>
445
+ </ThemeWrapper>
446
+ </PopoverPortal>
447
+ </Popover>
434
448
  </div>
435
- </ThemeProvider>
436
- </ExampleSection>
437
-
438
- {/* Select */}
439
- <ExampleSection
440
- fullWidth
441
- label="Select"
442
- description="SelectContent được render tách biệt hoàn toàn khỏi trigger. Thiếu ThemeWrapper, dropdown option sẽ trắng xuộa trong khi trigger vẫn tối — mù quáng và khó đọc."
443
- codeString={`<ThemeProvider defaultMode="dark">
444
- <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
445
- <div className="flex-1 flex flex-col items-center gap-4">
446
- <span className="text-sm font-medium text-muted-foreground">
447
- Không dùng ThemeWrapper
448
- </span>
449
- <Select items={{ next: "Next.js", vite: "Vite", remix: "Remix" }}>
450
- <SelectTrigger className="w-[140px]">
451
- <SelectValue placeholder="Chọn framework..." />
452
- </SelectTrigger>
453
- <SelectPortal>
454
- <SelectContent>
455
- <SelectItem value="next">Next.js</SelectItem>
456
- <SelectItem value="vite">Vite</SelectItem>
457
- <SelectItem value="remix">Remix</SelectItem>
458
- </SelectContent>
459
- </SelectPortal>
460
- </Select>
461
- </div>
449
+ </div>
450
+ </ThemeProvider>
451
+ </ExampleSection>
462
452
 
463
- <div className="flex-1 flex flex-col items-center gap-4">
464
- <span className="text-sm font-medium text-muted-foreground">
465
- Có ThemeWrapper
466
- </span>
467
- <Select items={{ next: "Next.js", vite: "Vite", remix: "Remix" }}>
468
- <SelectTrigger className="w-[140px]">
469
- <SelectValue placeholder="Chọn framework..." />
470
- </SelectTrigger>
471
- <SelectPortal>
472
- <ThemeWrapper>
453
+ {/* Select */}
454
+ <ExampleSection
455
+ fullWidth
456
+ label="Select"
457
+ description="SelectContent được render tách biệt hoàn toàn khỏi trigger. Thiếu ThemeWrapper, dropdown option sẽ trắng xuộa trong khi trigger vẫn tối — mù quáng và khó đọc."
458
+ codeString={`<ThemeProvider defaultMode="dark">
459
+ <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
460
+ <div className="flex-1 flex flex-col items-center gap-4">
461
+ <span className="text-sm font-medium text-muted-foreground">
462
+ Không dùng ThemeWrapper
463
+ </span>
464
+ <Select
465
+ items={{
466
+ next: "Next.js",
467
+ vite: "Vite",
468
+ remix: "Remix",
469
+ }}
470
+ >
471
+ <SelectTrigger className="w-[140px]">
472
+ <SelectValue placeholder="Chọn framework..." />
473
+ </SelectTrigger>
474
+ <SelectPortal>
473
475
  <SelectContent>
474
476
  <SelectItem value="next">Next.js</SelectItem>
475
477
  <SelectItem value="vite">Vite</SelectItem>
476
478
  <SelectItem value="remix">Remix</SelectItem>
477
479
  </SelectContent>
478
- </ThemeWrapper>
479
- </SelectPortal>
480
- </Select>
481
- </div>
482
- </div>
483
- </ThemeProvider>`}
480
+ </SelectPortal>
481
+ </Select>
482
+ </div>
483
+
484
+ <div className="flex-1 flex flex-col items-center gap-4">
485
+ <span className="text-sm font-medium text-muted-foreground">
486
+ Có ThemeWrapper
487
+ </span>
488
+ <Select
489
+ items={{
490
+ next: "Next.js",
491
+ vite: "Vite",
492
+ remix: "Remix",
493
+ }}
484
494
  >
485
- <ThemeProvider defaultMode="dark">
486
- <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
487
- <div className="flex-1 flex flex-col items-center gap-4">
488
- <span className="text-sm font-medium text-muted-foreground">
489
- Không dùng ThemeWrapper
490
- </span>
491
- <Select items={{ next: "Next.js", vite: "Vite", remix: "Remix" }}>
492
- <SelectTrigger className="w-[140px]">
493
- <SelectValue placeholder="Chọn framework..." />
494
- </SelectTrigger>
495
- <SelectPortal>
495
+ <SelectTrigger className="w-[140px]">
496
+ <SelectValue placeholder="Chọn framework..." />
497
+ </SelectTrigger>
498
+ <SelectPortal>
499
+ <ThemeWrapper>
500
+ <SelectContent>
501
+ <SelectItem value="next">
502
+ Next.js
503
+ </SelectItem>
504
+ <SelectItem value="vite">Vite</SelectItem>
505
+ <SelectItem value="remix">Remix</SelectItem>
506
+ </SelectContent>
507
+ </ThemeWrapper>
508
+ </SelectPortal>
509
+ </Select>
510
+ </div>
511
+ </div>
512
+ </ThemeProvider>`}
513
+ >
514
+ <ThemeProvider defaultMode="dark">
515
+ <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
516
+ <div className="flex-1 flex flex-col items-center gap-4">
517
+ <span className="text-sm font-medium text-muted-foreground">
518
+ Không dùng ThemeWrapper
519
+ </span>
520
+ <Select items={{ next: "Next.js", vite: "Vite", remix: "Remix" }}>
521
+ <SelectTrigger className="w-[140px]">
522
+ <SelectValue placeholder="Chọn framework..." />
523
+ </SelectTrigger>
524
+ <SelectPortal>
525
+ <SelectContent>
526
+ <SelectItem value="next">Next.js</SelectItem>
527
+ <SelectItem value="vite">Vite</SelectItem>
528
+ <SelectItem value="remix">Remix</SelectItem>
529
+ </SelectContent>
530
+ </SelectPortal>
531
+ </Select>
532
+ </div>
533
+
534
+ <div className="flex-1 flex flex-col items-center gap-4">
535
+ <span className="text-sm font-medium text-muted-foreground">
536
+ Có ThemeWrapper
537
+ </span>
538
+ <Select items={{ next: "Next.js", vite: "Vite", remix: "Remix" }}>
539
+ <SelectTrigger className="w-[140px]">
540
+ <SelectValue placeholder="Chọn framework..." />
541
+ </SelectTrigger>
542
+ <SelectPortal>
543
+ <ThemeWrapper>
496
544
  <SelectContent>
497
545
  <SelectItem value="next">Next.js</SelectItem>
498
546
  <SelectItem value="vite">Vite</SelectItem>
499
547
  <SelectItem value="remix">Remix</SelectItem>
500
548
  </SelectContent>
501
- </SelectPortal>
502
- </Select>
503
- </div>
504
-
505
- <div className="flex-1 flex flex-col items-center gap-4">
506
- <span className="text-sm font-medium text-muted-foreground">
507
- Có ThemeWrapper
508
- </span>
509
- <Select items={{ next: "Next.js", vite: "Vite", remix: "Remix" }}>
510
- <SelectTrigger className="w-[140px]">
511
- <SelectValue placeholder="Chọn framework..." />
512
- </SelectTrigger>
513
- <SelectPortal>
514
- <ThemeWrapper>
515
- <SelectContent>
516
- <SelectItem value="next">Next.js</SelectItem>
517
- <SelectItem value="vite">Vite</SelectItem>
518
- <SelectItem value="remix">Remix</SelectItem>
519
- </SelectContent>
520
- </ThemeWrapper>
521
- </SelectPortal>
522
- </Select>
523
- </div>
549
+ </ThemeWrapper>
550
+ </SelectPortal>
551
+ </Select>
524
552
  </div>
525
- </ThemeProvider>
526
- </ExampleSection>
527
-
528
- {/* DropdownMenu */}
529
- <ExampleSection
530
- fullWidth
531
- label="DropdownMenu"
532
- description="DropdownMenu thường dùng cho navigation actions (profile, settings, logout). Khi hover qua từng item, màu highlight cũng lấy từ CSS variable — thiếu ThemeWrapper, cả nền menu lẫn trạng thái hover cùng lúc đều hiển thị sai màu."
533
- codeString={`<ThemeProvider defaultMode="dark">
534
- <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
535
- <div className="flex-1 flex flex-col items-center gap-4">
536
- <span className="text-sm font-medium text-muted-foreground">
537
- Không dùng ThemeWrapper
538
- </span>
539
- <DropdownMenu>
540
- <DropdownMenuTrigger
541
- render={<Button variant="outline">Open Dropdown</Button>}
542
- />
543
- <DropdownMenuPortal>
544
- <DropdownMenuContent className="w-48">
545
- <DropdownMenuGroup>
546
- <DropdownMenuLabel>Tài khoản</DropdownMenuLabel>
547
- <DropdownMenuItem>Trang cá nhân</DropdownMenuItem>
548
- <DropdownMenuItem>Cài đặt</DropdownMenuItem>
549
- </DropdownMenuGroup>
550
- <DropdownMenuSeparator />
551
- <DropdownMenuItem>Đăng xuất</DropdownMenuItem>
552
- </DropdownMenuContent>
553
- </DropdownMenuPortal>
554
- </DropdownMenu>
555
- </div>
553
+ </div>
554
+ </ThemeProvider>
555
+ </ExampleSection>
556
556
 
557
- <div className="flex-1 flex flex-col items-center gap-4">
558
- <span className="text-sm font-medium text-muted-foreground">
559
- Có ThemeWrapper
560
- </span>
561
- <DropdownMenu>
562
- <DropdownMenuTrigger
563
- render={<Button variant="outline">Open Dropdown</Button>}
564
- />
565
- <DropdownMenuPortal>
566
- <ThemeWrapper>
557
+ {/* DropdownMenu */}
558
+ <ExampleSection
559
+ fullWidth
560
+ label="DropdownMenu"
561
+ description="DropdownMenu thường dùng cho navigation actions (profile, settings, logout). Khi hover qua từng item, màu highlight cũng lấy từ CSS variable — thiếu ThemeWrapper, cả nền menu lẫn trạng thái hover cùng lúc đều hiển thị sai màu."
562
+ codeString={`<ThemeProvider defaultMode="dark">
563
+ <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
564
+ <div className="flex-1 flex flex-col items-center gap-4">
565
+ <span className="text-sm font-medium text-muted-foreground">
566
+ Không dùng ThemeWrapper
567
+ </span>
568
+ <DropdownMenu>
569
+ <DropdownMenuTrigger
570
+ render={
571
+ <Button variant="outline">
572
+ Open Dropdown
573
+ </Button>
574
+ }
575
+ />
576
+ <DropdownMenuPortal>
567
577
  <DropdownMenuContent className="w-48">
568
578
  <DropdownMenuGroup>
569
- <DropdownMenuLabel>Tài khoản</DropdownMenuLabel>
570
- <DropdownMenuItem>Trang cá nhân</DropdownMenuItem>
579
+ <DropdownMenuLabel>
580
+ Tài khoản
581
+ </DropdownMenuLabel>
582
+ <DropdownMenuItem>
583
+ Trang cá nhân
584
+ </DropdownMenuItem>
571
585
  <DropdownMenuItem>Cài đặt</DropdownMenuItem>
572
586
  </DropdownMenuGroup>
573
587
  <DropdownMenuSeparator />
574
588
  <DropdownMenuItem>Đăng xuất</DropdownMenuItem>
575
589
  </DropdownMenuContent>
576
- </ThemeWrapper>
577
- </DropdownMenuPortal>
578
- </DropdownMenu>
590
+ </DropdownMenuPortal>
591
+ </DropdownMenu>
592
+ </div>
593
+
594
+ <div className="flex-1 flex flex-col items-center gap-4">
595
+ <span className="text-sm font-medium text-muted-foreground">
596
+ Có ThemeWrapper
597
+ </span>
598
+ <DropdownMenu>
599
+ <DropdownMenuTrigger
600
+ render={
601
+ <Button variant="outline">
602
+ Open Dropdown
603
+ </Button>
604
+ }
605
+ />
606
+ <DropdownMenuPortal>
607
+ <ThemeWrapper>
608
+ <DropdownMenuContent className="w-48">
609
+ <DropdownMenuGroup>
610
+ <DropdownMenuLabel>
611
+ Tài khoản
612
+ </DropdownMenuLabel>
613
+ <DropdownMenuItem>
614
+ Trang cá nhân
615
+ </DropdownMenuItem>
616
+ <DropdownMenuItem>
617
+ Cài đặt
618
+ </DropdownMenuItem>
619
+ </DropdownMenuGroup>
620
+ <DropdownMenuSeparator />
621
+ <DropdownMenuItem>
622
+ Đăng xuất
623
+ </DropdownMenuItem>
624
+ </DropdownMenuContent>
625
+ </ThemeWrapper>
626
+ </DropdownMenuPortal>
627
+ </DropdownMenu>
628
+ </div>
579
629
  </div>
580
- </div>
581
- </ThemeProvider>`}
582
- >
583
- <ThemeProvider defaultMode="dark">
584
- <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
585
- <div className="flex-1 flex flex-col items-center gap-4">
586
- <span className="text-sm font-medium text-muted-foreground">
587
- Không dùng ThemeWrapper
588
- </span>
589
- <DropdownMenu>
590
- <DropdownMenuTrigger
591
- render={<Button variant="outline">Open Dropdown</Button>}
592
- />
593
- <DropdownMenuPortal>
630
+ </ThemeProvider>`}
631
+ >
632
+ <ThemeProvider defaultMode="dark">
633
+ <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
634
+ <div className="flex-1 flex flex-col items-center gap-4">
635
+ <span className="text-sm font-medium text-muted-foreground">
636
+ Không dùng ThemeWrapper
637
+ </span>
638
+ <DropdownMenu>
639
+ <DropdownMenuTrigger
640
+ render={<Button variant="outline">Open Dropdown</Button>}
641
+ />
642
+ <DropdownMenuPortal>
643
+ <DropdownMenuContent className="w-48">
644
+ <DropdownMenuGroup>
645
+ <DropdownMenuLabel>Tài khoản</DropdownMenuLabel>
646
+ <DropdownMenuItem>Trang cá nhân</DropdownMenuItem>
647
+ <DropdownMenuItem>Cài đặt</DropdownMenuItem>
648
+ </DropdownMenuGroup>
649
+ <DropdownMenuSeparator />
650
+ <DropdownMenuItem>Đăng xuất</DropdownMenuItem>
651
+ </DropdownMenuContent>
652
+ </DropdownMenuPortal>
653
+ </DropdownMenu>
654
+ </div>
655
+
656
+ <div className="flex-1 flex flex-col items-center gap-4">
657
+ <span className="text-sm font-medium text-muted-foreground">
658
+ Có ThemeWrapper
659
+ </span>
660
+ <DropdownMenu>
661
+ <DropdownMenuTrigger
662
+ render={<Button variant="outline">Open Dropdown</Button>}
663
+ />
664
+ <DropdownMenuPortal>
665
+ <ThemeWrapper>
594
666
  <DropdownMenuContent className="w-48">
595
667
  <DropdownMenuGroup>
596
668
  <DropdownMenuLabel>Tài khoản</DropdownMenuLabel>
@@ -600,232 +672,222 @@ function ThemeProviderMicroShowcase() {
600
672
  <DropdownMenuSeparator />
601
673
  <DropdownMenuItem>Đăng xuất</DropdownMenuItem>
602
674
  </DropdownMenuContent>
603
- </DropdownMenuPortal>
604
- </DropdownMenu>
605
- </div>
606
-
607
- <div className="flex-1 flex flex-col items-center gap-4">
608
- <span className="text-sm font-medium text-muted-foreground">
609
- Có ThemeWrapper
610
- </span>
611
- <DropdownMenu>
612
- <DropdownMenuTrigger
613
- render={<Button variant="outline">Open Dropdown</Button>}
614
- />
615
- <DropdownMenuPortal>
616
- <ThemeWrapper>
617
- <DropdownMenuContent className="w-48">
618
- <DropdownMenuGroup>
619
- <DropdownMenuLabel>Tài khoản</DropdownMenuLabel>
620
- <DropdownMenuItem>Trang cá nhân</DropdownMenuItem>
621
- <DropdownMenuItem>Cài đặt</DropdownMenuItem>
622
- </DropdownMenuGroup>
623
- <DropdownMenuSeparator />
624
- <DropdownMenuItem>Đăng xuất</DropdownMenuItem>
625
- </DropdownMenuContent>
626
- </ThemeWrapper>
627
- </DropdownMenuPortal>
628
- </DropdownMenu>
629
- </div>
675
+ </ThemeWrapper>
676
+ </DropdownMenuPortal>
677
+ </DropdownMenu>
630
678
  </div>
631
- </ThemeProvider>
632
- </ExampleSection>
633
-
634
- {/* Dialog */}
635
- <ExampleSection
636
- fullWidth
637
- label="Dialog"
638
- description="Dialog là trường hợp phức tạp nhất: portal chứa cả Overlay backdrop lẫn Content panel. Cả hai layer đều cần được bọc trong ThemeWrapper để đảm bảo đồng bộ hoàn toàn."
639
- codeString={`<ThemeProvider defaultMode="dark">
640
- <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
641
- <div className="flex-1 flex flex-col items-center gap-4">
642
- <span className="text-sm font-medium text-muted-foreground">
643
- Không dùng ThemeWrapper
644
- </span>
645
- <Dialog>
646
- <DialogTrigger
647
- render={<Button variant="outline">Open Dialog</Button>}
648
- />
649
- <DialogPortal>
650
- <DialogContent className="sm:max-w-md">
651
- <DialogHeader>
652
- <DialogTitle>Mất Dark Mode!</DialogTitle>
653
- <DialogDescription>
654
- Lỗi: Hiển thị giao diện sáng mặc định.
655
- </DialogDescription>
656
- </DialogHeader>
657
- </DialogContent>
658
- </DialogPortal>
659
- </Dialog>
660
- </div>
679
+ </div>
680
+ </ThemeProvider>
681
+ </ExampleSection>
661
682
 
662
- <div className="flex-1 flex flex-col items-center gap-4">
663
- <span className="text-sm font-medium text-muted-foreground">
664
- Có ThemeWrapper
665
- </span>
666
- <Dialog>
667
- <DialogTrigger
668
- render={<Button variant="outline">Open Dialog</Button>}
669
- />
670
- <DialogPortal>
671
- <ThemeWrapper>
683
+ {/* Dialog */}
684
+ <ExampleSection
685
+ fullWidth
686
+ label="Dialog"
687
+ description="Dialog là trường hợp phức tạp nhất: portal chứa cả Overlay backdrop lẫn Content panel. Cả hai layer đều cần được bọc trong ThemeWrapper để đảm bảo đồng bộ hoàn toàn."
688
+ codeString={`<ThemeProvider defaultMode="dark">
689
+ <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
690
+ <div className="flex-1 flex flex-col items-center gap-4">
691
+ <span className="text-sm font-medium text-muted-foreground">
692
+ Không dùng ThemeWrapper
693
+ </span>
694
+ <Dialog>
695
+ <DialogTrigger
696
+ render={
697
+ <Button variant="outline">Open Dialog</Button>
698
+ }
699
+ />
700
+ <DialogPortal>
672
701
  <DialogContent className="sm:max-w-md">
673
702
  <DialogHeader>
674
- <DialogTitle>Màu tối toàn vẹn</DialogTitle>
703
+ <DialogTitle>Mất Dark Mode!</DialogTitle>
675
704
  <DialogDescription>
676
- Ngay cả khi mở Dialog bọc ngoài toàn bộ màn hình,
677
- Portal Tunnel vẫn bảo vệ được scope Dark Mode.
705
+ Lỗi: Hiển thị giao diện sáng mặc định.
678
706
  </DialogDescription>
679
707
  </DialogHeader>
680
708
  </DialogContent>
681
- </ThemeWrapper>
682
- </DialogPortal>
683
- </Dialog>
709
+ </DialogPortal>
710
+ </Dialog>
711
+ </div>
712
+
713
+ <div className="flex-1 flex flex-col items-center gap-4">
714
+ <span className="text-sm font-medium text-muted-foreground">
715
+ Có ThemeWrapper
716
+ </span>
717
+ <Dialog>
718
+ <DialogTrigger
719
+ render={
720
+ <Button variant="outline">Open Dialog</Button>
721
+ }
722
+ />
723
+ <DialogPortal>
724
+ <ThemeWrapper>
725
+ <DialogContent className="sm:max-w-md">
726
+ <DialogHeader>
727
+ <DialogTitle>
728
+ Màu tối toàn vẹn
729
+ </DialogTitle>
730
+ <DialogDescription>
731
+ Ngay cả khi mở Dialog bọc ngoài toàn bộ
732
+ màn hình, Portal Tunnel vẫn bảo vệ được
733
+ scope Dark Mode.
734
+ </DialogDescription>
735
+ </DialogHeader>
736
+ </DialogContent>
737
+ </ThemeWrapper>
738
+ </DialogPortal>
739
+ </Dialog>
740
+ </div>
684
741
  </div>
685
- </div>
686
- </ThemeProvider>`}
687
- >
688
- <ThemeProvider defaultMode="dark">
689
- <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
690
- <div className="flex-1 flex flex-col items-center gap-4">
691
- <span className="text-sm font-medium text-muted-foreground">
692
- Không dùng ThemeWrapper
693
- </span>
694
- <Dialog>
695
- <DialogTrigger
696
- render={<Button variant="outline">Open Dialog</Button>}
697
- />
698
- <DialogPortal>
742
+ </ThemeProvider>`}
743
+ >
744
+ <ThemeProvider defaultMode="dark">
745
+ <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
746
+ <div className="flex-1 flex flex-col items-center gap-4">
747
+ <span className="text-sm font-medium text-muted-foreground">
748
+ Không dùng ThemeWrapper
749
+ </span>
750
+ <Dialog>
751
+ <DialogTrigger
752
+ render={<Button variant="outline">Open Dialog</Button>}
753
+ />
754
+ <DialogPortal>
755
+ <DialogContent className="sm:max-w-md">
756
+ <DialogHeader>
757
+ <DialogTitle>Mất Dark Mode!</DialogTitle>
758
+ <DialogDescription>
759
+ Lỗi: Hiển thị giao diện sáng mặc định.
760
+ </DialogDescription>
761
+ </DialogHeader>
762
+ </DialogContent>
763
+ </DialogPortal>
764
+ </Dialog>
765
+ </div>
766
+
767
+ <div className="flex-1 flex flex-col items-center gap-4">
768
+ <span className="text-sm font-medium text-muted-foreground">
769
+ Có ThemeWrapper
770
+ </span>
771
+ <Dialog>
772
+ <DialogTrigger
773
+ render={<Button variant="outline">Open Dialog</Button>}
774
+ />
775
+ <DialogPortal>
776
+ <ThemeWrapper>
699
777
  <DialogContent className="sm:max-w-md">
700
778
  <DialogHeader>
701
- <DialogTitle>Mất Dark Mode!</DialogTitle>
779
+ <DialogTitle>Màu tối toàn vẹn</DialogTitle>
702
780
  <DialogDescription>
703
- Lỗi: Hiển thị giao diện sáng mặc định.
781
+ Ngay cả khi mở Dialog bọc ngoài toàn bộ màn hình,
782
+ Portal Tunnel vẫn bảo vệ được scope Dark Mode.
704
783
  </DialogDescription>
705
784
  </DialogHeader>
706
785
  </DialogContent>
707
- </DialogPortal>
708
- </Dialog>
709
- </div>
710
-
711
- <div className="flex-1 flex flex-col items-center gap-4">
712
- <span className="text-sm font-medium text-muted-foreground">
713
- Có ThemeWrapper
714
- </span>
715
- <Dialog>
716
- <DialogTrigger
717
- render={<Button variant="outline">Open Dialog</Button>}
718
- />
719
- <DialogPortal>
720
- <ThemeWrapper>
721
- <DialogContent className="sm:max-w-md">
722
- <DialogHeader>
723
- <DialogTitle>Màu tối toàn vẹn</DialogTitle>
724
- <DialogDescription>
725
- Ngay cả khi mở Dialog bọc ngoài toàn bộ màn hình,
726
- Portal Tunnel vẫn bảo vệ được scope Dark Mode.
727
- </DialogDescription>
728
- </DialogHeader>
729
- </DialogContent>
730
- </ThemeWrapper>
731
- </DialogPortal>
732
- </Dialog>
733
- </div>
786
+ </ThemeWrapper>
787
+ </DialogPortal>
788
+ </Dialog>
734
789
  </div>
735
- </ThemeProvider>
736
- </ExampleSection>
737
-
738
- {/* Sheet */}
739
- <ExampleSection
740
- fullWidth
741
- label="Sheet"
742
- description="Sheet trượt từ cạnh màn hình và phủ một vùng diện tích lớn — lỗi theme dễ nhận biết nhất vì panel thông thường chứa layout phức tạp hơn Popover hay Tooltip."
743
- codeString={`<ThemeProvider defaultMode="dark">
744
- <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
745
- <div className="flex-1 flex flex-col items-center gap-4">
746
- <span className="text-sm font-medium text-muted-foreground">
747
- Không dùng ThemeWrapper
748
- </span>
749
- <Sheet>
750
- <SheetTrigger
751
- render={<Button variant="outline">Open Sheet</Button>}
752
- />
753
- <SheetPortal>
754
- <SheetContent side="right">
755
- <SheetHeader>
756
- <SheetTitle>Mất Dark Mode!</SheetTitle>
757
- </SheetHeader>
758
- </SheetContent>
759
- </SheetPortal>
760
- </Sheet>
761
- </div>
790
+ </div>
791
+ </ThemeProvider>
792
+ </ExampleSection>
762
793
 
763
- <div className="flex-1 flex flex-col items-center gap-4">
764
- <span className="text-sm font-medium text-muted-foreground">
765
- Có ThemeWrapper
766
- </span>
767
- <Sheet>
768
- <SheetTrigger
769
- render={<Button variant="outline">Open Sheet</Button>}
770
- />
771
- <SheetPortal>
772
- <ThemeWrapper>
794
+ {/* Sheet */}
795
+ <ExampleSection
796
+ fullWidth
797
+ label="Sheet"
798
+ description="Sheet trượt từ cạnh màn hình và phủ một vùng diện tích lớn — lỗi theme dễ nhận biết nhất vì panel thông thường chứa layout phức tạp hơn Popover hay Tooltip."
799
+ codeString={`<ThemeProvider defaultMode="dark">
800
+ <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
801
+ <div className="flex-1 flex flex-col items-center gap-4">
802
+ <span className="text-sm font-medium text-muted-foreground">
803
+ Không dùng ThemeWrapper
804
+ </span>
805
+ <Sheet>
806
+ <SheetTrigger
807
+ render={
808
+ <Button variant="outline">Open Sheet</Button>
809
+ }
810
+ />
811
+ <SheetPortal>
773
812
  <SheetContent side="right">
774
813
  <SheetHeader>
775
- <SheetTitle>Sheet Demo</SheetTitle>
814
+ <SheetTitle>Mất Dark Mode!</SheetTitle>
776
815
  </SheetHeader>
777
- <div className="py-4">Màu tối đồng bộ hoàn hảo!</div>
778
816
  </SheetContent>
779
- </ThemeWrapper>
780
- </SheetPortal>
781
- </Sheet>
817
+ </SheetPortal>
818
+ </Sheet>
819
+ </div>
820
+
821
+ <div className="flex-1 flex flex-col items-center gap-4">
822
+ <span className="text-sm font-medium text-muted-foreground">
823
+ Có ThemeWrapper
824
+ </span>
825
+ <Sheet>
826
+ <SheetTrigger
827
+ render={
828
+ <Button variant="outline">Open Sheet</Button>
829
+ }
830
+ />
831
+ <SheetPortal>
832
+ <ThemeWrapper>
833
+ <SheetContent side="right">
834
+ <SheetHeader>
835
+ <SheetTitle>Sheet Demo</SheetTitle>
836
+ </SheetHeader>
837
+ <div className="py-4">
838
+ Màu tối đồng bộ hoàn hảo!
839
+ </div>
840
+ </SheetContent>
841
+ </ThemeWrapper>
842
+ </SheetPortal>
843
+ </Sheet>
844
+ </div>
782
845
  </div>
783
- </div>
784
- </ThemeProvider>`}
785
- >
786
- <ThemeProvider defaultMode="dark">
787
- <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
788
- <div className="flex-1 flex flex-col items-center gap-4">
789
- <span className="text-sm font-medium text-muted-foreground">
790
- Không dùng ThemeWrapper
791
- </span>
792
- <Sheet>
793
- <SheetTrigger
794
- render={<Button variant="outline">Open Sheet</Button>}
795
- />
796
- <SheetPortal>
846
+ </ThemeProvider>`}
847
+ >
848
+ <ThemeProvider defaultMode="dark">
849
+ <div className="w-full flex gap-10 rounded-xl border border-border bg-background p-10">
850
+ <div className="flex-1 flex flex-col items-center gap-4">
851
+ <span className="text-sm font-medium text-muted-foreground">
852
+ Không dùng ThemeWrapper
853
+ </span>
854
+ <Sheet>
855
+ <SheetTrigger
856
+ render={<Button variant="outline">Open Sheet</Button>}
857
+ />
858
+ <SheetPortal>
859
+ <SheetContent side="right">
860
+ <SheetHeader>
861
+ <SheetTitle>Mất Dark Mode!</SheetTitle>
862
+ </SheetHeader>
863
+ </SheetContent>
864
+ </SheetPortal>
865
+ </Sheet>
866
+ </div>
867
+
868
+ <div className="flex-1 flex flex-col items-center gap-4">
869
+ <span className="text-sm font-medium text-muted-foreground">
870
+ Có ThemeWrapper
871
+ </span>
872
+ <Sheet>
873
+ <SheetTrigger
874
+ render={<Button variant="outline">Open Sheet</Button>}
875
+ />
876
+ <SheetPortal>
877
+ <ThemeWrapper>
797
878
  <SheetContent side="right">
798
879
  <SheetHeader>
799
- <SheetTitle>Mất Dark Mode!</SheetTitle>
880
+ <SheetTitle>Sheet Demo</SheetTitle>
800
881
  </SheetHeader>
882
+ <div className="py-4">Màu tối đồng bộ hoàn hảo!</div>
801
883
  </SheetContent>
802
- </SheetPortal>
803
- </Sheet>
804
- </div>
805
-
806
- <div className="flex-1 flex flex-col items-center gap-4">
807
- <span className="text-sm font-medium text-muted-foreground">
808
- Có ThemeWrapper
809
- </span>
810
- <Sheet>
811
- <SheetTrigger
812
- render={<Button variant="outline">Open Sheet</Button>}
813
- />
814
- <SheetPortal>
815
- <ThemeWrapper>
816
- <SheetContent side="right">
817
- <SheetHeader>
818
- <SheetTitle>Sheet Demo</SheetTitle>
819
- </SheetHeader>
820
- <div className="py-4">Màu tối đồng bộ hoàn hảo!</div>
821
- </SheetContent>
822
- </ThemeWrapper>
823
- </SheetPortal>
824
- </Sheet>
825
- </div>
884
+ </ThemeWrapper>
885
+ </SheetPortal>
886
+ </Sheet>
826
887
  </div>
827
- </ThemeProvider>
828
- </ExampleSection>
888
+ </div>
889
+ </ThemeProvider>
890
+ </ExampleSection>
829
891
  </div>
830
892
  );
831
893
  }
@@ -845,8 +907,8 @@ export default function ThemeProviderShowcase() {
845
907
  <DocsCode>ThemeProvider</DocsCode> bọc children trong một{" "}
846
908
  <DocsCode>{"div[display:contents]"}</DocsCode> và gắn class{" "}
847
909
  <DocsCode>light</DocsCode> hoặc <DocsCode>dark</DocsCode> lên đó,
848
- kích hoạt CSS variable cascade mà không ảnh hưởng layout. Hỗ trợ
849
- hai chế độ: <strong>Uncontrolled</strong> (truyền{" "}
910
+ kích hoạt CSS variable cascade mà không ảnh hưởng layout. Hỗ trợ hai
911
+ chế độ: <strong>Uncontrolled</strong> (truyền{" "}
850
912
  <DocsCode>defaultMode</DocsCode> — tự quản lý state) và{" "}
851
913
  <strong>Controlled</strong> (truyền <DocsCode>mode</DocsCode> +{" "}
852
914
  <DocsCode>onModeChange</DocsCode> — state do component cha sở hữu).
@@ -859,8 +921,8 @@ export default function ThemeProviderShowcase() {
859
921
  React component tree. Khi một component render qua Portal (ra{" "}
860
922
  <DocsCode>document.body</DocsCode>), nó thoát khỏi hoàn toàn chuỗi
861
923
  DOM ancestry — không còn tổ tiên nào mang class{" "}
862
- <DocsCode>.dark</DocsCode>, và mọi CSS variable rơi thẳng về giá
863
- trị <DocsCode>:root</DocsCode> (thường là light).
924
+ <DocsCode>.dark</DocsCode>, và mọi CSS variable rơi thẳng về giá trị{" "}
925
+ <DocsCode>:root</DocsCode> (thường là light).
864
926
  </DocsP>
865
927
  <DocsP>
866
928
  <DocsCode>ThemeWrapper</DocsCode> giải quyết vấn đề này bằng cách
@@ -875,10 +937,10 @@ export default function ThemeProviderShowcase() {
875
937
  runtime warning, nhưng UI sẽ hiển thị sai màu âm thầm.
876
938
  </DocsP>
877
939
  <DocsP>
878
- Trách nhiệm đặt <DocsCode>ThemeWrapper</DocsCode> không thể
879
- delegate tuỳ tiện: Micro component không được tự ôm nó bên trong
880
- (vi phạm nguyên tắc pure composition). Tầng nào kiểm soát Portal —
881
- Macro component hoặc consumer trực tiếp — tầng đó phải tự đặt{" "}
940
+ Trách nhiệm đặt <DocsCode>ThemeWrapper</DocsCode> không thể delegate
941
+ tuỳ tiện: Micro component không được tự ôm nó bên trong (vi phạm
942
+ nguyên tắc pure composition). Tầng nào kiểm soát Portal — Macro
943
+ component hoặc consumer trực tiếp — tầng đó phải tự đặt{" "}
882
944
  <DocsCode>ThemeWrapper</DocsCode> ngay sau Portal boundary.
883
945
  </DocsP>
884
946
  </ShowcaseDocs>