@comitor/ui 2.1.0 → 3.0.1

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 (405) hide show
  1. package/README.md +63 -24
  2. package/dist/chart/chart.d.ts +6 -1
  3. package/dist/chart/chart.js +3 -1
  4. package/dist/chart/chart.js.map +1 -1
  5. package/dist/chart/comitor-chart.d.ts +4 -1
  6. package/dist/chart/comitor-chart.js +3 -1
  7. package/dist/chart/comitor-chart.js.map +1 -1
  8. package/dist/components/composite/avatar-group.d.ts +9 -6
  9. package/dist/components/composite/avatar-group.js +6 -2
  10. package/dist/components/composite/avatar-group.js.map +1 -1
  11. package/dist/components/composite/combobox.d.ts +11 -11
  12. package/dist/components/composite/combobox.js +25 -11
  13. package/dist/components/composite/combobox.js.map +1 -1
  14. package/dist/components/composite/command-palette-constants.d.ts +15 -5
  15. package/dist/components/composite/command-palette-constants.js +3 -2
  16. package/dist/components/composite/command-palette-constants.js.map +1 -1
  17. package/dist/components/composite/command-palette.d.ts +2 -2
  18. package/dist/components/composite/command-palette.js +8 -5
  19. package/dist/components/composite/command-palette.js.map +1 -1
  20. package/dist/components/composite/confirm-dialog.d.ts +8 -8
  21. package/dist/components/composite/confirm-dialog.js +8 -3
  22. package/dist/components/composite/confirm-dialog.js.map +1 -1
  23. package/dist/components/composite/copy-button.d.ts +7 -3
  24. package/dist/components/composite/copy-button.js +7 -3
  25. package/dist/components/composite/copy-button.js.map +1 -1
  26. package/dist/components/composite/data-table-constants.d.ts +7 -3
  27. package/dist/components/composite/data-table-constants.js +2 -9
  28. package/dist/components/composite/data-table-constants.js.map +1 -1
  29. package/dist/components/composite/data-table.js +3 -3
  30. package/dist/components/composite/data-table.js.map +1 -1
  31. package/dist/components/composite/date-picker-constants.d.ts +32 -9
  32. package/dist/components/composite/date-picker-constants.js +16 -11
  33. package/dist/components/composite/date-picker-constants.js.map +1 -1
  34. package/dist/components/composite/date-picker.d.ts +19 -10
  35. package/dist/components/composite/date-picker.js +33 -9
  36. package/dist/components/composite/date-picker.js.map +1 -1
  37. package/dist/components/composite/filter-chips.d.ts +4 -3
  38. package/dist/components/composite/filter-chips.js +6 -2
  39. package/dist/components/composite/filter-chips.js.map +1 -1
  40. package/dist/components/composite/inline-edit.d.ts +14 -3
  41. package/dist/components/composite/inline-edit.js +8 -4
  42. package/dist/components/composite/inline-edit.js.map +1 -1
  43. package/dist/components/composite/relative-time.d.ts +4 -4
  44. package/dist/components/composite/relative-time.js +4 -2
  45. package/dist/components/composite/relative-time.js.map +1 -1
  46. package/dist/components/composite/route-tabs-nav.d.ts +9 -0
  47. package/dist/components/composite/route-tabs-nav.js +11 -0
  48. package/dist/components/composite/route-tabs-nav.js.map +1 -0
  49. package/dist/components/composite/route-tabs.d.ts +4 -1
  50. package/dist/components/composite/route-tabs.js +3 -2
  51. package/dist/components/composite/route-tabs.js.map +1 -1
  52. package/dist/components/composite/search-filter-bar-constants.d.ts +18 -8
  53. package/dist/components/composite/search-filter-bar-constants.js +2 -14
  54. package/dist/components/composite/search-filter-bar-constants.js.map +1 -1
  55. package/dist/components/composite/search-filter-bar.d.ts +5 -2
  56. package/dist/components/composite/search-filter-bar.js +2 -2
  57. package/dist/components/composite/search-filter-bar.js.map +1 -1
  58. package/dist/components/composite/stat-card.d.ts +1 -1
  59. package/dist/components/composite/table-pagination-constants.d.ts +16 -11
  60. package/dist/components/composite/table-pagination-constants.js +2 -12
  61. package/dist/components/composite/table-pagination-constants.js.map +1 -1
  62. package/dist/components/composite/table-pagination.d.ts +6 -3
  63. package/dist/components/composite/table-pagination.js +3 -5
  64. package/dist/components/composite/table-pagination.js.map +1 -1
  65. package/dist/components/composite/toast.d.ts +5 -2
  66. package/dist/components/composite/toast.js +3 -1
  67. package/dist/components/composite/toast.js.map +1 -1
  68. package/dist/components/ui/action-bar-constants.d.ts +8 -4
  69. package/dist/components/ui/action-bar-constants.js +2 -5
  70. package/dist/components/ui/action-bar-constants.js.map +1 -1
  71. package/dist/components/ui/action-bar.d.ts +5 -4
  72. package/dist/components/ui/action-bar.js +47 -3
  73. package/dist/components/ui/action-bar.js.map +1 -1
  74. package/dist/components/ui/alert.d.ts +1 -1
  75. package/dist/components/ui/badge-overflow.d.ts +2 -2
  76. package/dist/components/ui/badge-overflow.js +4 -2
  77. package/dist/components/ui/badge-overflow.js.map +1 -1
  78. package/dist/components/ui/badge.d.ts +1 -1
  79. package/dist/components/ui/banner.d.ts +6 -5
  80. package/dist/components/ui/banner.js +3 -1
  81. package/dist/components/ui/banner.js.map +1 -1
  82. package/dist/components/ui/breadcrumb.d.ts +11 -4
  83. package/dist/components/ui/breadcrumb.js +7 -2
  84. package/dist/components/ui/breadcrumb.js.map +1 -1
  85. package/dist/components/ui/button.d.ts +2 -2
  86. package/dist/components/ui/calendar.d.ts +12 -5
  87. package/dist/components/ui/calendar.js +38 -3
  88. package/dist/components/ui/calendar.js.map +1 -1
  89. package/dist/components/ui/carousel.d.ts +4 -3
  90. package/dist/components/ui/carousel.js +11 -4
  91. package/dist/components/ui/carousel.js.map +1 -1
  92. package/dist/components/ui/circular-progress.js +10 -2
  93. package/dist/components/ui/circular-progress.js.map +1 -1
  94. package/dist/components/ui/command.d.ts +5 -4
  95. package/dist/components/ui/command.js +6 -2
  96. package/dist/components/ui/command.js.map +1 -1
  97. package/dist/components/ui/cropper-constants.d.ts +8 -3
  98. package/dist/components/ui/cropper-constants.js +2 -6
  99. package/dist/components/ui/cropper-constants.js.map +1 -1
  100. package/dist/components/ui/cropper.d.ts +2 -1
  101. package/dist/components/ui/cropper.js +2 -2
  102. package/dist/components/ui/cropper.js.map +1 -1
  103. package/dist/components/ui/dialog.d.ts +2 -2
  104. package/dist/components/ui/dialog.js +4 -1
  105. package/dist/components/ui/dialog.js.map +1 -1
  106. package/dist/components/ui/item.d.ts +2 -2
  107. package/dist/components/ui/kanban-constants.d.ts +7 -1
  108. package/dist/components/ui/kanban-constants.js +2 -17
  109. package/dist/components/ui/kanban-constants.js.map +1 -1
  110. package/dist/components/ui/kanban.d.ts +2 -2
  111. package/dist/components/ui/kanban.js +11 -5
  112. package/dist/components/ui/kanban.js.map +1 -1
  113. package/dist/components/ui/key-value-constants.d.ts +7 -3
  114. package/dist/components/ui/key-value-constants.js +2 -7
  115. package/dist/components/ui/key-value-constants.js.map +1 -1
  116. package/dist/components/ui/key-value.d.ts +5 -5
  117. package/dist/components/ui/key-value.js +72 -78
  118. package/dist/components/ui/key-value.js.map +1 -1
  119. package/dist/components/ui/mask-input-constants.d.ts +2 -3
  120. package/dist/components/ui/mask-input-constants.js +36 -77
  121. package/dist/components/ui/mask-input-constants.js.map +1 -1
  122. package/dist/components/ui/mask-input.d.ts +7 -4
  123. package/dist/components/ui/mask-input.js +22 -22
  124. package/dist/components/ui/mask-input.js.map +1 -1
  125. package/dist/components/ui/mention.d.ts +3 -2
  126. package/dist/components/ui/mention.js +4 -6
  127. package/dist/components/ui/mention.js.map +1 -1
  128. package/dist/components/ui/pagination.d.ts +13 -9
  129. package/dist/components/ui/pagination.js +15 -6
  130. package/dist/components/ui/pagination.js.map +1 -1
  131. package/dist/components/ui/phone-input-constants.d.ts +17 -6
  132. package/dist/components/ui/phone-input-constants.js +2 -5
  133. package/dist/components/ui/phone-input-constants.js.map +1 -1
  134. package/dist/components/ui/phone-input.d.ts +18 -11
  135. package/dist/components/ui/phone-input.js +14 -12
  136. package/dist/components/ui/phone-input.js.map +1 -1
  137. package/dist/components/ui/progress.d.ts +2 -2
  138. package/dist/components/ui/rating.d.ts +2 -1
  139. package/dist/components/ui/rating.js +8 -4
  140. package/dist/components/ui/rating.js.map +1 -1
  141. package/dist/components/ui/scroll-spy.js +3 -1
  142. package/dist/components/ui/scroll-spy.js.map +1 -1
  143. package/dist/components/ui/sheet.d.ts +2 -2
  144. package/dist/components/ui/sheet.js +10 -1
  145. package/dist/components/ui/sheet.js.map +1 -1
  146. package/dist/components/ui/slider.d.ts +1 -1
  147. package/dist/components/ui/slider.js +15 -1
  148. package/dist/components/ui/slider.js.map +1 -1
  149. package/dist/components/ui/sonner.js +2 -0
  150. package/dist/components/ui/sonner.js.map +1 -1
  151. package/dist/components/ui/spinner.js +4 -1
  152. package/dist/components/ui/spinner.js.map +1 -1
  153. package/dist/components/ui/stepper-constants.d.ts +7 -2
  154. package/dist/components/ui/stepper-constants.js +2 -5
  155. package/dist/components/ui/stepper-constants.js.map +1 -1
  156. package/dist/components/ui/stepper.d.ts +2 -1
  157. package/dist/components/ui/stepper.js +2 -2
  158. package/dist/components/ui/stepper.js.map +1 -1
  159. package/dist/components/ui/tags-input.d.ts +3 -2
  160. package/dist/components/ui/tags-input.js +4 -2
  161. package/dist/components/ui/tags-input.js.map +1 -1
  162. package/dist/components/ui/time-picker-constants.d.ts +12 -9
  163. package/dist/components/ui/time-picker-constants.js +2 -10
  164. package/dist/components/ui/time-picker-constants.js.map +1 -1
  165. package/dist/components/ui/time-picker.d.ts +11 -6
  166. package/dist/components/ui/time-picker.js +5 -7
  167. package/dist/components/ui/time-picker.js.map +1 -1
  168. package/dist/components/ui/toggle-group.js +12 -1
  169. package/dist/components/ui/toggle-group.js.map +1 -1
  170. package/dist/components/ui/toggle.d.ts +1 -1
  171. package/dist/components/ui/tour-constants.d.ts +7 -2
  172. package/dist/components/ui/tour-constants.js +2 -8
  173. package/dist/components/ui/tour-constants.js.map +1 -1
  174. package/dist/components/ui/tour.d.ts +3 -2
  175. package/dist/components/ui/tour.js +5 -4
  176. package/dist/components/ui/tour.js.map +1 -1
  177. package/dist/data-grid/data-grid-cell-variants.js +4 -4
  178. package/dist/data-grid/data-grid-cell-variants.js.map +1 -1
  179. package/dist/data-grid/data-grid-column-header.js +1 -1
  180. package/dist/data-grid/data-grid-column-header.js.map +1 -1
  181. package/dist/data-grid/data-grid-filter-menu.d.ts +5 -4
  182. package/dist/data-grid/data-grid-filter-menu.js +13 -8
  183. package/dist/data-grid/data-grid-filter-menu.js.map +1 -1
  184. package/dist/data-grid/data-grid-keyboard-shortcuts.d.ts +4 -4
  185. package/dist/data-grid/data-grid-keyboard-shortcuts.js.map +1 -1
  186. package/dist/data-grid/data-grid-locale.d.ts +58 -6
  187. package/dist/data-grid/data-grid-locale.js +41 -9
  188. package/dist/data-grid/data-grid-locale.js.map +1 -1
  189. package/dist/data-grid/data-grid-row-height-menu.d.ts +4 -3
  190. package/dist/data-grid/data-grid-row-height-menu.js.map +1 -1
  191. package/dist/data-grid/data-grid-sort-menu.d.ts +4 -4
  192. package/dist/data-grid/data-grid-sort-menu.js +1 -1
  193. package/dist/data-grid/data-grid-sort-menu.js.map +1 -1
  194. package/dist/data-grid/data-grid-view-menu.d.ts +4 -4
  195. package/dist/data-grid/data-grid-view-menu.js.map +1 -1
  196. package/dist/data-grid/data-grid.d.ts +4 -3
  197. package/dist/data-grid/data-grid.js +2 -3
  198. package/dist/data-grid/data-grid.js.map +1 -1
  199. package/dist/data-grid/index.d.ts +1 -0
  200. package/dist/data-grid/index.js.map +1 -1
  201. package/dist/data-grid/messages-en.d.ts +23 -4
  202. package/dist/data-grid/messages-en.js +20 -0
  203. package/dist/data-grid/messages-en.js.map +1 -1
  204. package/dist/data-grid/messages-vi.d.ts +3 -1
  205. package/dist/data-grid/messages-vi.js +14 -0
  206. package/dist/data-grid/messages-vi.js.map +1 -1
  207. package/dist/data-grid/messages.d.ts +29 -3
  208. package/dist/data-grid/messages.js.map +1 -1
  209. package/dist/data-grid/sortable.js +16 -19
  210. package/dist/data-grid/sortable.js.map +1 -1
  211. package/dist/data-grid/types.d.ts +1 -1
  212. package/dist/data-grid/use-data-grid-undo-redo.d.ts +5 -4
  213. package/dist/data-grid/use-data-grid-undo-redo.js +2 -2
  214. package/dist/data-grid/use-data-grid-undo-redo.js.map +1 -1
  215. package/dist/data-grid/use-data-grid.d.ts +23 -8
  216. package/dist/data-grid/use-data-grid.js +8 -6
  217. package/dist/data-grid/use-data-grid.js.map +1 -1
  218. package/dist/data-grid/utils.d.ts +24 -4
  219. package/dist/data-grid/utils.js +15 -5
  220. package/dist/data-grid/utils.js.map +1 -1
  221. package/dist/i18n/locale-provider.d.ts +127 -0
  222. package/dist/i18n/locale-provider.js +47 -0
  223. package/dist/i18n/locale-provider.js.map +1 -0
  224. package/dist/i18n/locale.d.ts +27 -0
  225. package/dist/i18n/locale.js +10 -0
  226. package/dist/i18n/locale.js.map +1 -0
  227. package/dist/i18n/messages.d.ts +116 -0
  228. package/dist/i18n/messages.js +149 -0
  229. package/dist/i18n/messages.js.map +1 -0
  230. package/dist/i18n/namespaces/action-bar.d.ts +7 -0
  231. package/dist/i18n/namespaces/action-bar.js +15 -0
  232. package/dist/i18n/namespaces/action-bar.js.map +1 -0
  233. package/dist/i18n/namespaces/avatar-group.d.ts +14 -0
  234. package/dist/i18n/namespaces/avatar-group.js +13 -0
  235. package/dist/i18n/namespaces/avatar-group.js.map +1 -0
  236. package/dist/i18n/namespaces/badge-overflow.d.ts +12 -0
  237. package/dist/i18n/namespaces/badge-overflow.js +11 -0
  238. package/dist/i18n/namespaces/badge-overflow.js.map +1 -0
  239. package/dist/i18n/namespaces/banner.d.ts +9 -0
  240. package/dist/i18n/namespaces/banner.js +7 -0
  241. package/dist/i18n/namespaces/banner.js.map +1 -0
  242. package/dist/i18n/namespaces/breadcrumb.d.ts +11 -0
  243. package/dist/i18n/namespaces/breadcrumb.js +13 -0
  244. package/dist/i18n/namespaces/breadcrumb.js.map +1 -0
  245. package/dist/i18n/namespaces/calendar.d.ts +40 -0
  246. package/dist/i18n/namespaces/calendar.js +25 -0
  247. package/dist/i18n/namespaces/calendar.js.map +1 -0
  248. package/dist/i18n/namespaces/carousel.d.ts +15 -0
  249. package/dist/i18n/namespaces/carousel.js +17 -0
  250. package/dist/i18n/namespaces/carousel.js.map +1 -0
  251. package/dist/i18n/namespaces/combobox.d.ts +21 -0
  252. package/dist/i18n/namespaces/combobox.js +23 -0
  253. package/dist/i18n/namespaces/combobox.js.map +1 -0
  254. package/dist/i18n/namespaces/command-palette.d.ts +20 -0
  255. package/dist/i18n/namespaces/command-palette.js +19 -0
  256. package/dist/i18n/namespaces/command-palette.js.map +1 -0
  257. package/dist/i18n/namespaces/command.d.ts +11 -0
  258. package/dist/i18n/namespaces/command.js +13 -0
  259. package/dist/i18n/namespaces/command.js.map +1 -0
  260. package/dist/i18n/namespaces/confirm-dialog.d.ts +13 -0
  261. package/dist/i18n/namespaces/confirm-dialog.js +15 -0
  262. package/dist/i18n/namespaces/confirm-dialog.js.map +1 -0
  263. package/dist/i18n/namespaces/contrast.d.ts +7 -0
  264. package/dist/i18n/namespaces/contrast.js +13 -0
  265. package/dist/i18n/namespaces/contrast.js.map +1 -0
  266. package/dist/i18n/namespaces/copy-button.d.ts +11 -0
  267. package/dist/i18n/namespaces/copy-button.js +13 -0
  268. package/dist/i18n/namespaces/copy-button.js.map +1 -0
  269. package/dist/i18n/namespaces/cropper.d.ts +7 -0
  270. package/dist/i18n/namespaces/cropper.js +17 -0
  271. package/dist/i18n/namespaces/cropper.js.map +1 -0
  272. package/dist/i18n/namespaces/data-table.d.ts +7 -0
  273. package/dist/i18n/namespaces/data-table.js +23 -0
  274. package/dist/i18n/namespaces/data-table.js.map +1 -0
  275. package/dist/i18n/namespaces/date-picker.d.ts +42 -0
  276. package/dist/i18n/namespaces/date-picker.js +35 -0
  277. package/dist/i18n/namespaces/date-picker.js.map +1 -0
  278. package/dist/i18n/namespaces/dialog.d.ts +9 -0
  279. package/dist/i18n/namespaces/dialog.js +7 -0
  280. package/dist/i18n/namespaces/dialog.js.map +1 -0
  281. package/dist/i18n/namespaces/display-axis.d.ts +25 -0
  282. package/dist/i18n/namespaces/display-axis.js +21 -0
  283. package/dist/i18n/namespaces/display-axis.js.map +1 -0
  284. package/dist/i18n/namespaces/file-upload.d.ts +11 -0
  285. package/dist/i18n/namespaces/file-upload.js +19 -0
  286. package/dist/i18n/namespaces/file-upload.js.map +1 -0
  287. package/dist/i18n/namespaces/filter-chips.d.ts +11 -0
  288. package/dist/i18n/namespaces/filter-chips.js +13 -0
  289. package/dist/i18n/namespaces/filter-chips.js.map +1 -0
  290. package/dist/i18n/namespaces/image-upload-field.d.ts +12 -0
  291. package/dist/i18n/namespaces/image-upload-field.js +23 -0
  292. package/dist/i18n/namespaces/image-upload-field.js.map +1 -0
  293. package/dist/i18n/namespaces/inline-edit.d.ts +15 -0
  294. package/dist/i18n/namespaces/inline-edit.js +17 -0
  295. package/dist/i18n/namespaces/inline-edit.js.map +1 -0
  296. package/dist/i18n/namespaces/kanban.d.ts +11 -0
  297. package/dist/i18n/namespaces/kanban.js +39 -0
  298. package/dist/i18n/namespaces/kanban.js.map +1 -0
  299. package/dist/i18n/namespaces/key-value.d.ts +10 -0
  300. package/dist/i18n/namespaces/key-value.js +19 -0
  301. package/dist/i18n/namespaces/key-value.js.map +1 -0
  302. package/dist/i18n/namespaces/mention.d.ts +9 -0
  303. package/dist/i18n/namespaces/mention.js +7 -0
  304. package/dist/i18n/namespaces/mention.js.map +1 -0
  305. package/dist/i18n/namespaces/pagination.d.ts +19 -0
  306. package/dist/i18n/namespaces/pagination.js +21 -0
  307. package/dist/i18n/namespaces/pagination.js.map +1 -0
  308. package/dist/i18n/namespaces/phone-input.d.ts +10 -0
  309. package/dist/i18n/namespaces/phone-input.js +17 -0
  310. package/dist/i18n/namespaces/phone-input.js.map +1 -0
  311. package/dist/i18n/namespaces/rating.d.ts +12 -0
  312. package/dist/i18n/namespaces/rating.js +12 -0
  313. package/dist/i18n/namespaces/rating.js.map +1 -0
  314. package/dist/i18n/namespaces/route-tabs.d.ts +9 -0
  315. package/dist/i18n/namespaces/route-tabs.js +7 -0
  316. package/dist/i18n/namespaces/route-tabs.js.map +1 -0
  317. package/dist/i18n/namespaces/scroll-spy.d.ts +9 -0
  318. package/dist/i18n/namespaces/scroll-spy.js +7 -0
  319. package/dist/i18n/namespaces/scroll-spy.js.map +1 -0
  320. package/dist/i18n/namespaces/search-filter-bar.d.ts +15 -0
  321. package/dist/i18n/namespaces/search-filter-bar.js +32 -0
  322. package/dist/i18n/namespaces/search-filter-bar.js.map +1 -0
  323. package/dist/i18n/namespaces/sheet.d.ts +9 -0
  324. package/dist/i18n/namespaces/sheet.js +7 -0
  325. package/dist/i18n/namespaces/sheet.js.map +1 -0
  326. package/dist/i18n/namespaces/shell.d.ts +21 -0
  327. package/dist/i18n/namespaces/shell.js +75 -0
  328. package/dist/i18n/namespaces/shell.js.map +1 -0
  329. package/dist/i18n/namespaces/spinner.d.ts +9 -0
  330. package/dist/i18n/namespaces/spinner.js +7 -0
  331. package/dist/i18n/namespaces/spinner.js.map +1 -0
  332. package/dist/i18n/namespaces/stepper.d.ts +7 -0
  333. package/dist/i18n/namespaces/stepper.js +15 -0
  334. package/dist/i18n/namespaces/stepper.js.map +1 -0
  335. package/dist/i18n/namespaces/table-pagination.d.ts +7 -0
  336. package/dist/i18n/namespaces/table-pagination.js +29 -0
  337. package/dist/i18n/namespaces/table-pagination.js.map +1 -0
  338. package/dist/i18n/namespaces/tags-input.d.ts +12 -0
  339. package/dist/i18n/namespaces/tags-input.js +11 -0
  340. package/dist/i18n/namespaces/tags-input.js.map +1 -0
  341. package/dist/i18n/namespaces/time-picker.d.ts +15 -0
  342. package/dist/i18n/namespaces/time-picker.js +25 -0
  343. package/dist/i18n/namespaces/time-picker.js.map +1 -0
  344. package/dist/i18n/namespaces/toast.d.ts +16 -0
  345. package/dist/i18n/namespaces/toast.js +7 -0
  346. package/dist/i18n/namespaces/toast.js.map +1 -0
  347. package/dist/i18n/namespaces/tour.d.ts +7 -0
  348. package/dist/i18n/namespaces/tour.js +21 -0
  349. package/dist/i18n/namespaces/tour.js.map +1 -0
  350. package/dist/index.d.ts +32 -0
  351. package/dist/index.js +24 -1
  352. package/dist/index.js.map +1 -1
  353. package/dist/lib/toast-language.d.ts +8 -0
  354. package/dist/lib/toast-language.js +19 -0
  355. package/dist/lib/toast-language.js.map +1 -0
  356. package/dist/shell/app-header.js.map +1 -1
  357. package/dist/shell/app-shell.d.ts +20 -2
  358. package/dist/shell/app-shell.js +4 -1
  359. package/dist/shell/app-shell.js.map +1 -1
  360. package/dist/shell/contrast-constants.d.ts +9 -1
  361. package/dist/shell/contrast-constants.js +2 -4
  362. package/dist/shell/contrast-constants.js.map +1 -1
  363. package/dist/shell/contrast-toggle.d.ts +4 -1
  364. package/dist/shell/contrast-toggle.js +2 -2
  365. package/dist/shell/contrast-toggle.js.map +1 -1
  366. package/dist/shell/display-axis-constants.d.ts +2 -1
  367. package/dist/shell/display-axis-constants.js.map +1 -1
  368. package/dist/shell/display-axis-controls.d.ts +15 -6
  369. package/dist/shell/display-axis-controls.js +11 -9
  370. package/dist/shell/display-axis-controls.js.map +1 -1
  371. package/dist/shell/display-axis-provider.d.ts +1 -1
  372. package/dist/shell/mobile-menu.js.map +1 -1
  373. package/dist/shell/notifications-button.d.ts +1 -1
  374. package/dist/shell/notifications-button.js +3 -2
  375. package/dist/shell/notifications-button.js.map +1 -1
  376. package/dist/shell/shell-context.d.ts +4 -1
  377. package/dist/shell/shell-context.js +2 -4
  378. package/dist/shell/shell-context.js.map +1 -1
  379. package/dist/shell/sidebar.d.ts +1 -1
  380. package/dist/shell/sidebar.js.map +1 -1
  381. package/dist/shell/theme-toggle.d.ts +6 -3
  382. package/dist/shell/theme-toggle.js +2 -2
  383. package/dist/shell/theme-toggle.js.map +1 -1
  384. package/dist/shell/types.d.ts +14 -8
  385. package/dist/shell/types.js +2 -35
  386. package/dist/shell/types.js.map +1 -1
  387. package/dist/shell/user-menu.d.ts +6 -6
  388. package/dist/shell/user-menu.js.map +1 -1
  389. package/dist/shell/utils.d.ts +1 -1
  390. package/dist/shell/utils.js.map +1 -1
  391. package/dist/shell/workspace-switcher.js +1 -1
  392. package/dist/shell/workspace-switcher.js.map +1 -1
  393. package/dist/uploader/file-upload-constants.d.ts +13 -0
  394. package/dist/uploader/file-upload-constants.js +4 -16
  395. package/dist/uploader/file-upload-constants.js.map +1 -1
  396. package/dist/uploader/file-upload.d.ts +4 -1
  397. package/dist/uploader/file-upload.js +2 -2
  398. package/dist/uploader/file-upload.js.map +1 -1
  399. package/dist/uploader/image-upload-field.d.ts +5 -1
  400. package/dist/uploader/image-upload-field.js +2 -2
  401. package/dist/uploader/image-upload-field.js.map +1 -1
  402. package/dist/uploader/use-file-upload.d.ts +4 -0
  403. package/dist/uploader/use-file-upload.js +6 -2
  404. package/dist/uploader/use-file-upload.js.map +1 -1
  405. package/package.json +4 -3
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/ui/carousel.tsx"],"sourcesContent":["\"use client\";\n\nimport useEmblaCarousel, { type UseEmblaCarouselType } from \"embla-carousel-react\";\nimport { ArrowLeft, ArrowRight } from \"lucide-react\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn.js\";\nimport { Button, type ButtonProps } from \"./button.js\";\n\n/**\n * Carousel (embla) — băng chuyền ngang/dọc, điều hướng được bằng phím ←/→.\n * `useCarousel()` được export để app tự dựng chấm chỉ báo hoặc nút điều khiển riêng.\n * Chuỗi cho trình đọc màn hình mặc định tiếng Việt, override qua prop `srLabel`.\n */\n\nexport type CarouselApi = UseEmblaCarouselType[1];\ntype UseCarouselParameters = Parameters<typeof useEmblaCarousel>;\nexport type CarouselOptions = UseCarouselParameters[0];\nexport type CarouselPlugin = UseCarouselParameters[1];\n\nexport type CarouselOwnProps = {\n opts?: CarouselOptions;\n plugins?: CarouselPlugin;\n orientation?: \"horizontal\" | \"vertical\";\n setApi?: (api: CarouselApi) => void;\n};\n\nexport type CarouselProps = React.ComponentProps<\"div\"> & CarouselOwnProps;\nexport type CarouselContentProps = React.ComponentProps<\"div\">;\nexport type CarouselItemProps = React.ComponentProps<\"div\">;\nexport type CarouselPreviousProps = ButtonProps & { srLabel?: string };\nexport type CarouselNextProps = ButtonProps & { srLabel?: string };\n\nexport type CarouselContextProps = {\n carouselRef: ReturnType<typeof useEmblaCarousel>[0];\n api: ReturnType<typeof useEmblaCarousel>[1];\n scrollPrev: () => void;\n scrollNext: () => void;\n canScrollPrev: boolean;\n canScrollNext: boolean;\n} & CarouselOwnProps;\n\nconst CarouselContext = React.createContext<CarouselContextProps | null>(null);\n\nfunction useCarousel(): CarouselContextProps {\n const context = React.useContext(CarouselContext);\n\n if (!context) {\n throw new Error(\"useCarousel phải được dùng bên trong <Carousel />\");\n }\n\n return context;\n}\n\nfunction Carousel({ orientation = \"horizontal\", opts, setApi, plugins, className, children, ...props }: CarouselProps) {\n const [carouselRef, api] = useEmblaCarousel(\n {\n ...opts,\n axis: orientation === \"horizontal\" ? \"x\" : \"y\"\n },\n plugins\n );\n const [canScrollPrev, setCanScrollPrev] = React.useState(false);\n const [canScrollNext, setCanScrollNext] = React.useState(false);\n\n const onSelect = React.useCallback((emblaApi: CarouselApi) => {\n if (!emblaApi) return;\n setCanScrollPrev(emblaApi.canScrollPrev());\n setCanScrollNext(emblaApi.canScrollNext());\n }, []);\n\n const scrollPrev = React.useCallback(() => {\n api?.scrollPrev();\n }, [api]);\n\n const scrollNext = React.useCallback(() => {\n api?.scrollNext();\n }, [api]);\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n scrollPrev();\n } else if (event.key === \"ArrowRight\") {\n event.preventDefault();\n scrollNext();\n }\n },\n [scrollPrev, scrollNext]\n );\n\n React.useEffect(() => {\n if (!api || !setApi) return;\n setApi(api);\n }, [api, setApi]);\n\n React.useEffect(() => {\n if (!api) return;\n onSelect(api);\n api.on(\"reInit\", onSelect);\n api.on(\"select\", onSelect);\n\n return () => {\n api?.off(\"select\", onSelect);\n };\n }, [api, onSelect]);\n\n return (\n <CarouselContext.Provider\n value={{\n carouselRef,\n api: api,\n opts,\n orientation: orientation || (opts?.axis === \"y\" ? \"vertical\" : \"horizontal\"),\n scrollPrev,\n scrollNext,\n canScrollPrev,\n canScrollNext\n }}\n >\n <div\n onKeyDownCapture={handleKeyDown}\n className={cn(\"relative\", className)}\n role=\"region\"\n aria-roledescription=\"băng chuyền\"\n data-slot=\"carousel\"\n {...props}\n >\n {children}\n </div>\n </CarouselContext.Provider>\n );\n}\n\nfunction CarouselContent({ className, ...props }: CarouselContentProps) {\n const { carouselRef, orientation } = useCarousel();\n\n return (\n <div ref={carouselRef} className=\"overflow-hidden\" data-slot=\"carousel-content\">\n <div className={cn(\"flex\", orientation === \"horizontal\" ? \"-ml-4\" : \"-mt-4 flex-col\", className)} {...props} />\n </div>\n );\n}\n\nfunction CarouselItem({ className, ...props }: CarouselItemProps) {\n const { orientation } = useCarousel();\n\n return (\n <div\n role=\"group\"\n aria-roledescription=\"trang chiếu\"\n data-slot=\"carousel-item\"\n className={cn(\"min-w-0 shrink-0 grow-0 basis-full\", orientation === \"horizontal\" ? \"pl-4\" : \"pt-4\", className)}\n {...props}\n />\n );\n}\n\nfunction CarouselPrevious({\n className,\n variant = \"outline\",\n size = \"icon\",\n srLabel = \"Trang chiếu trước\",\n ...props\n}: CarouselPreviousProps) {\n const { orientation, scrollPrev, canScrollPrev } = useCarousel();\n\n return (\n <Button\n data-slot=\"carousel-previous\"\n variant={variant}\n size={size}\n className={cn(\n \"absolute size-8 rounded-full\",\n orientation === \"horizontal\"\n ? \"top-1/2 -left-12 -translate-y-1/2\"\n : \"-top-12 left-1/2 -translate-x-1/2 rotate-90\",\n className\n )}\n disabled={!canScrollPrev}\n onClick={scrollPrev}\n {...props}\n >\n <ArrowLeft />\n <span className=\"sr-only\">{srLabel}</span>\n </Button>\n );\n}\n\nfunction CarouselNext({\n className,\n variant = \"outline\",\n size = \"icon\",\n srLabel = \"Trang chiếu sau\",\n ...props\n}: CarouselNextProps) {\n const { orientation, scrollNext, canScrollNext } = useCarousel();\n\n return (\n <Button\n data-slot=\"carousel-next\"\n variant={variant}\n size={size}\n className={cn(\n \"absolute size-8 rounded-full\",\n orientation === \"horizontal\"\n ? \"top-1/2 -right-12 -translate-y-1/2\"\n : \"-bottom-12 left-1/2 -translate-x-1/2 rotate-90\",\n className\n )}\n disabled={!canScrollNext}\n onClick={scrollNext}\n {...props}\n >\n <ArrowRight />\n <span className=\"sr-only\">{srLabel}</span>\n </Button>\n );\n}\n\nexport { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, useCarousel };\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/components/ui/carousel.tsx"],"sourcesContent":["\"use client\";\n\nimport useEmblaCarousel, { type UseEmblaCarouselType } from \"embla-carousel-react\";\nimport { ArrowLeft, ArrowRight } from \"lucide-react\";\nimport * as React from \"react\";\nimport { useComitorMessages } from \"../../i18n/locale-provider.js\";\nimport { cn } from \"../../lib/cn.js\";\nimport { Button, type ButtonProps } from \"./button.js\";\n\n/**\n * Carousel (embla) — băng chuyền ngang/dọc, điều hướng được bằng phím ←/→.\n * `useCarousel()` được export để app tự dựng chấm chỉ báo hoặc nút điều khiển riêng.\n * Chuỗi cho trình đọc màn hình theo `ComitorLocaleProvider` (namespace `carousel`, mặc định tiếng\n * Anh); override qua prop `srLabel` / `aria-roledescription`.\n */\n\nexport type CarouselApi = UseEmblaCarouselType[1];\ntype UseCarouselParameters = Parameters<typeof useEmblaCarousel>;\nexport type CarouselOptions = UseCarouselParameters[0];\nexport type CarouselPlugin = UseCarouselParameters[1];\n\nexport type CarouselOwnProps = {\n opts?: CarouselOptions;\n plugins?: CarouselPlugin;\n orientation?: \"horizontal\" | \"vertical\";\n setApi?: (api: CarouselApi) => void;\n};\n\nexport type CarouselProps = React.ComponentProps<\"div\"> & CarouselOwnProps;\nexport type CarouselContentProps = React.ComponentProps<\"div\">;\nexport type CarouselItemProps = React.ComponentProps<\"div\">;\nexport type CarouselPreviousProps = ButtonProps & { srLabel?: string };\nexport type CarouselNextProps = ButtonProps & { srLabel?: string };\n\nexport type CarouselContextProps = {\n carouselRef: ReturnType<typeof useEmblaCarousel>[0];\n api: ReturnType<typeof useEmblaCarousel>[1];\n scrollPrev: () => void;\n scrollNext: () => void;\n canScrollPrev: boolean;\n canScrollNext: boolean;\n} & CarouselOwnProps;\n\nconst CarouselContext = React.createContext<CarouselContextProps | null>(null);\n\nfunction useCarousel(): CarouselContextProps {\n const context = React.useContext(CarouselContext);\n\n if (!context) {\n throw new Error(\"useCarousel phải được dùng bên trong <Carousel />\");\n }\n\n return context;\n}\n\nfunction Carousel({ orientation = \"horizontal\", opts, setApi, plugins, className, children, ...props }: CarouselProps) {\n const t = useComitorMessages(\"carousel\");\n const [carouselRef, api] = useEmblaCarousel(\n {\n ...opts,\n axis: orientation === \"horizontal\" ? \"x\" : \"y\"\n },\n plugins\n );\n const [canScrollPrev, setCanScrollPrev] = React.useState(false);\n const [canScrollNext, setCanScrollNext] = React.useState(false);\n\n const onSelect = React.useCallback((emblaApi: CarouselApi) => {\n if (!emblaApi) return;\n setCanScrollPrev(emblaApi.canScrollPrev());\n setCanScrollNext(emblaApi.canScrollNext());\n }, []);\n\n const scrollPrev = React.useCallback(() => {\n api?.scrollPrev();\n }, [api]);\n\n const scrollNext = React.useCallback(() => {\n api?.scrollNext();\n }, [api]);\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n scrollPrev();\n } else if (event.key === \"ArrowRight\") {\n event.preventDefault();\n scrollNext();\n }\n },\n [scrollPrev, scrollNext]\n );\n\n React.useEffect(() => {\n if (!api || !setApi) return;\n setApi(api);\n }, [api, setApi]);\n\n React.useEffect(() => {\n if (!api) return;\n onSelect(api);\n api.on(\"reInit\", onSelect);\n api.on(\"select\", onSelect);\n\n return () => {\n api?.off(\"select\", onSelect);\n };\n }, [api, onSelect]);\n\n return (\n <CarouselContext.Provider\n value={{\n carouselRef,\n api: api,\n opts,\n orientation: orientation || (opts?.axis === \"y\" ? \"vertical\" : \"horizontal\"),\n scrollPrev,\n scrollNext,\n canScrollPrev,\n canScrollNext\n }}\n >\n <div\n onKeyDownCapture={handleKeyDown}\n className={cn(\"relative\", className)}\n role=\"region\"\n aria-roledescription={t.roleDescription}\n data-slot=\"carousel\"\n {...props}\n >\n {children}\n </div>\n </CarouselContext.Provider>\n );\n}\n\nfunction CarouselContent({ className, ...props }: CarouselContentProps) {\n const { carouselRef, orientation } = useCarousel();\n\n return (\n <div ref={carouselRef} className=\"overflow-hidden\" data-slot=\"carousel-content\">\n <div className={cn(\"flex\", orientation === \"horizontal\" ? \"-ml-4\" : \"-mt-4 flex-col\", className)} {...props} />\n </div>\n );\n}\n\nfunction CarouselItem({ className, ...props }: CarouselItemProps) {\n const { orientation } = useCarousel();\n const t = useComitorMessages(\"carousel\");\n\n return (\n <div\n role=\"group\"\n aria-roledescription={t.slideRoleDescription}\n data-slot=\"carousel-item\"\n className={cn(\"min-w-0 shrink-0 grow-0 basis-full\", orientation === \"horizontal\" ? \"pl-4\" : \"pt-4\", className)}\n {...props}\n />\n );\n}\n\nfunction CarouselPrevious({\n className,\n variant = \"outline\",\n size = \"icon\",\n srLabel: srLabelProp,\n ...props\n}: CarouselPreviousProps) {\n const { orientation, scrollPrev, canScrollPrev } = useCarousel();\n const t = useComitorMessages(\"carousel\");\n const srLabel = srLabelProp ?? t.previousLabel;\n\n return (\n <Button\n data-slot=\"carousel-previous\"\n variant={variant}\n size={size}\n className={cn(\n \"absolute size-8 rounded-full\",\n orientation === \"horizontal\"\n ? \"top-1/2 -left-12 -translate-y-1/2\"\n : \"-top-12 left-1/2 -translate-x-1/2 rotate-90\",\n className\n )}\n disabled={!canScrollPrev}\n onClick={scrollPrev}\n {...props}\n >\n <ArrowLeft />\n <span className=\"sr-only\">{srLabel}</span>\n </Button>\n );\n}\n\nfunction CarouselNext({\n className,\n variant = \"outline\",\n size = \"icon\",\n srLabel: srLabelProp,\n ...props\n}: CarouselNextProps) {\n const { orientation, scrollNext, canScrollNext } = useCarousel();\n const t = useComitorMessages(\"carousel\");\n const srLabel = srLabelProp ?? t.nextLabel;\n\n return (\n <Button\n data-slot=\"carousel-next\"\n variant={variant}\n size={size}\n className={cn(\n \"absolute size-8 rounded-full\",\n orientation === \"horizontal\"\n ? \"top-1/2 -right-12 -translate-y-1/2\"\n : \"-bottom-12 left-1/2 -translate-x-1/2 rotate-90\",\n className\n )}\n disabled={!canScrollNext}\n onClick={scrollNext}\n {...props}\n >\n <ArrowRight />\n <span className=\"sr-only\">{srLabel}</span>\n </Button>\n );\n}\n\nexport { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, useCarousel };\n"],"mappings":"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","names":[]}
@@ -3,6 +3,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { Slot } from "@radix-ui/react-slot";
4
4
  import * as React from "react";
5
5
  import { cn } from "../../lib/cn.js";
6
+ import { useIsomorphicLayoutEffect } from "../../lib/use-isomorphic-layout-effect.js";
6
7
  const CIRCULAR_PROGRESS_NAME = "CircularProgress";
7
8
  const INDICATOR_NAME = "CircularProgressIndicator";
8
9
  const TRACK_NAME = "CircularProgressTrack";
@@ -81,6 +82,7 @@ function CircularProgress(props) {
81
82
  const percentage = getIsValidNumber(value) ? max === min ? 1 : (value - min) / (max - min) : null;
82
83
  const labelId = React.useId();
83
84
  const valueTextId = React.useId();
85
+ const [hasValueText, setHasValueText] = React.useState(false);
84
86
  const contextValue = React.useMemo(
85
87
  () => ({
86
88
  value,
@@ -94,7 +96,8 @@ function CircularProgress(props) {
94
96
  center,
95
97
  circumference,
96
98
  percentage,
97
- valueTextId
99
+ valueTextId,
100
+ onValueTextMountChange: setHasValueText
98
101
  }),
99
102
  [value, valueText, max, min, state, radius, thickness, size, center, circumference, percentage, valueTextId]
100
103
  );
@@ -103,7 +106,7 @@ function CircularProgress(props) {
103
106
  RootPrimitive,
104
107
  {
105
108
  role: "progressbar",
106
- "aria-describedby": valueText ? valueTextId : void 0,
109
+ "aria-describedby": valueText && hasValueText ? valueTextId : void 0,
107
110
  "aria-labelledby": label ? labelId : void 0,
108
111
  "aria-valuemax": max,
109
112
  "aria-valuemin": min,
@@ -233,6 +236,11 @@ function CircularProgressRange(props) {
233
236
  function CircularProgressValueText(props) {
234
237
  const { asChild, className, children, ...valueTextProps } = props;
235
238
  const context = useCircularProgressContext(VALUE_TEXT_NAME);
239
+ const { onValueTextMountChange } = context;
240
+ useIsomorphicLayoutEffect(() => {
241
+ onValueTextMountChange(true);
242
+ return () => onValueTextMountChange(false);
243
+ }, [onValueTextMountChange]);
236
244
  const ValueTextPrimitive = asChild ? Slot : "span";
237
245
  return /* @__PURE__ */ jsx(
238
246
  ValueTextPrimitive,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/ui/circular-progress.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/circular-progress) — MIT, © 2024 Sadman Sakib.\n * Giữ nguyên cấu trúc thượng nguồn để còn đối chiếu ngược được; mọi chỗ đổi đều có chú thích.\n */\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn.js\";\n\nconst CIRCULAR_PROGRESS_NAME = \"CircularProgress\";\nconst INDICATOR_NAME = \"CircularProgressIndicator\";\nconst TRACK_NAME = \"CircularProgressTrack\";\nconst RANGE_NAME = \"CircularProgressRange\";\nconst VALUE_TEXT_NAME = \"CircularProgressValueText\";\n\nconst DEFAULT_MAX = 100;\n\n/*\n * ⚠ Khác thượng nguồn: bản gốc đọc thẳng `process.env.NODE_ENV` ngay trong lúc render. Gói ra ESM\n * từng file, không bundle; ở môi trường không có bundler thay chuỗi đó (ESM thuần trên trình\n * duyệt), `process` không tồn tại → ReferenceError lúc render. Bọc `typeof` để chỗ đó chỉ mất cảnh\n * báo dev chứ không gãy; bundler vẫn thay `process.env.NODE_ENV` và loại nhánh dev như cũ.\n */\nconst IS_DEV = typeof process !== \"undefined\" && process.env.NODE_ENV !== \"production\";\n\ntype ProgressState = \"indeterminate\" | \"complete\" | \"loading\";\n\nfunction getProgressState(value: number | undefined | null, maxValue: number): ProgressState {\n return value == null ? \"indeterminate\" : value === maxValue ? \"complete\" : \"loading\";\n}\n\nfunction getIsValidNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction getIsValidMaxNumber(max: unknown): max is number {\n return getIsValidNumber(max) && max > 0;\n}\n\nfunction getIsValidValueNumber(value: unknown, min: number, max: number): value is number {\n return getIsValidNumber(value) && value <= max && value >= min;\n}\n\nfunction getDefaultValueText(value: number, min: number, max: number): string {\n const percentage = max === min ? 100 : ((value - min) / (max - min)) * 100;\n return `${Math.round(percentage)}%`;\n}\n\nfunction getInvalidValueError(propValue: string, componentName: string): string {\n return `Prop \\`value\\` = \\`${propValue}\\` truyền cho \\`${componentName}\\` không hợp lệ. \\`value\\` phải là số trong khoảng \\`min\\`…\\`max\\` (tính cả hai đầu), hoặc \\`null\\`/\\`undefined\\` cho tiến trình không xác định. Giá trị sẽ bị kẹp về khoảng hợp lệ.`;\n}\n\nfunction getInvalidMaxError(propValue: string, componentName: string): string {\n return `Prop \\`max\\` = \\`${propValue}\\` truyền cho \\`${componentName}\\` không hợp lệ. Chỉ nhận số lớn hơn 0 — dùng mặc định ${DEFAULT_MAX}.`;\n}\n\ninterface CircularProgressContextValue {\n value: number | null;\n valueText: string | undefined;\n max: number;\n min: number;\n state: ProgressState;\n radius: number;\n thickness: number;\n size: number;\n center: number;\n circumference: number;\n percentage: number | null;\n valueTextId?: string;\n}\n\nconst CircularProgressContext = React.createContext<CircularProgressContextValue | null>(null);\n\nfunction useCircularProgressContext(consumerName: string) {\n const context = React.useContext(CircularProgressContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${CIRCULAR_PROGRESS_NAME}\\``);\n }\n return context;\n}\n\ninterface CircularProgressProps extends React.ComponentProps<\"div\"> {\n /** Giá trị hiện tại; `null`/`undefined` = không xác định (vòng quay). */\n value?: number | null | undefined;\n /**\n * Chuỗi trình đọc màn hình đọc thay cho con số (`aria-valuetext`) và chữ giữa vòng — mặc định\n * phần trăm làm tròn, vd `\"45%\"`.\n */\n getValueText?(value: number, min: number, max: number): string;\n min?: number;\n max?: number;\n /** Đường kính, px. */\n size?: number;\n /** Độ dày nét, px. */\n thickness?: number;\n /**\n * Nhãn HIỆN của vòng, đồng thời là tên của `role=\"progressbar\"`. Không đặt nhãn hiện thì PHẢI\n * truyền `aria-label` — progressbar không tên là lỗi a11y (ARIA 1.2), gói không tự đặt tên\n * chung chung thay app (giống `Progress`).\n */\n label?: string;\n asChild?: boolean;\n}\n\n/**\n * CircularProgress — tiến trình dạng VÒNG, cặp với `Progress` (dạng thanh) của gói.\n * Ráp từ các phần (`CircularProgressIndicator` › `Track` + `Range`, `CircularProgressValueText`),\n * hoặc dùng sẵn `CircularProgressCombined`.\n *\n * Phần đã chạy là `text-primary-ink`, cùng bậc với thanh `Progress`; rãnh xám trung tính. Đổi tông\n * thì truyền bậc INK cho `CircularProgressRange` (vd `className=\"text-success-ink\"`), không phải\n * token tô nền `text-success` — rãnh không cần đổi theo (số đo ở `CircularProgressTrack`).\n *\n * ⚠ Trạng thái không xác định cần `--animate-spin-around` + `@keyframes spin-around` trong\n * styles.css; thiếu thì vòng đứng yên ở một cung 25% (không lỗi, không cảnh báo).\n */\nfunction CircularProgress(props: CircularProgressProps) {\n const {\n value: valueProp = null,\n getValueText = getDefaultValueText,\n min: minProp = 0,\n max: maxProp,\n size = 48,\n thickness = 4,\n label,\n asChild,\n className,\n children,\n ...rootProps\n } = props;\n\n if ((maxProp || maxProp === 0) && !getIsValidMaxNumber(maxProp)) {\n if (IS_DEV) {\n console.error(getInvalidMaxError(`${maxProp}`, CIRCULAR_PROGRESS_NAME));\n }\n }\n\n const rawMax = getIsValidMaxNumber(maxProp) ? maxProp : DEFAULT_MAX;\n const min = getIsValidNumber(minProp) ? minProp : 0;\n const max = rawMax <= min ? min + 1 : rawMax;\n\n if (IS_DEV && thickness >= size) {\n console.warn(\n `CircularProgress: \\`thickness\\` (${thickness}) phải nhỏ hơn \\`size\\` (${size}) thì vòng mới vẽ đúng.`\n );\n }\n\n if (valueProp !== null && !getIsValidValueNumber(valueProp, min, max)) {\n if (IS_DEV) {\n console.error(getInvalidValueError(`${valueProp}`, CIRCULAR_PROGRESS_NAME));\n }\n }\n\n const value = getIsValidValueNumber(valueProp, min, max)\n ? valueProp\n : getIsValidNumber(valueProp) && valueProp > max\n ? max\n : getIsValidNumber(valueProp) && valueProp < min\n ? min\n : null;\n\n const valueText = getIsValidNumber(value) ? getValueText(value, min, max) : undefined;\n const state = getProgressState(value, max);\n const radius = Math.max(0, (size - thickness) / 2);\n const center = size / 2;\n const circumference = 2 * Math.PI * radius;\n\n const percentage = getIsValidNumber(value) ? (max === min ? 1 : (value - min) / (max - min)) : null;\n\n const labelId = React.useId();\n const valueTextId = React.useId();\n\n const contextValue = React.useMemo<CircularProgressContextValue>(\n () => ({\n value,\n valueText,\n max,\n min,\n state,\n radius,\n thickness,\n size,\n center,\n circumference,\n percentage,\n valueTextId\n }),\n [value, valueText, max, min, state, radius, thickness, size, center, circumference, percentage, valueTextId]\n );\n\n const RootPrimitive = asChild ? Slot : \"div\";\n\n return (\n <CircularProgressContext.Provider value={contextValue}>\n <RootPrimitive\n role=\"progressbar\"\n aria-describedby={valueText ? valueTextId : undefined}\n aria-labelledby={label ? labelId : undefined}\n aria-valuemax={max}\n aria-valuemin={min}\n aria-valuenow={getIsValidNumber(value) ? value : undefined}\n aria-valuetext={valueText}\n data-state={state}\n data-value={value ?? undefined}\n data-max={max}\n data-min={min}\n data-percentage={percentage}\n data-slot=\"circular-progress\"\n {...rootProps}\n className={cn(\"relative inline-flex w-fit items-center justify-center\", label && \"flex-col gap-1.5\", className)}\n >\n {/*\n * ⚠ Khác thượng nguồn: bản gốc đặt nhãn làm anh em của vòng NGAY TRONG gốc, trong khi\n * `CircularProgressValueText` là `absolute inset-0` phủ CẢ gốc — có nhãn là chữ \"65%\" đè\n * lên chữ nhãn. Khi có `label`: bọc phần con trong một khung đúng cỡ vòng (`relative`, nên\n * chữ giá trị căn giữa VÒNG), nhãn xuống dưới vòng. Không có `label` thì DOM y như bản gốc.\n */}\n {label ? (\n <div data-slot=\"circular-progress-ring\" className=\"relative inline-flex items-center justify-center\">\n {children}\n </div>\n ) : (\n children\n )}\n {label && (\n <div id={labelId} data-slot=\"circular-progress-label\" className=\"text-sm\">\n {label}\n </div>\n )}\n </RootPrimitive>\n </CircularProgressContext.Provider>\n );\n}\n\nfunction CircularProgressIndicator(props: React.ComponentProps<\"svg\">) {\n const { className, ...indicatorProps } = props;\n\n const context = useCircularProgressContext(INDICATOR_NAME);\n\n return (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n viewBox={`0 0 ${context.size} ${context.size}`}\n data-state={context.state}\n data-value={context.value ?? undefined}\n data-max={context.max}\n data-min={context.min}\n data-percentage={context.percentage}\n data-slot=\"circular-progress-indicator\"\n width={context.size}\n height={context.size}\n {...indicatorProps}\n className={cn(\"-rotate-90 transform\", className)}\n />\n );\n}\n\nCircularProgressIndicator.displayName = INDICATOR_NAME;\n\nfunction CircularProgressTrack(props: React.ComponentProps<\"circle\">) {\n const { className, ...trackProps } = props;\n\n const context = useCircularProgressContext(TRACK_NAME);\n\n return (\n <circle\n data-state={context.state}\n data-slot=\"circular-progress-track\"\n cx={context.center}\n cy={context.center}\n r={context.radius}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={context.thickness}\n strokeLinecap=\"round\"\n vectorEffect=\"non-scaling-stroke\"\n {...trackProps}\n className={cn(\n /*\n * GIỮ NGUYÊN thượng nguồn — rãnh xám trung tính `text-muted-foreground/20`, KHÔNG phải tint\n * `/20` của bậc ink như rãnh `Progress`. Đã đo cả hai; thứ mang THÔNG TIN ở đây là ranh\n * giới cung-đã-chạy ⇄ rãnh (chỗ cung dừng lại chính là giá trị), và rãnh trung tính giữ\n * ranh giới đó TỐT HƠN (bảng tương phản cao, cung `text-primary-ink`):\n *\n * rãnh trung tính tint `primary-ink/20`\n * cung ⇄ rãnh trên --background : 5,03 (L) · 9,65 (D) 4,85 (L) · 7,97 (D)\n * tệ nhất, rãnh trên --muted : 4,71 (L) · 8,00 (D) 4,54 (L) · 6,52 (D)\n * (viền trang trí --border : 2,62 (L) ✗ — loại)\n *\n * Và nó không phụ thuộc tông: app đổi cung sang `text-success-ink`/`text-destructive-ink`\n * thì rãnh vẫn đúng (5,03 · 5,51:1 trên nền trắng) mà không phải đổi theo.\n *\n * Rãnh ⇄ nền trang chỉ ~1,3:1 — CỐ Ý, như rãnh `Progress`: không có cặp màu nào vừa ≥3:1\n * với nhau vừa ≥3:1 với nền trắng (chứng minh ở chú thích `Slider`). Khác `Progress` ở chỗ\n * vòng KHÔNG cần viền khoanh mốc 100%: hình tròn tự khép và cung luôn bắt đầu ở 12 giờ, nên\n * TỈ LỆ đọc được từ góc của cung mà không cần thấy rãnh. Một nét tròn liền, không nét nào\n * cắt nhau, nên màu có alpha không để lộ vệt nối (xem \"Cạm bẫy\" về icon trong CLAUDE.md).\n */\n \"text-muted-foreground/20\",\n className\n )}\n />\n );\n}\n\nfunction CircularProgressRange(props: React.ComponentProps<\"circle\">) {\n const { className, ...rangeProps } = props;\n\n const context = useCircularProgressContext(RANGE_NAME);\n\n const strokeDasharray = context.circumference;\n const strokeDashoffset =\n context.state === \"indeterminate\"\n ? context.circumference * 0.75\n : context.percentage !== null\n ? context.circumference - context.percentage * context.circumference\n : context.circumference;\n\n return (\n <circle\n data-state={context.state}\n data-value={context.value ?? undefined}\n data-max={context.max}\n data-min={context.min}\n data-slot=\"circular-progress-range\"\n cx={context.center}\n cy={context.center}\n r={context.radius}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={context.thickness}\n strokeLinecap=\"round\"\n strokeDasharray={strokeDasharray}\n strokeDashoffset={strokeDashoffset}\n vectorEffect=\"non-scaling-stroke\"\n {...rangeProps}\n className={cn(\n /*\n * ⚠ Khác thượng nguồn: `text-primary` (bậc TÔ NỀN, gold #E8B824 chỉ 1,86:1 trên nền trắng)\n * → `text-primary-ink`, đúng bậc của thanh `Progress`: 6,51:1 (light) · 12,67:1 (dark)\n * trên --background, tệ nhất 6,09:1 · 10,80:1 trên --muted (bảng tương phản cao). Cung là\n * thông tin thị giác (WCAG 1.4.11, 3:1).\n * Hiệu ứng quay đọc `--animate-spin-around` của styles.css; `motion-reduce` thì đứng yên.\n */\n \"origin-center text-primary-ink transition-all duration-300 ease-in-out\",\n context.state === \"indeterminate\" &&\n \"motion-safe:[animation:var(--animate-spin-around)] motion-reduce:animate-none\",\n className\n )}\n />\n );\n}\n\ninterface CircularProgressValueTextProps extends React.ComponentProps<\"span\"> {\n asChild?: boolean;\n}\n\nfunction CircularProgressValueText(props: CircularProgressValueTextProps) {\n const { asChild, className, children, ...valueTextProps } = props;\n\n const context = useCircularProgressContext(VALUE_TEXT_NAME);\n\n const ValueTextPrimitive = asChild ? Slot : \"span\";\n\n return (\n <ValueTextPrimitive\n id={context.valueTextId}\n data-state={context.state}\n data-slot=\"circular-progress-value-text\"\n {...valueTextProps}\n className={cn(\"absolute inset-0 flex items-center justify-center text-sm font-medium\", className)}\n >\n {children ?? context.valueText}\n </ValueTextPrimitive>\n );\n}\n\nfunction CircularProgressCombined(props: CircularProgressProps) {\n return (\n <CircularProgress {...props}>\n <CircularProgressIndicator>\n <CircularProgressTrack />\n <CircularProgressRange />\n </CircularProgressIndicator>\n <CircularProgressValueText />\n </CircularProgress>\n );\n}\n\nexport {\n CircularProgress,\n CircularProgressCombined,\n CircularProgressIndicator,\n type CircularProgressProps,\n CircularProgressRange,\n CircularProgressTrack,\n CircularProgressValueText,\n type CircularProgressValueTextProps\n};\n"],"mappings":";AAoMM,SAwBI,KAxBJ;AA7LN,SAAS,YAAY;AACrB,YAAY,WAAW;AACvB,SAAS,UAAU;AAEnB,MAAM,yBAAyB;AAC/B,MAAM,iBAAiB;AACvB,MAAM,aAAa;AACnB,MAAM,aAAa;AACnB,MAAM,kBAAkB;AAExB,MAAM,cAAc;AAQpB,MAAM,SAAS,OAAO,YAAY,eAAe,QAAQ,IAAI,aAAa;AAI1E,SAAS,iBAAiB,OAAkC,UAAiC;AAC3F,SAAO,SAAS,OAAO,kBAAkB,UAAU,WAAW,aAAa;AAC7E;AAEA,SAAS,iBAAiB,OAAiC;AACzD,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK;AAC3D;AAEA,SAAS,oBAAoB,KAA6B;AACxD,SAAO,iBAAiB,GAAG,KAAK,MAAM;AACxC;AAEA,SAAS,sBAAsB,OAAgB,KAAa,KAA8B;AACxF,SAAO,iBAAiB,KAAK,KAAK,SAAS,OAAO,SAAS;AAC7D;AAEA,SAAS,oBAAoB,OAAe,KAAa,KAAqB;AAC5E,QAAM,aAAa,QAAQ,MAAM,OAAQ,QAAQ,QAAQ,MAAM,OAAQ;AACvE,SAAO,GAAG,KAAK,MAAM,UAAU,CAAC;AAClC;AAEA,SAAS,qBAAqB,WAAmB,eAA+B;AAC9E,SAAO,sBAAsB,SAAS,wBAAmB,aAAa;AACxE;AAEA,SAAS,mBAAmB,WAAmB,eAA+B;AAC5E,SAAO,oBAAoB,SAAS,wBAAmB,aAAa,uHAA0D,WAAW;AAC3I;AAiBA,MAAM,0BAA0B,MAAM,cAAmD,IAAI;AAE7F,SAAS,2BAA2B,cAAsB;AACxD,QAAM,UAAU,MAAM,WAAW,uBAAuB;AACxD,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,KAAK,YAAY,wCAA2B,sBAAsB,IAAI;AAAA,EACxF;AACA,SAAO;AACT;AAqCA,SAAS,iBAAiB,OAA8B;AACtD,QAAM;AAAA,IACJ,OAAO,YAAY;AAAA,IACnB,eAAe;AAAA,IACf,KAAK,UAAU;AAAA,IACf,KAAK;AAAA,IACL,OAAO;AAAA,IACP,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL,IAAI;AAEJ,OAAK,WAAW,YAAY,MAAM,CAAC,oBAAoB,OAAO,GAAG;AAC/D,QAAI,QAAQ;AACV,cAAQ,MAAM,mBAAmB,GAAG,OAAO,IAAI,sBAAsB,CAAC;AAAA,IACxE;AAAA,EACF;AAEA,QAAM,SAAS,oBAAoB,OAAO,IAAI,UAAU;AACxD,QAAM,MAAM,iBAAiB,OAAO,IAAI,UAAU;AAClD,QAAM,MAAM,UAAU,MAAM,MAAM,IAAI;AAEtC,MAAI,UAAU,aAAa,MAAM;AAC/B,YAAQ;AAAA,MACN,oCAAoC,SAAS,2CAA4B,IAAI;AAAA,IAC/E;AAAA,EACF;AAEA,MAAI,cAAc,QAAQ,CAAC,sBAAsB,WAAW,KAAK,GAAG,GAAG;AACrE,QAAI,QAAQ;AACV,cAAQ,MAAM,qBAAqB,GAAG,SAAS,IAAI,sBAAsB,CAAC;AAAA,IAC5E;AAAA,EACF;AAEA,QAAM,QAAQ,sBAAsB,WAAW,KAAK,GAAG,IACnD,YACA,iBAAiB,SAAS,KAAK,YAAY,MACzC,MACA,iBAAiB,SAAS,KAAK,YAAY,MACzC,MACA;AAER,QAAM,YAAY,iBAAiB,KAAK,IAAI,aAAa,OAAO,KAAK,GAAG,IAAI;AAC5E,QAAM,QAAQ,iBAAiB,OAAO,GAAG;AACzC,QAAM,SAAS,KAAK,IAAI,IAAI,OAAO,aAAa,CAAC;AACjD,QAAM,SAAS,OAAO;AACtB,QAAM,gBAAgB,IAAI,KAAK,KAAK;AAEpC,QAAM,aAAa,iBAAiB,KAAK,IAAK,QAAQ,MAAM,KAAK,QAAQ,QAAQ,MAAM,OAAQ;AAE/F,QAAM,UAAU,MAAM,MAAM;AAC5B,QAAM,cAAc,MAAM,MAAM;AAEhC,QAAM,eAAe,MAAM;AAAA,IACzB,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,OAAO,WAAW,KAAK,KAAK,OAAO,QAAQ,WAAW,MAAM,QAAQ,eAAe,YAAY,WAAW;AAAA,EAC7G;AAEA,QAAM,gBAAgB,UAAU,OAAO;AAEvC,SACE,oBAAC,wBAAwB,UAAxB,EAAiC,OAAO,cACvC;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,oBAAkB,YAAY,cAAc;AAAA,MAC5C,mBAAiB,QAAQ,UAAU;AAAA,MACnC,iBAAe;AAAA,MACf,iBAAe;AAAA,MACf,iBAAe,iBAAiB,KAAK,IAAI,QAAQ;AAAA,MACjD,kBAAgB;AAAA,MAChB,cAAY;AAAA,MACZ,cAAY,SAAS;AAAA,MACrB,YAAU;AAAA,MACV,YAAU;AAAA,MACV,mBAAiB;AAAA,MACjB,aAAU;AAAA,MACT,GAAG;AAAA,MACJ,WAAW,GAAG,0DAA0D,SAAS,oBAAoB,SAAS;AAAA,MAQ7G;AAAA,gBACC,oBAAC,SAAI,aAAU,0BAAyB,WAAU,oDAC/C,UACH,IAEA;AAAA,QAED,SACC,oBAAC,SAAI,IAAI,SAAS,aAAU,2BAA0B,WAAU,WAC7D,iBACH;AAAA;AAAA;AAAA,EAEJ,GACF;AAEJ;AAEA,SAAS,0BAA0B,OAAoC;AACrE,QAAM,EAAE,WAAW,GAAG,eAAe,IAAI;AAEzC,QAAM,UAAU,2BAA2B,cAAc;AAEzD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAY;AAAA,MACZ,WAAU;AAAA,MACV,SAAS,OAAO,QAAQ,IAAI,IAAI,QAAQ,IAAI;AAAA,MAC5C,cAAY,QAAQ;AAAA,MACpB,cAAY,QAAQ,SAAS;AAAA,MAC7B,YAAU,QAAQ;AAAA,MAClB,YAAU,QAAQ;AAAA,MAClB,mBAAiB,QAAQ;AAAA,MACzB,aAAU;AAAA,MACV,OAAO,QAAQ;AAAA,MACf,QAAQ,QAAQ;AAAA,MACf,GAAG;AAAA,MACJ,WAAW,GAAG,wBAAwB,SAAS;AAAA;AAAA,EACjD;AAEJ;AAEA,0BAA0B,cAAc;AAExC,SAAS,sBAAsB,OAAuC;AACpE,QAAM,EAAE,WAAW,GAAG,WAAW,IAAI;AAErC,QAAM,UAAU,2BAA2B,UAAU;AAErD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,cAAY,QAAQ;AAAA,MACpB,aAAU;AAAA,MACV,IAAI,QAAQ;AAAA,MACZ,IAAI,QAAQ;AAAA,MACZ,GAAG,QAAQ;AAAA,MACX,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAa,QAAQ;AAAA,MACrB,eAAc;AAAA,MACd,cAAa;AAAA,MACZ,GAAG;AAAA,MACJ,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAqBT;AAAA,QACA;AAAA,MACF;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,sBAAsB,OAAuC;AACpE,QAAM,EAAE,WAAW,GAAG,WAAW,IAAI;AAErC,QAAM,UAAU,2BAA2B,UAAU;AAErD,QAAM,kBAAkB,QAAQ;AAChC,QAAM,mBACJ,QAAQ,UAAU,kBACd,QAAQ,gBAAgB,OACxB,QAAQ,eAAe,OACrB,QAAQ,gBAAgB,QAAQ,aAAa,QAAQ,gBACrD,QAAQ;AAEhB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,cAAY,QAAQ;AAAA,MACpB,cAAY,QAAQ,SAAS;AAAA,MAC7B,YAAU,QAAQ;AAAA,MAClB,YAAU,QAAQ;AAAA,MAClB,aAAU;AAAA,MACV,IAAI,QAAQ;AAAA,MACZ,IAAI,QAAQ;AAAA,MACZ,GAAG,QAAQ;AAAA,MACX,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAa,QAAQ;AAAA,MACrB,eAAc;AAAA,MACd;AAAA,MACA;AAAA,MACA,cAAa;AAAA,MACZ,GAAG;AAAA,MACJ,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAQT;AAAA,QACA,QAAQ,UAAU,mBAChB;AAAA,QACF;AAAA,MACF;AAAA;AAAA,EACF;AAEJ;AAMA,SAAS,0BAA0B,OAAuC;AACxE,QAAM,EAAE,SAAS,WAAW,UAAU,GAAG,eAAe,IAAI;AAE5D,QAAM,UAAU,2BAA2B,eAAe;AAE1D,QAAM,qBAAqB,UAAU,OAAO;AAE5C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,IAAI,QAAQ;AAAA,MACZ,cAAY,QAAQ;AAAA,MACpB,aAAU;AAAA,MACT,GAAG;AAAA,MACJ,WAAW,GAAG,yEAAyE,SAAS;AAAA,MAE/F,sBAAY,QAAQ;AAAA;AAAA,EACvB;AAEJ;AAEA,SAAS,yBAAyB,OAA8B;AAC9D,SACE,qBAAC,oBAAkB,GAAG,OACpB;AAAA,yBAAC,6BACC;AAAA,0BAAC,yBAAsB;AAAA,MACvB,oBAAC,yBAAsB;AAAA,OACzB;AAAA,IACA,oBAAC,6BAA0B;AAAA,KAC7B;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/ui/circular-progress.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/circular-progress) — MIT, © 2024 Sadman Sakib.\n * Giữ nguyên cấu trúc thượng nguồn để còn đối chiếu ngược được; mọi chỗ đổi đều có chú thích.\n */\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn.js\";\nimport { useIsomorphicLayoutEffect } from \"../../lib/use-isomorphic-layout-effect.js\";\n\nconst CIRCULAR_PROGRESS_NAME = \"CircularProgress\";\nconst INDICATOR_NAME = \"CircularProgressIndicator\";\nconst TRACK_NAME = \"CircularProgressTrack\";\nconst RANGE_NAME = \"CircularProgressRange\";\nconst VALUE_TEXT_NAME = \"CircularProgressValueText\";\n\nconst DEFAULT_MAX = 100;\n\n/*\n * ⚠ Khác thượng nguồn: bản gốc đọc thẳng `process.env.NODE_ENV` ngay trong lúc render. Gói ra ESM\n * từng file, không bundle; ở môi trường không có bundler thay chuỗi đó (ESM thuần trên trình\n * duyệt), `process` không tồn tại → ReferenceError lúc render. Bọc `typeof` để chỗ đó chỉ mất cảnh\n * báo dev chứ không gãy; bundler vẫn thay `process.env.NODE_ENV` và loại nhánh dev như cũ.\n */\nconst IS_DEV = typeof process !== \"undefined\" && process.env.NODE_ENV !== \"production\";\n\ntype ProgressState = \"indeterminate\" | \"complete\" | \"loading\";\n\nfunction getProgressState(value: number | undefined | null, maxValue: number): ProgressState {\n return value == null ? \"indeterminate\" : value === maxValue ? \"complete\" : \"loading\";\n}\n\nfunction getIsValidNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction getIsValidMaxNumber(max: unknown): max is number {\n return getIsValidNumber(max) && max > 0;\n}\n\nfunction getIsValidValueNumber(value: unknown, min: number, max: number): value is number {\n return getIsValidNumber(value) && value <= max && value >= min;\n}\n\nfunction getDefaultValueText(value: number, min: number, max: number): string {\n const percentage = max === min ? 100 : ((value - min) / (max - min)) * 100;\n return `${Math.round(percentage)}%`;\n}\n\nfunction getInvalidValueError(propValue: string, componentName: string): string {\n // i18n-ignore: thông điệp cho LẬP TRÌNH VIÊN (đi vào console.error), không phải chữ hiển thị\n return `Prop \\`value\\` = \\`${propValue}\\` truyền cho \\`${componentName}\\` không hợp lệ. \\`value\\` phải là số trong khoảng \\`min\\`…\\`max\\` (tính cả hai đầu), hoặc \\`null\\`/\\`undefined\\` cho tiến trình không xác định. Giá trị sẽ bị kẹp về khoảng hợp lệ.`;\n}\n\nfunction getInvalidMaxError(propValue: string, componentName: string): string {\n // i18n-ignore: thông điệp cho LẬP TRÌNH VIÊN (đi vào console.error), không phải chữ hiển thị\n return `Prop \\`max\\` = \\`${propValue}\\` truyền cho \\`${componentName}\\` không hợp lệ. Chỉ nhận số lớn hơn 0 — dùng mặc định ${DEFAULT_MAX}.`;\n}\n\ninterface CircularProgressContextValue {\n value: number | null;\n valueText: string | undefined;\n max: number;\n min: number;\n state: ProgressState;\n radius: number;\n thickness: number;\n size: number;\n center: number;\n circumference: number;\n percentage: number | null;\n valueTextId?: string;\n /** `CircularProgressValueText` báo nó đang có mặt — xem chú thích ở `aria-describedby`. */\n onValueTextMountChange: (mounted: boolean) => void;\n}\n\nconst CircularProgressContext = React.createContext<CircularProgressContextValue | null>(null);\n\nfunction useCircularProgressContext(consumerName: string) {\n const context = React.useContext(CircularProgressContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${CIRCULAR_PROGRESS_NAME}\\``);\n }\n return context;\n}\n\ninterface CircularProgressProps extends React.ComponentProps<\"div\"> {\n /** Giá trị hiện tại; `null`/`undefined` = không xác định (vòng quay). */\n value?: number | null | undefined;\n /**\n * Chuỗi trình đọc màn hình đọc thay cho con số (`aria-valuetext`) và chữ giữa vòng — mặc định\n * phần trăm làm tròn, vd `\"45%\"`.\n */\n getValueText?(value: number, min: number, max: number): string;\n min?: number;\n max?: number;\n /** Đường kính, px. */\n size?: number;\n /** Độ dày nét, px. */\n thickness?: number;\n /**\n * Nhãn HIỆN của vòng, đồng thời là tên của `role=\"progressbar\"`. Không đặt nhãn hiện thì PHẢI\n * truyền `aria-label` — progressbar không tên là lỗi a11y (ARIA 1.2), gói không tự đặt tên\n * chung chung thay app (giống `Progress`).\n */\n label?: string;\n asChild?: boolean;\n}\n\n/**\n * CircularProgress — tiến trình dạng VÒNG, cặp với `Progress` (dạng thanh) của gói.\n * Ráp từ các phần (`CircularProgressIndicator` › `Track` + `Range`, `CircularProgressValueText`),\n * hoặc dùng sẵn `CircularProgressCombined`.\n *\n * Phần đã chạy là `text-primary-ink`, cùng bậc với thanh `Progress`; rãnh xám trung tính. Đổi tông\n * thì truyền bậc INK cho `CircularProgressRange` (vd `className=\"text-success-ink\"`), không phải\n * token tô nền `text-success` — rãnh không cần đổi theo (số đo ở `CircularProgressTrack`).\n *\n * ⚠ Trạng thái không xác định cần `--animate-spin-around` + `@keyframes spin-around` trong\n * styles.css; thiếu thì vòng đứng yên ở một cung 25% (không lỗi, không cảnh báo).\n */\nfunction CircularProgress(props: CircularProgressProps) {\n const {\n value: valueProp = null,\n getValueText = getDefaultValueText,\n min: minProp = 0,\n max: maxProp,\n size = 48,\n thickness = 4,\n label,\n asChild,\n className,\n children,\n ...rootProps\n } = props;\n\n if ((maxProp || maxProp === 0) && !getIsValidMaxNumber(maxProp)) {\n if (IS_DEV) {\n console.error(getInvalidMaxError(`${maxProp}`, CIRCULAR_PROGRESS_NAME));\n }\n }\n\n const rawMax = getIsValidMaxNumber(maxProp) ? maxProp : DEFAULT_MAX;\n const min = getIsValidNumber(minProp) ? minProp : 0;\n const max = rawMax <= min ? min + 1 : rawMax;\n\n if (IS_DEV && thickness >= size) {\n console.warn(\n `CircularProgress: \\`thickness\\` (${thickness}) phải nhỏ hơn \\`size\\` (${size}) thì vòng mới vẽ đúng.`\n );\n }\n\n if (valueProp !== null && !getIsValidValueNumber(valueProp, min, max)) {\n if (IS_DEV) {\n console.error(getInvalidValueError(`${valueProp}`, CIRCULAR_PROGRESS_NAME));\n }\n }\n\n const value = getIsValidValueNumber(valueProp, min, max)\n ? valueProp\n : getIsValidNumber(valueProp) && valueProp > max\n ? max\n : getIsValidNumber(valueProp) && valueProp < min\n ? min\n : null;\n\n const valueText = getIsValidNumber(value) ? getValueText(value, min, max) : undefined;\n const state = getProgressState(value, max);\n const radius = Math.max(0, (size - thickness) / 2);\n const center = size / 2;\n const circumference = 2 * Math.PI * radius;\n\n const percentage = getIsValidNumber(value) ? (max === min ? 1 : (value - min) / (max - min)) : null;\n\n const labelId = React.useId();\n const valueTextId = React.useId();\n const [hasValueText, setHasValueText] = React.useState(false);\n\n const contextValue = React.useMemo<CircularProgressContextValue>(\n () => ({\n value,\n valueText,\n max,\n min,\n state,\n radius,\n thickness,\n size,\n center,\n circumference,\n percentage,\n valueTextId,\n onValueTextMountChange: setHasValueText\n }),\n [value, valueText, max, min, state, radius, thickness, size, center, circumference, percentage, valueTextId]\n );\n\n const RootPrimitive = asChild ? Slot : \"div\";\n\n return (\n <CircularProgressContext.Provider value={contextValue}>\n <RootPrimitive\n role=\"progressbar\"\n /*\n * ⚠ Khác thượng nguồn (3.0.1): chỉ trỏ tới phần chữ giá trị khi `CircularProgressValueText`\n * THẬT SỰ có trên trang. Bản gốc luôn đặt `aria-describedby` khi có giá trị — vòng không vẽ\n * chữ (chỉ vòng, hay nhãn ở chỗ khác) thì thuộc tính trỏ vào một id không phần tử nào mang\n * (axe: \"aria-describedby references an element that does not exist\"). Giá trị vẫn đi qua\n * `aria-valuetext` như cũ.\n */\n aria-describedby={valueText && hasValueText ? valueTextId : undefined}\n aria-labelledby={label ? labelId : undefined}\n aria-valuemax={max}\n aria-valuemin={min}\n aria-valuenow={getIsValidNumber(value) ? value : undefined}\n aria-valuetext={valueText}\n data-state={state}\n data-value={value ?? undefined}\n data-max={max}\n data-min={min}\n data-percentage={percentage}\n data-slot=\"circular-progress\"\n {...rootProps}\n className={cn(\"relative inline-flex w-fit items-center justify-center\", label && \"flex-col gap-1.5\", className)}\n >\n {/*\n * ⚠ Khác thượng nguồn: bản gốc đặt nhãn làm anh em của vòng NGAY TRONG gốc, trong khi\n * `CircularProgressValueText` là `absolute inset-0` phủ CẢ gốc — có nhãn là chữ \"65%\" đè\n * lên chữ nhãn. Khi có `label`: bọc phần con trong một khung đúng cỡ vòng (`relative`, nên\n * chữ giá trị căn giữa VÒNG), nhãn xuống dưới vòng. Không có `label` thì DOM y như bản gốc.\n */}\n {label ? (\n <div data-slot=\"circular-progress-ring\" className=\"relative inline-flex items-center justify-center\">\n {children}\n </div>\n ) : (\n children\n )}\n {label && (\n <div id={labelId} data-slot=\"circular-progress-label\" className=\"text-sm\">\n {label}\n </div>\n )}\n </RootPrimitive>\n </CircularProgressContext.Provider>\n );\n}\n\nfunction CircularProgressIndicator(props: React.ComponentProps<\"svg\">) {\n const { className, ...indicatorProps } = props;\n\n const context = useCircularProgressContext(INDICATOR_NAME);\n\n return (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n viewBox={`0 0 ${context.size} ${context.size}`}\n data-state={context.state}\n data-value={context.value ?? undefined}\n data-max={context.max}\n data-min={context.min}\n data-percentage={context.percentage}\n data-slot=\"circular-progress-indicator\"\n width={context.size}\n height={context.size}\n {...indicatorProps}\n className={cn(\"-rotate-90 transform\", className)}\n />\n );\n}\n\nCircularProgressIndicator.displayName = INDICATOR_NAME;\n\nfunction CircularProgressTrack(props: React.ComponentProps<\"circle\">) {\n const { className, ...trackProps } = props;\n\n const context = useCircularProgressContext(TRACK_NAME);\n\n return (\n <circle\n data-state={context.state}\n data-slot=\"circular-progress-track\"\n cx={context.center}\n cy={context.center}\n r={context.radius}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={context.thickness}\n strokeLinecap=\"round\"\n vectorEffect=\"non-scaling-stroke\"\n {...trackProps}\n className={cn(\n /*\n * GIỮ NGUYÊN thượng nguồn — rãnh xám trung tính `text-muted-foreground/20`, KHÔNG phải tint\n * `/20` của bậc ink như rãnh `Progress`. Đã đo cả hai; thứ mang THÔNG TIN ở đây là ranh\n * giới cung-đã-chạy ⇄ rãnh (chỗ cung dừng lại chính là giá trị), và rãnh trung tính giữ\n * ranh giới đó TỐT HƠN (bảng tương phản cao, cung `text-primary-ink`):\n *\n * rãnh trung tính tint `primary-ink/20`\n * cung ⇄ rãnh trên --background : 5,03 (L) · 9,65 (D) 4,85 (L) · 7,97 (D)\n * tệ nhất, rãnh trên --muted : 4,71 (L) · 8,00 (D) 4,54 (L) · 6,52 (D)\n * (viền trang trí --border : 2,62 (L) ✗ — loại)\n *\n * Và nó không phụ thuộc tông: app đổi cung sang `text-success-ink`/`text-destructive-ink`\n * thì rãnh vẫn đúng (5,03 · 5,51:1 trên nền trắng) mà không phải đổi theo.\n *\n * Rãnh ⇄ nền trang chỉ ~1,3:1 — CỐ Ý, như rãnh `Progress`: không có cặp màu nào vừa ≥3:1\n * với nhau vừa ≥3:1 với nền trắng (chứng minh ở chú thích `Slider`). Khác `Progress` ở chỗ\n * vòng KHÔNG cần viền khoanh mốc 100%: hình tròn tự khép và cung luôn bắt đầu ở 12 giờ, nên\n * TỈ LỆ đọc được từ góc của cung mà không cần thấy rãnh. Một nét tròn liền, không nét nào\n * cắt nhau, nên màu có alpha không để lộ vệt nối (xem \"Cạm bẫy\" về icon trong CLAUDE.md).\n */\n \"text-muted-foreground/20\",\n className\n )}\n />\n );\n}\n\nfunction CircularProgressRange(props: React.ComponentProps<\"circle\">) {\n const { className, ...rangeProps } = props;\n\n const context = useCircularProgressContext(RANGE_NAME);\n\n const strokeDasharray = context.circumference;\n const strokeDashoffset =\n context.state === \"indeterminate\"\n ? context.circumference * 0.75\n : context.percentage !== null\n ? context.circumference - context.percentage * context.circumference\n : context.circumference;\n\n return (\n <circle\n data-state={context.state}\n data-value={context.value ?? undefined}\n data-max={context.max}\n data-min={context.min}\n data-slot=\"circular-progress-range\"\n cx={context.center}\n cy={context.center}\n r={context.radius}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={context.thickness}\n strokeLinecap=\"round\"\n strokeDasharray={strokeDasharray}\n strokeDashoffset={strokeDashoffset}\n vectorEffect=\"non-scaling-stroke\"\n {...rangeProps}\n className={cn(\n /*\n * ⚠ Khác thượng nguồn: `text-primary` (bậc TÔ NỀN, gold #E8B824 chỉ 1,86:1 trên nền trắng)\n * → `text-primary-ink`, đúng bậc của thanh `Progress`: 6,51:1 (light) · 12,67:1 (dark)\n * trên --background, tệ nhất 6,09:1 · 10,80:1 trên --muted (bảng tương phản cao). Cung là\n * thông tin thị giác (WCAG 1.4.11, 3:1).\n * Hiệu ứng quay đọc `--animate-spin-around` của styles.css; `motion-reduce` thì đứng yên.\n */\n \"origin-center text-primary-ink transition-all duration-300 ease-in-out\",\n context.state === \"indeterminate\" &&\n \"motion-safe:[animation:var(--animate-spin-around)] motion-reduce:animate-none\",\n className\n )}\n />\n );\n}\n\ninterface CircularProgressValueTextProps extends React.ComponentProps<\"span\"> {\n asChild?: boolean;\n}\n\nfunction CircularProgressValueText(props: CircularProgressValueTextProps) {\n const { asChild, className, children, ...valueTextProps } = props;\n\n const context = useCircularProgressContext(VALUE_TEXT_NAME);\n const { onValueTextMountChange } = context;\n\n useIsomorphicLayoutEffect(() => {\n onValueTextMountChange(true);\n return () => onValueTextMountChange(false);\n }, [onValueTextMountChange]);\n\n const ValueTextPrimitive = asChild ? Slot : \"span\";\n\n return (\n <ValueTextPrimitive\n id={context.valueTextId}\n data-state={context.state}\n data-slot=\"circular-progress-value-text\"\n {...valueTextProps}\n className={cn(\"absolute inset-0 flex items-center justify-center text-sm font-medium\", className)}\n >\n {children ?? context.valueText}\n </ValueTextPrimitive>\n );\n}\n\nfunction CircularProgressCombined(props: CircularProgressProps) {\n return (\n <CircularProgress {...props}>\n <CircularProgressIndicator>\n <CircularProgressTrack />\n <CircularProgressRange />\n </CircularProgressIndicator>\n <CircularProgressValueText />\n </CircularProgress>\n );\n}\n\nexport {\n CircularProgress,\n CircularProgressCombined,\n CircularProgressIndicator,\n type CircularProgressProps,\n CircularProgressRange,\n CircularProgressTrack,\n CircularProgressValueText,\n type CircularProgressValueTextProps\n};\n"],"mappings":"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","names":[]}
@@ -10,19 +10,20 @@ import '@radix-ui/react-dialog';
10
10
  * từ đây. `CommandDialog` bọc sẵn trong `Dialog` cho bảng lệnh Cmd/Ctrl+K.
11
11
  *
12
12
  * Lưu ý a11y: `CommandDialog` bắt buộc có tiêu đề + mô tả cho trình đọc màn hình
13
- * (đặt trong `DialogHeader` ẩn `sr-only`) — đổi bằng prop `title`/`description`.
13
+ * (đặt trong `DialogHeader` ẩn `sr-only`) — mặc định theo `ComitorLocaleProvider` (namespace
14
+ * `command`), đổi riêng bằng prop `title`/`description`.
14
15
  */
15
16
  type CommandProps = React.ComponentProps<typeof Command$1>;
16
17
  declare function Command({ className, ...props }: CommandProps): React.JSX.Element;
17
18
  type CommandDialogProps = React.ComponentProps<typeof Dialog> & {
18
- /** Tiêu đề cho trình đọc màn hình. Mặc định "Bảng lệnh". */
19
+ /** Tiêu đề cho trình đọc màn hình. Mặc định: khoá `dialogTitle` của namespace `command`. */
19
20
  title?: string;
20
- /** Mô tả cho trình đọc màn hình. Mặc định "Tìm và chạy một lệnh…". */
21
+ /** Mô tả cho trình đọc màn hình. Mặc định: khoá `dialogDescription` của namespace `command`. */
21
22
  description?: string;
22
23
  className?: string;
23
24
  showCloseButton?: boolean;
24
25
  };
25
- declare function CommandDialog({ title, description, children, className, showCloseButton, ...props }: CommandDialogProps): React.JSX.Element;
26
+ declare function CommandDialog({ title: titleProp, description: descriptionProp, children, className, showCloseButton, ...props }: CommandDialogProps): React.JSX.Element;
26
27
  type CommandInputProps = React.ComponentProps<typeof Command$1.Input>;
27
28
  declare function CommandInput({ className, ...props }: CommandInputProps): React.JSX.Element;
28
29
  type CommandListProps = React.ComponentProps<typeof Command$1.List>;
@@ -2,6 +2,7 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { Command as CommandPrimitive } from "cmdk";
4
4
  import { SearchIcon } from "lucide-react";
5
+ import { useComitorMessages } from "../../i18n/locale-provider.js";
5
6
  import { cn } from "../../lib/cn.js";
6
7
  import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "./dialog.js";
7
8
  function Command({ className, ...props }) {
@@ -18,13 +19,16 @@ function Command({ className, ...props }) {
18
19
  );
19
20
  }
20
21
  function CommandDialog({
21
- title = "B\u1EA3ng l\u1EC7nh",
22
- description = "T\xECm v\xE0 ch\u1EA1y m\u1ED9t l\u1EC7nh\u2026",
22
+ title: titleProp,
23
+ description: descriptionProp,
23
24
  children,
24
25
  className,
25
26
  showCloseButton = true,
26
27
  ...props
27
28
  }) {
29
+ const t = useComitorMessages("command");
30
+ const title = titleProp ?? t.dialogTitle;
31
+ const description = descriptionProp ?? t.dialogDescription;
28
32
  return /* @__PURE__ */ jsxs(Dialog, { ...props, children: [
29
33
  /* @__PURE__ */ jsxs(DialogHeader, { className: "sr-only", children: [
30
34
  /* @__PURE__ */ jsx(DialogTitle, { children: title }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/ui/command.tsx"],"sourcesContent":["\"use client\";\n\nimport { Command as CommandPrimitive } from \"cmdk\";\nimport { SearchIcon } from \"lucide-react\";\nimport type * as React from \"react\";\nimport { cn } from \"../../lib/cn.js\";\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from \"./dialog.js\";\n\n/**\n * Command — danh sách lệnh có lọc theo phím gõ (cmdk).\n *\n * Đây là primitive trần: composite `CommandPalette` và `Combobox` (Tier 2) dựng lên\n * từ đây. `CommandDialog` bọc sẵn trong `Dialog` cho bảng lệnh Cmd/Ctrl+K.\n *\n * Lưu ý a11y: `CommandDialog` bắt buộc có tiêu đề + mô tả cho trình đọc màn hình\n * (đặt trong `DialogHeader` ẩn `sr-only`) — đổi bằng prop `title`/`description`.\n */\n\nexport type CommandProps = React.ComponentProps<typeof CommandPrimitive>;\n\nfunction Command({ className, ...props }: CommandProps) {\n return (\n <CommandPrimitive\n data-slot=\"command\"\n className={cn(\n \"bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport type CommandDialogProps = React.ComponentProps<typeof Dialog> & {\n /** Tiêu đề cho trình đọc màn hình. Mặc định \"Bảng lệnh\". */\n title?: string;\n /** Mô tả cho trình đọc màn hình. Mặc định \"Tìm và chạy một lệnh…\". */\n description?: string;\n className?: string;\n showCloseButton?: boolean;\n};\n\nfunction CommandDialog({\n title = \"Bảng lệnh\",\n description = \"Tìm và chạy một lệnh…\",\n children,\n className,\n showCloseButton = true,\n ...props\n}: CommandDialogProps) {\n return (\n <Dialog {...props}>\n <DialogHeader className=\"sr-only\">\n <DialogTitle>{title}</DialogTitle>\n <DialogDescription>{description}</DialogDescription>\n </DialogHeader>\n <DialogContent className={cn(\"overflow-hidden p-0\", className)} showCloseButton={showCloseButton}>\n <Command className=\"[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5\">\n {children}\n </Command>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport type CommandInputProps = React.ComponentProps<typeof CommandPrimitive.Input>;\n\nfunction CommandInput({ className, ...props }: CommandInputProps) {\n return (\n <div data-slot=\"command-input-wrapper\" className=\"flex h-9 items-center gap-2 border-b px-3\">\n {/* Icon kính lúp là icon MANG NGHĨA (nói \"đây là ô tìm kiếm\") → ngưỡng 3:1.\n `opacity-50` cũ hạ màu kế thừa xuống 3,56:1 (light) / 4,99:1 (dark) — đạt nhưng sát,\n và là con số không token nào bảo vệ. `--muted-foreground` là bậc dành đúng cho vai trò\n này: 5,23:1 (light) · 5,35:1 (dark) trên nền popover. */}\n <SearchIcon className=\"size-4 shrink-0 opacity-50\" />\n <CommandPrimitive.Input\n data-slot=\"command-input\"\n className={cn(\n \"placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50\",\n className\n )}\n {...props}\n />\n </div>\n );\n}\n\nexport type CommandListProps = React.ComponentProps<typeof CommandPrimitive.List>;\n\nfunction CommandList({ className, ...props }: CommandListProps) {\n return (\n <CommandPrimitive.List\n data-slot=\"command-list\"\n className={cn(\"max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto\", className)}\n {...props}\n />\n );\n}\n\nexport type CommandEmptyProps = React.ComponentProps<typeof CommandPrimitive.Empty>;\n\nfunction CommandEmpty({ ...props }: CommandEmptyProps) {\n return <CommandPrimitive.Empty data-slot=\"command-empty\" className=\"py-6 text-center text-sm\" {...props} />;\n}\n\nexport type CommandGroupProps = React.ComponentProps<typeof CommandPrimitive.Group>;\n\nfunction CommandGroup({ className, ...props }: CommandGroupProps) {\n return (\n <CommandPrimitive.Group\n data-slot=\"command-group\"\n className={cn(\n \"text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport type CommandSeparatorProps = React.ComponentProps<typeof CommandPrimitive.Separator>;\n\nfunction CommandSeparator({ className, ...props }: CommandSeparatorProps) {\n return (\n <CommandPrimitive.Separator\n data-slot=\"command-separator\"\n className={cn(\"bg-border -mx-1 h-px\", className)}\n {...props}\n />\n );\n}\n\nexport type CommandItemProps = React.ComponentProps<typeof CommandPrimitive.Item>;\n\nfunction CommandItem({ className, ...props }: CommandItemProps) {\n return (\n <CommandPrimitive.Item\n data-slot=\"command-item\"\n className={cn(\n \"data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 mt-1 first:mt-0 rounded-sm px-2 py-(--menu-item-py) text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport type CommandShortcutProps = React.ComponentProps<\"span\">;\n\nfunction CommandShortcut({ className, ...props }: CommandShortcutProps) {\n return (\n <span\n data-slot=\"command-shortcut\"\n className={cn(\"text-muted-foreground ml-auto text-xs tracking-widest\", className)}\n {...props}\n />\n );\n}\n\nexport {\n Command,\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut\n};\n"],"mappings":";AAsBI,cA8BE,YA9BF;AApBJ,SAAS,WAAW,wBAAwB;AAC5C,SAAS,kBAAkB;AAE3B,SAAS,UAAU;AACnB,SAAS,QAAQ,eAAe,mBAAmB,cAAc,mBAAmB;AAcpF,SAAS,QAAQ,EAAE,WAAW,GAAG,MAAM,GAAiB;AACtD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAWA,SAAS,cAAc;AAAA,EACrB,QAAQ;AAAA,EACR,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,GAAG;AACL,GAAuB;AACrB,SACE,qBAAC,UAAQ,GAAG,OACV;AAAA,yBAAC,gBAAa,WAAU,WACtB;AAAA,0BAAC,eAAa,iBAAM;AAAA,MACpB,oBAAC,qBAAmB,uBAAY;AAAA,OAClC;AAAA,IACA,oBAAC,iBAAc,WAAW,GAAG,uBAAuB,SAAS,GAAG,iBAC9D,8BAAC,WAAQ,WAAU,yZAChB,UACH,GACF;AAAA,KACF;AAEJ;AAIA,SAAS,aAAa,EAAE,WAAW,GAAG,MAAM,GAAsB;AAChE,SACE,qBAAC,SAAI,aAAU,yBAAwB,WAAU,6CAK/C;AAAA,wBAAC,cAAW,WAAU,8BAA6B;AAAA,IACnD;AAAA,MAAC,iBAAiB;AAAA,MAAjB;AAAA,QACC,aAAU;AAAA,QACV,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,QACC,GAAG;AAAA;AAAA,IACN;AAAA,KACF;AAEJ;AAIA,SAAS,YAAY,EAAE,WAAW,GAAG,MAAM,GAAqB;AAC9D,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,+DAA+D,SAAS;AAAA,MACrF,GAAG;AAAA;AAAA,EACN;AAEJ;AAIA,SAAS,aAAa,EAAE,GAAG,MAAM,GAAsB;AACrD,SAAO,oBAAC,iBAAiB,OAAjB,EAAuB,aAAU,iBAAgB,WAAU,4BAA4B,GAAG,OAAO;AAC3G;AAIA,SAAS,aAAa,EAAE,WAAW,GAAG,MAAM,GAAsB;AAChE,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAIA,SAAS,iBAAiB,EAAE,WAAW,GAAG,MAAM,GAA0B;AACxE,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,wBAAwB,SAAS;AAAA,MAC9C,GAAG;AAAA;AAAA,EACN;AAEJ;AAIA,SAAS,YAAY,EAAE,WAAW,GAAG,MAAM,GAAqB;AAC9D,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAIA,SAAS,gBAAgB,EAAE,WAAW,GAAG,MAAM,GAAyB;AACtE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,yDAAyD,SAAS;AAAA,MAC/E,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/ui/command.tsx"],"sourcesContent":["\"use client\";\n\nimport { Command as CommandPrimitive } from \"cmdk\";\nimport { SearchIcon } from \"lucide-react\";\nimport type * as React from \"react\";\nimport { useComitorMessages } from \"../../i18n/locale-provider.js\";\nimport { cn } from \"../../lib/cn.js\";\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from \"./dialog.js\";\n\n/**\n * Command — danh sách lệnh có lọc theo phím gõ (cmdk).\n *\n * Đây là primitive trần: composite `CommandPalette` và `Combobox` (Tier 2) dựng lên\n * từ đây. `CommandDialog` bọc sẵn trong `Dialog` cho bảng lệnh Cmd/Ctrl+K.\n *\n * Lưu ý a11y: `CommandDialog` bắt buộc có tiêu đề + mô tả cho trình đọc màn hình\n * (đặt trong `DialogHeader` ẩn `sr-only`) — mặc định theo `ComitorLocaleProvider` (namespace\n * `command`), đổi riêng bằng prop `title`/`description`.\n */\n\nexport type CommandProps = React.ComponentProps<typeof CommandPrimitive>;\n\nfunction Command({ className, ...props }: CommandProps) {\n return (\n <CommandPrimitive\n data-slot=\"command\"\n className={cn(\n \"bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport type CommandDialogProps = React.ComponentProps<typeof Dialog> & {\n /** Tiêu đề cho trình đọc màn hình. Mặc định: khoá `dialogTitle` của namespace `command`. */\n title?: string;\n /** Mô tả cho trình đọc màn hình. Mặc định: khoá `dialogDescription` của namespace `command`. */\n description?: string;\n className?: string;\n showCloseButton?: boolean;\n};\n\nfunction CommandDialog({\n title: titleProp,\n description: descriptionProp,\n children,\n className,\n showCloseButton = true,\n ...props\n}: CommandDialogProps) {\n const t = useComitorMessages(\"command\");\n const title = titleProp ?? t.dialogTitle;\n const description = descriptionProp ?? t.dialogDescription;\n return (\n <Dialog {...props}>\n <DialogHeader className=\"sr-only\">\n <DialogTitle>{title}</DialogTitle>\n <DialogDescription>{description}</DialogDescription>\n </DialogHeader>\n <DialogContent className={cn(\"overflow-hidden p-0\", className)} showCloseButton={showCloseButton}>\n <Command className=\"[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5\">\n {children}\n </Command>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport type CommandInputProps = React.ComponentProps<typeof CommandPrimitive.Input>;\n\nfunction CommandInput({ className, ...props }: CommandInputProps) {\n return (\n <div data-slot=\"command-input-wrapper\" className=\"flex h-9 items-center gap-2 border-b px-3\">\n {/* Icon kính lúp là icon MANG NGHĨA (nói \"đây là ô tìm kiếm\") → ngưỡng 3:1.\n `opacity-50` cũ hạ màu kế thừa xuống 3,56:1 (light) / 4,99:1 (dark) — đạt nhưng sát,\n và là con số không token nào bảo vệ. `--muted-foreground` là bậc dành đúng cho vai trò\n này: 5,23:1 (light) · 5,35:1 (dark) trên nền popover. */}\n <SearchIcon className=\"size-4 shrink-0 opacity-50\" />\n <CommandPrimitive.Input\n data-slot=\"command-input\"\n className={cn(\n \"placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50\",\n className\n )}\n {...props}\n />\n </div>\n );\n}\n\nexport type CommandListProps = React.ComponentProps<typeof CommandPrimitive.List>;\n\nfunction CommandList({ className, ...props }: CommandListProps) {\n return (\n <CommandPrimitive.List\n data-slot=\"command-list\"\n className={cn(\"max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto\", className)}\n {...props}\n />\n );\n}\n\nexport type CommandEmptyProps = React.ComponentProps<typeof CommandPrimitive.Empty>;\n\nfunction CommandEmpty({ ...props }: CommandEmptyProps) {\n return <CommandPrimitive.Empty data-slot=\"command-empty\" className=\"py-6 text-center text-sm\" {...props} />;\n}\n\nexport type CommandGroupProps = React.ComponentProps<typeof CommandPrimitive.Group>;\n\nfunction CommandGroup({ className, ...props }: CommandGroupProps) {\n return (\n <CommandPrimitive.Group\n data-slot=\"command-group\"\n className={cn(\n \"text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport type CommandSeparatorProps = React.ComponentProps<typeof CommandPrimitive.Separator>;\n\nfunction CommandSeparator({ className, ...props }: CommandSeparatorProps) {\n return (\n <CommandPrimitive.Separator\n data-slot=\"command-separator\"\n className={cn(\"bg-border -mx-1 h-px\", className)}\n {...props}\n />\n );\n}\n\nexport type CommandItemProps = React.ComponentProps<typeof CommandPrimitive.Item>;\n\nfunction CommandItem({ className, ...props }: CommandItemProps) {\n return (\n <CommandPrimitive.Item\n data-slot=\"command-item\"\n className={cn(\n \"data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 mt-1 first:mt-0 rounded-sm px-2 py-(--menu-item-py) text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport type CommandShortcutProps = React.ComponentProps<\"span\">;\n\nfunction CommandShortcut({ className, ...props }: CommandShortcutProps) {\n return (\n <span\n data-slot=\"command-shortcut\"\n className={cn(\"text-muted-foreground ml-auto text-xs tracking-widest\", className)}\n {...props}\n />\n );\n}\n\nexport {\n Command,\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut\n};\n"],"mappings":";AAwBI,cAiCE,YAjCF;AAtBJ,SAAS,WAAW,wBAAwB;AAC5C,SAAS,kBAAkB;AAE3B,SAAS,0BAA0B;AACnC,SAAS,UAAU;AACnB,SAAS,QAAQ,eAAe,mBAAmB,cAAc,mBAAmB;AAepF,SAAS,QAAQ,EAAE,WAAW,GAAG,MAAM,GAAiB;AACtD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAWA,SAAS,cAAc;AAAA,EACrB,OAAO;AAAA,EACP,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,GAAG;AACL,GAAuB;AACrB,QAAM,IAAI,mBAAmB,SAAS;AACtC,QAAM,QAAQ,aAAa,EAAE;AAC7B,QAAM,cAAc,mBAAmB,EAAE;AACzC,SACE,qBAAC,UAAQ,GAAG,OACV;AAAA,yBAAC,gBAAa,WAAU,WACtB;AAAA,0BAAC,eAAa,iBAAM;AAAA,MACpB,oBAAC,qBAAmB,uBAAY;AAAA,OAClC;AAAA,IACA,oBAAC,iBAAc,WAAW,GAAG,uBAAuB,SAAS,GAAG,iBAC9D,8BAAC,WAAQ,WAAU,yZAChB,UACH,GACF;AAAA,KACF;AAEJ;AAIA,SAAS,aAAa,EAAE,WAAW,GAAG,MAAM,GAAsB;AAChE,SACE,qBAAC,SAAI,aAAU,yBAAwB,WAAU,6CAK/C;AAAA,wBAAC,cAAW,WAAU,8BAA6B;AAAA,IACnD;AAAA,MAAC,iBAAiB;AAAA,MAAjB;AAAA,QACC,aAAU;AAAA,QACV,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,QACC,GAAG;AAAA;AAAA,IACN;AAAA,KACF;AAEJ;AAIA,SAAS,YAAY,EAAE,WAAW,GAAG,MAAM,GAAqB;AAC9D,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,+DAA+D,SAAS;AAAA,MACrF,GAAG;AAAA;AAAA,EACN;AAEJ;AAIA,SAAS,aAAa,EAAE,GAAG,MAAM,GAAsB;AACrD,SAAO,oBAAC,iBAAiB,OAAjB,EAAuB,aAAU,iBAAgB,WAAU,4BAA4B,GAAG,OAAO;AAC3G;AAIA,SAAS,aAAa,EAAE,WAAW,GAAG,MAAM,GAAsB;AAChE,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAIA,SAAS,iBAAiB,EAAE,WAAW,GAAG,MAAM,GAA0B;AACxE,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,wBAAwB,SAAS;AAAA,MAC9C,GAAG;AAAA;AAAA,EACN;AAEJ;AAIA,SAAS,YAAY,EAAE,WAAW,GAAG,MAAM,GAAqB;AAC9D,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAIA,SAAS,gBAAgB,EAAE,WAAW,GAAG,MAAM,GAAyB;AACtE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,yDAAyD,SAAS;AAAA,MAC/E,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
@@ -6,7 +6,8 @@
6
6
  * `src/chart/chart-colors.ts`. Barrel xuất module này TRỰC TIẾP; `cropper.tsx` chỉ `import`.
7
7
  */
8
8
  /**
9
- * Chuỗi a11y của `Cropper` — truyền `labels` cho `Cropper` để ghi đè từng khoá.
9
+ * Chuỗi a11y của `Cropper`. Theo `ComitorLocaleProvider` (mặc định tiếng Anh, bảng tiếng Việt
10
+ * dựng sẵn); truyền `labels` cho `Cropper` để ghi đè từng khoá.
10
11
  *
11
12
  * ⚠ Thượng nguồn (Dice UI) KHÔNG có chuỗi nào: vùng cắt nhận focus bằng Tab (`tabIndex=0`) nhưng
12
13
  * không role, không tên, không mô tả — trình đọc màn hình gặp một phần tử focus được mà không
@@ -18,7 +19,7 @@ interface CropperLabels {
18
19
  * đó thắng, vì nó được trải SAU giá trị mặc định.
19
20
  */
20
21
  label: string;
21
- /** `aria-roledescription` — tên loại control mà trình đọc màn hình đọc thay cho "ứng dụng". */
22
+ /** `aria-roledescription` — tên loại control mà trình đọc màn hình đọc thay cho "application". */
22
23
  roleDescription: string;
23
24
  /** Hướng dẫn phím, gắn vào vùng cắt qua `aria-describedby`. */
24
25
  instructions: string;
@@ -28,7 +29,11 @@ interface CropperLabels {
28
29
  */
29
30
  zoomStatus: (zoom: number) => string;
30
31
  }
31
- /** Nhãn tiếng Việt mặc định — mọi khoá đều ghi đè được qua prop `labels` của `Cropper`. */
32
+ /**
33
+ * Nhãn TIẾNG ANH mặc định (từ `3.0.0`; trước đó là tiếng Việt). Bảng tiếng Việt:
34
+ * `comitorMessagesVi.cropper`. Component không đọc thẳng hằng này — nó đọc bảng của
35
+ * `ComitorLocaleProvider`; hằng ở đây để app trải ra khi tự dựng nhãn.
36
+ */
32
37
  declare const DEFAULT_CROPPER_LABELS: CropperLabels;
33
38
 
34
39
  export { type CropperLabels, DEFAULT_CROPPER_LABELS };
@@ -1,9 +1,5 @@
1
- const DEFAULT_CROPPER_LABELS = {
2
- label: "V\xF9ng c\u1EAFt \u1EA3nh",
3
- roleDescription: "tr\xECnh c\u1EAFt \u1EA3nh",
4
- instructions: "D\xF9ng c\xE1c ph\xEDm m\u0169i t\xEAn \u0111\u1EC3 di chuy\u1EC3n \u1EA3nh, gi\u1EEF Shift \u0111\u1EC3 di chuy\u1EC3n ch\u1EADm h\u01A1n. Ph\xEDm + v\xE0 - \u0111\u1EC3 ph\xF3ng to, thu nh\u1ECF.",
5
- zoomStatus: (zoom) => `Thu ph\xF3ng ${Math.round(zoom * 100)}%`
6
- };
1
+ import { cropperEn } from "../../i18n/namespaces/cropper.js";
2
+ const DEFAULT_CROPPER_LABELS = { ...cropperEn };
7
3
  export {
8
4
  DEFAULT_CROPPER_LABELS
9
5
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/ui/cropper-constants.ts"],"sourcesContent":["/**\n * Nhãn mặc định của `Cropper`.\n *\n * Module **CỐ Ý không có `\"use client\"`**: mọi export của một file `\"use client\"` tới Server\n * Component là client-reference proxy, đọc ra `undefined` mà KHÔNG throw — xem\n * `src/chart/chart-colors.ts`. Barrel xuất module này TRỰC TIẾP; `cropper.tsx` chỉ `import`.\n */\n\n/**\n * Chuỗi a11y của `Cropper` — truyền `labels` cho `Cropper` để ghi đè từng khoá.\n *\n * ⚠ Thượng nguồn (Dice UI) KHÔNG có chuỗi nào: vùng cắt nhận focus bằng Tab (`tabIndex=0`) nhưng\n * không role, không tên, không mô tả — trình đọc màn hình gặp một phần tử focus được mà không\n * biết nó là gì, và người dùng không có cách nào biết phím nào điều khiển được nó.\n */\nexport interface CropperLabels {\n /**\n * Tên của vùng cắt (`aria-label`). Truyền thẳng `aria-label` cho `Cropper` cũng được — prop\n * đó thắng, vì nó được trải SAU giá trị mặc định.\n */\n label: string;\n /** `aria-roledescription` — tên loại control mà trình đọc màn hình đọc thay cho \"ứng dụng\". */\n roleDescription: string;\n /** Hướng dẫn phím, gắn vào vùng cắt qua `aria-describedby`. */\n instructions: string;\n /**\n * Câu đọc qua vùng `aria-live` sau mỗi lần phóng/thu bằng phím. `zoom` là hệ số thô (1 = vừa\n * khung). Là HÀM vì có số chèn vào giữa câu.\n */\n zoomStatus: (zoom: number) => string;\n}\n\n/** Nhãn tiếng Việt mặc định — mọi khoá đều ghi đè được qua prop `labels` của `Cropper`. */\nexport const DEFAULT_CROPPER_LABELS: CropperLabels = {\n label: \"Vùng cắt ảnh\",\n roleDescription: \"trình cắt ảnh\",\n instructions:\n \"Dùng các phím mũi tên để di chuyển ảnh, giữ Shift để di chuyển chậm hơn. Phím + và - để phóng to, thu nhỏ.\",\n zoomStatus: (zoom) => `Thu phóng ${Math.round(zoom * 100)}%`\n};\n"],"mappings":"AAiCO,MAAM,yBAAwC;AAAA,EACnD,OAAO;AAAA,EACP,iBAAiB;AAAA,EACjB,cACE;AAAA,EACF,YAAY,CAAC,SAAS,gBAAa,KAAK,MAAM,OAAO,GAAG,CAAC;AAC3D;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/ui/cropper-constants.ts"],"sourcesContent":["/**\n * Nhãn mặc định của `Cropper`.\n *\n * Module **CỐ Ý không có `\"use client\"`**: mọi export của một file `\"use client\"` tới Server\n * Component là client-reference proxy, đọc ra `undefined` mà KHÔNG throw — xem\n * `src/chart/chart-colors.ts`. Barrel xuất module này TRỰC TIẾP; `cropper.tsx` chỉ `import`.\n */\n\nimport { cropperEn } from \"../../i18n/namespaces/cropper.js\";\n\n/**\n * Chuỗi a11y của `Cropper`. Theo `ComitorLocaleProvider` (mặc định tiếng Anh, bảng tiếng Việt\n * dựng sẵn); truyền `labels` cho `Cropper` để ghi đè từng khoá.\n *\n * ⚠ Thượng nguồn (Dice UI) KHÔNG có chuỗi nào: vùng cắt nhận focus bằng Tab (`tabIndex=0`) nhưng\n * không role, không tên, không mô tả — trình đọc màn hình gặp một phần tử focus được mà không\n * biết nó là gì, và người dùng không có cách nào biết phím nào điều khiển được nó.\n */\nexport interface CropperLabels {\n /**\n * Tên của vùng cắt (`aria-label`). Truyền thẳng `aria-label` cho `Cropper` cũng được — prop\n * đó thắng, vì nó được trải SAU giá trị mặc định.\n */\n label: string;\n /** `aria-roledescription` — tên loại control mà trình đọc màn hình đọc thay cho \"application\". */\n roleDescription: string;\n /** Hướng dẫn phím, gắn vào vùng cắt qua `aria-describedby`. */\n instructions: string;\n /**\n * Câu đọc qua vùng `aria-live` sau mỗi lần phóng/thu bằng phím. `zoom` là hệ số thô (1 = vừa\n * khung). Là HÀM vì có số chèn vào giữa câu.\n */\n zoomStatus: (zoom: number) => string;\n}\n\n/**\n * Nhãn TIẾNG ANH mặc định (từ `3.0.0`; trước đó là tiếng Việt). Bảng tiếng Việt:\n * `comitorMessagesVi.cropper`. Component không đọc thẳng hằng này — nó đọc bảng của\n * `ComitorLocaleProvider`; hằng ở đây để app trải ra khi tự dựng nhãn.\n */\nexport const DEFAULT_CROPPER_LABELS: CropperLabels = { ...cropperEn };\n"],"mappings":"AAQA,SAAS,iBAAiB;AAgCnB,MAAM,yBAAwC,EAAE,GAAG,UAAU;","names":[]}
@@ -53,7 +53,8 @@ interface CropperProps extends DivProps {
53
53
  preventScrollZoom?: boolean;
54
54
  withGrid?: boolean;
55
55
  /**
56
- * Chuỗi a11y của vùng cắt — ghi đè từng khoá, mặc định `DEFAULT_CROPPER_LABELS` (tiếng Việt).
56
+ * Chuỗi a11y của vùng cắt — ghi đè từng khoá. Không truyền thì theo namespace `cropper` của
57
+ * `ComitorLocaleProvider` (mặc định tiếng Anh).
57
58
  *
58
59
  * ⚠ Thêm so với thượng nguồn — xem `CropperLabels`.
59
60
  */
@@ -3,12 +3,12 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { Slot } from "@radix-ui/react-slot";
4
4
  import { cva } from "class-variance-authority";
5
5
  import * as React from "react";
6
+ import { useComitorLabels } from "../../i18n/locale-provider.js";
6
7
  import { cn } from "../../lib/cn.js";
7
8
  import { useComposedRefs } from "../../lib/compose-refs.js";
8
9
  import { useAsRef } from "../../lib/use-as-ref.js";
9
10
  import { useIsomorphicLayoutEffect } from "../../lib/use-isomorphic-layout-effect.js";
10
11
  import { useLazyRef } from "../../lib/use-lazy-ref.js";
11
- import { DEFAULT_CROPPER_LABELS } from "./cropper-constants.js";
12
12
  const ROOT_NAME = "Cropper";
13
13
  const ROOT_IMPL_NAME = "CropperImpl";
14
14
  const IMAGE_NAME = "CropperImage";
@@ -408,7 +408,7 @@ function Cropper(props) {
408
408
  }
409
409
  }
410
410
  }, [cropProp, zoomProp, rotationProp, store, allowOverflow]);
411
- const labels = React.useMemo(() => ({ ...DEFAULT_CROPPER_LABELS, ...labelsProp }), [labelsProp]);
411
+ const labels = useComitorLabels("cropper", labelsProp);
412
412
  const contextValue = React.useMemo(
413
413
  () => ({
414
414
  minZoom,