@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
@@ -3,6 +3,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { Slot } from "@radix-ui/react-slot";
4
4
  import { Plus, X } from "lucide-react";
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";
@@ -11,7 +12,6 @@ import { useLazyRef } from "../../lib/use-lazy-ref.js";
11
12
  import { VisuallyHiddenInput } from "../../lib/visually-hidden-input.js";
12
13
  import { Button } from "./button.js";
13
14
  import { Input } from "./input.js";
14
- import { DEFAULT_KEY_VALUE_LABELS } from "./key-value-constants.js";
15
15
  import { Textarea } from "./textarea.js";
16
16
  const ROOT_NAME = "KeyValue";
17
17
  const LIST_NAME = "KeyValueList";
@@ -65,6 +65,42 @@ function useKeyValueContext(consumerName) {
65
65
  }
66
66
  return context;
67
67
  }
68
+ function commitItemField(store, context, itemId, field, text) {
69
+ const state = store.getState();
70
+ const newValue = state.value.map((item) => item.id === itemId ? { ...item, [field]: text } : item);
71
+ store.setState("value", newValue);
72
+ const updatedItemData = newValue.find((item) => item.id === itemId);
73
+ if (!updatedItemData) return;
74
+ const errors = {};
75
+ if (context.onKeyValidate) {
76
+ const keyError = context.onKeyValidate(updatedItemData.key, newValue);
77
+ if (keyError) errors.key = keyError;
78
+ }
79
+ if (!context.allowDuplicateKeys) {
80
+ const duplicateKey = newValue.find(
81
+ (item) => item.id !== updatedItemData.id && item.key === updatedItemData.key && updatedItemData.key !== ""
82
+ );
83
+ if (duplicateKey) {
84
+ errors.key = context.labels.duplicateKey;
85
+ }
86
+ }
87
+ if (context.onValueValidate) {
88
+ const valueError = context.onValueValidate(updatedItemData.value, updatedItemData.key, newValue);
89
+ if (valueError) errors.value = valueError;
90
+ }
91
+ const newErrorsState = { ...state.errors };
92
+ if (Object.keys(errors).length > 0) {
93
+ newErrorsState[itemId] = errors;
94
+ } else {
95
+ delete newErrorsState[itemId];
96
+ }
97
+ store.setState("errors", newErrorsState);
98
+ }
99
+ function useTrimDraft(committed) {
100
+ const [draft, setDraft] = React.useState(null);
101
+ const shown = draft !== null && draft.trim() === committed ? draft : committed;
102
+ return [shown, setDraft];
103
+ }
68
104
  function KeyValue(props) {
69
105
  const {
70
106
  value: valueProp,
@@ -96,7 +132,7 @@ function KeyValue(props) {
96
132
  } = props;
97
133
  const instanceId = React.useId();
98
134
  const rootId = id ?? instanceId;
99
- const labels = React.useMemo(() => ({ ...DEFAULT_KEY_VALUE_LABELS, ...labelsProp }), [labelsProp]);
135
+ const labels = useComitorLabels("keyValue", labelsProp);
100
136
  const keyPlaceholder = keyPlaceholderProp ?? labels.keyPlaceholder;
101
137
  const valuePlaceholder = valuePlaceholderProp ?? labels.valuePlaceholder;
102
138
  const [formTrigger, setFormTrigger] = React.useState(null);
@@ -258,6 +294,7 @@ function KeyValueItem(props) {
258
294
  function KeyValueKeyInput(props) {
259
295
  const {
260
296
  onChange: onChangeProp,
297
+ onBlur: onBlurProp,
261
298
  onPaste: onPasteProp,
262
299
  asChild,
263
300
  disabled,
@@ -280,52 +317,29 @@ function KeyValueKeyInput(props) {
280
317
  }, [focusedId, itemData.id]);
281
318
  const propsRef = useAsRef({
282
319
  onChange: onChangeProp,
320
+ onBlur: onBlurProp,
283
321
  onPaste: onPasteProp
284
322
  });
285
323
  const isDisabled = disabled || context.disabled;
286
324
  const isReadOnly = readOnly || context.readOnly;
287
325
  const isRequired = required || context.required;
288
326
  const isInvalid = errors[itemData.id]?.key !== void 0;
327
+ const [shownKey, setKeyDraft] = useTrimDraft(itemData.key);
289
328
  const onChange = React.useCallback(
290
329
  (event) => {
291
- const state = store.getState();
292
- const newValue = state.value.map((item) => {
293
- if (item.id !== itemData.id) return item;
294
- const updated = { ...item, key: event.target.value };
295
- if (context.trim) updated.key = updated.key.trim();
296
- return updated;
297
- });
298
- store.setState("value", newValue);
299
- const updatedItemData = newValue.find((item) => item.id === itemData.id);
300
- if (updatedItemData) {
301
- const errors2 = {};
302
- if (context.onKeyValidate) {
303
- const keyError = context.onKeyValidate(updatedItemData.key, newValue);
304
- if (keyError) errors2.key = keyError;
305
- }
306
- if (!context.allowDuplicateKeys) {
307
- const duplicateKey = newValue.find(
308
- (item) => item.id !== updatedItemData.id && item.key === updatedItemData.key && updatedItemData.key !== ""
309
- );
310
- if (duplicateKey) {
311
- errors2.key = context.labels.duplicateKey;
312
- }
313
- }
314
- if (context.onValueValidate) {
315
- const valueError = context.onValueValidate(updatedItemData.value, updatedItemData.key, newValue);
316
- if (valueError) errors2.value = valueError;
317
- }
318
- const newErrorsState = { ...state.errors };
319
- if (Object.keys(errors2).length > 0) {
320
- newErrorsState[itemData.id] = errors2;
321
- } else {
322
- delete newErrorsState[itemData.id];
323
- }
324
- store.setState("errors", newErrorsState);
325
- }
330
+ const text = event.target.value;
331
+ if (context.trim) setKeyDraft(text);
332
+ commitItemField(store, context, itemData.id, "key", context.trim ? text.trim() : text);
326
333
  propsRef.current.onChange?.(event);
327
334
  },
328
- [store, itemData.id, context, propsRef]
335
+ [store, itemData.id, context, propsRef, setKeyDraft]
336
+ );
337
+ const onBlur = React.useCallback(
338
+ (event) => {
339
+ propsRef.current.onBlur?.(event);
340
+ setKeyDraft(null);
341
+ },
342
+ [propsRef, setKeyDraft]
329
343
  );
330
344
  const onPaste = React.useCallback(
331
345
  (event) => {
@@ -395,8 +409,9 @@ function KeyValueKeyInput(props) {
395
409
  placeholder: context.keyPlaceholder,
396
410
  ...keyInputProps,
397
411
  ref: composedRef,
398
- value: itemData.key,
412
+ value: shownKey,
399
413
  onChange,
414
+ onBlur,
400
415
  onPaste
401
416
  }
402
417
  );
@@ -404,6 +419,7 @@ function KeyValueKeyInput(props) {
404
419
  function KeyValueValueInput(props) {
405
420
  const {
406
421
  onChange: onChangeProp,
422
+ onBlur: onBlurProp,
407
423
  asChild,
408
424
  disabled,
409
425
  readOnly,
@@ -418,53 +434,30 @@ function KeyValueValueInput(props) {
418
434
  const store = useStoreContext(VALUE_INPUT_NAME);
419
435
  const errors = useStore((state) => state.errors);
420
436
  const propsRef = useAsRef({
421
- onChange: onChangeProp
437
+ onChange: onChangeProp,
438
+ onBlur: onBlurProp
422
439
  });
423
440
  const isDisabled = disabled || context.disabled;
424
441
  const isReadOnly = readOnly || context.readOnly;
425
442
  const isRequired = required || context.required;
426
443
  const isInvalid = errors[itemData.id]?.value !== void 0;
427
444
  const maxHeight = maxRows ? `calc(${maxRows} * 1.5em + 1rem)` : void 0;
445
+ const [shownValue, setValueDraft] = useTrimDraft(itemData.value);
428
446
  const onChange = React.useCallback(
429
447
  (event) => {
430
448
  propsRef.current.onChange?.(event);
431
- const state = store.getState();
432
- const newValue = state.value.map((item) => {
433
- if (item.id !== itemData.id) return item;
434
- const updated = { ...item, value: event.target.value };
435
- if (context.trim) updated.value = updated.value.trim();
436
- return updated;
437
- });
438
- store.setState("value", newValue);
439
- const updatedItemData = newValue.find((item) => item.id === itemData.id);
440
- if (updatedItemData) {
441
- const errors2 = {};
442
- if (context.onKeyValidate) {
443
- const keyError = context.onKeyValidate(updatedItemData.key, newValue);
444
- if (keyError) errors2.key = keyError;
445
- }
446
- if (!context.allowDuplicateKeys) {
447
- const duplicateKey = newValue.find(
448
- (item) => item.id !== updatedItemData.id && item.key === updatedItemData.key && updatedItemData.key !== ""
449
- );
450
- if (duplicateKey) {
451
- errors2.key = context.labels.duplicateKey;
452
- }
453
- }
454
- if (context.onValueValidate) {
455
- const valueError = context.onValueValidate(updatedItemData.value, updatedItemData.key, newValue);
456
- if (valueError) errors2.value = valueError;
457
- }
458
- const newErrorsState = { ...state.errors };
459
- if (Object.keys(errors2).length > 0) {
460
- newErrorsState[itemData.id] = errors2;
461
- } else {
462
- delete newErrorsState[itemData.id];
463
- }
464
- store.setState("errors", newErrorsState);
465
- }
449
+ const text = event.target.value;
450
+ if (context.trim) setValueDraft(text);
451
+ commitItemField(store, context, itemData.id, "value", context.trim ? text.trim() : text);
466
452
  },
467
- [store, itemData.id, context, propsRef]
453
+ [store, itemData.id, context, propsRef, setValueDraft]
454
+ );
455
+ const onBlur = React.useCallback(
456
+ (event) => {
457
+ propsRef.current.onBlur?.(event);
458
+ setValueDraft(null);
459
+ },
460
+ [propsRef, setValueDraft]
468
461
  );
469
462
  const ValueInputPrimitive = asChild ? Slot : Textarea;
470
463
  return /* @__PURE__ */ jsx(
@@ -500,8 +493,9 @@ function KeyValueValueInput(props) {
500
493
  ...style,
501
494
  ...maxHeight && { maxHeight }
502
495
  },
503
- value: itemData.value,
504
- onChange
496
+ value: shownValue,
497
+ onChange,
498
+ onBlur
505
499
  }
506
500
  );
507
501
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/ui/key-value.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/key-value) — 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 { Plus, X } from \"lucide-react\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn.js\";\nimport { useComposedRefs } from \"../../lib/compose-refs.js\";\nimport { useAsRef } from \"../../lib/use-as-ref.js\";\nimport { useIsomorphicLayoutEffect } from \"../../lib/use-isomorphic-layout-effect.js\";\nimport { useLazyRef } from \"../../lib/use-lazy-ref.js\";\nimport { VisuallyHiddenInput } from \"../../lib/visually-hidden-input.js\";\nimport { Button } from \"./button.js\";\nimport { Input } from \"./input.js\";\nimport { DEFAULT_KEY_VALUE_LABELS, type KeyValueLabels } from \"./key-value-constants.js\";\nimport { Textarea } from \"./textarea.js\";\n\nconst ROOT_NAME = \"KeyValue\";\nconst LIST_NAME = \"KeyValueList\";\nconst ITEM_NAME = \"KeyValueItem\";\nconst KEY_INPUT_NAME = \"KeyValueKeyInput\";\nconst VALUE_INPUT_NAME = \"KeyValueValueInput\";\nconst REMOVE_NAME = \"KeyValueRemove\";\nconst ADD_NAME = \"KeyValueAdd\";\nconst ERROR_NAME = \"KeyValueError\";\n\ntype Orientation = \"vertical\" | \"horizontal\";\ntype Field = \"key\" | \"value\";\n\ninterface DivProps extends React.ComponentProps<\"div\"> {\n asChild?: boolean;\n}\n\ntype RootElement = React.ComponentRef<typeof KeyValue>;\ntype KeyInputElement = React.ComponentRef<typeof KeyValueKeyInput>;\ntype RemoveElement = React.ComponentRef<typeof KeyValueRemove>;\ntype AddElement = React.ComponentRef<typeof KeyValueAdd>;\n\nfunction getErrorId(rootId: string, itemId: string, field: Field) {\n return `${rootId}-${itemId}-${field}-error`;\n}\n\n/*\n * ⚠ Khác thượng nguồn: bản gốc gọi thẳng `crypto.randomUUID()`. Hàm đó chỉ tồn tại trong NGỮ CẢNH\n * AN TOÀN (HTTPS hoặc localhost) — mở trang quản trị qua `http://` bằng IP nội bộ là `TypeError`\n * ngay lúc render dòng đầu tiên. Id ở đây chỉ làm key của React và nối vào id của thông báo lỗi,\n * không cần ngẫu nhiên mật mã, nên có đường lui.\n */\nlet fallbackIdCounter = 0;\n\nfunction createItemId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n fallbackIdCounter += 1;\n return `kv-${Date.now().toString(36)}-${fallbackIdCounter}`;\n}\n\nfunction removeQuotes(string: string, shouldStrip: boolean): string {\n if (!shouldStrip) return string;\n\n const trimmed = string.trim();\n if ((trimmed.startsWith('\"') && trimmed.endsWith('\"')) || (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))) {\n return trimmed.slice(1, -1);\n }\n return trimmed;\n}\n\ninterface Store {\n subscribe: (callback: () => void) => () => void;\n getState: () => KeyValueState;\n setState: <K extends keyof KeyValueState>(key: K, value: KeyValueState[K]) => void;\n notify: () => void;\n}\n\nfunction useStore<T>(selector: (state: KeyValueState) => T, ogStore?: Store | null): T {\n const contextStore = React.useContext(StoreContext);\n\n const store = ogStore ?? contextStore;\n\n if (!store) {\n throw new Error(`\\`useKeyValueStore\\` phải được gọi bên trong \\`${ROOT_NAME}\\``);\n }\n\n const getSnapshot = React.useCallback(() => selector(store.getState()), [store, selector]);\n\n return React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);\n}\n\ninterface ItemData {\n id: string;\n key: string;\n value: string;\n}\n\ninterface KeyValueState {\n value: ItemData[];\n focusedId: string | null;\n errors: Record<string, { key?: string; value?: string }>;\n}\n\nconst StoreContext = React.createContext<Store | null>(null);\n\nfunction useStoreContext(consumerName: string) {\n const context = React.useContext(StoreContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\ninterface KeyValueContextValue {\n onPaste?: (event: ClipboardEvent, items: ItemData[]) => void;\n onAdd?: (value: ItemData) => void;\n onRemove?: (value: ItemData) => void;\n onKeyValidate?: (key: string, value: ItemData[]) => string | undefined;\n onValueValidate?: (value: string, key: string, items: ItemData[]) => string | undefined;\n rootId: string;\n maxItems?: number;\n minItems: number;\n keyPlaceholder: string;\n valuePlaceholder: string;\n labels: KeyValueLabels;\n allowDuplicateKeys: boolean;\n enablePaste: boolean;\n trim: boolean;\n stripQuotes: boolean;\n disabled: boolean;\n readOnly: boolean;\n required: boolean;\n}\n\nconst KeyValueContext = React.createContext<KeyValueContextValue | null>(null);\n\nfunction useKeyValueContext(consumerName: string) {\n const context = React.useContext(KeyValueContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\ninterface KeyValueProps extends Omit<DivProps, \"onPaste\" | \"defaultValue\"> {\n id?: string;\n defaultValue?: ItemData[];\n value?: ItemData[];\n onValueChange?: (value: ItemData[]) => void;\n maxItems?: number;\n minItems?: number;\n /** Placeholder của ô khoá — mặc định `labels.keyPlaceholder` (\"Khoá\"). */\n keyPlaceholder?: string;\n /** Placeholder của ô giá trị — mặc định `labels.valuePlaceholder` (\"Giá trị\"). */\n valuePlaceholder?: string;\n /**\n * Chuỗi hiển thị và chuỗi cho trình đọc màn hình — truyền MỘT PHẦN là đủ, phần còn lại lấy từ\n * `DEFAULT_KEY_VALUE_LABELS` (tiếng Việt). ⚠ Thêm so với thượng nguồn (bản gốc chôn cứng\n * \"Add\" / \"Duplicate key\" và để nút xoá không có tên).\n */\n labels?: Partial<KeyValueLabels>;\n name?: string;\n allowDuplicateKeys?: boolean;\n enablePaste?: boolean;\n trim?: boolean;\n stripQuotes?: boolean;\n disabled?: boolean;\n readOnly?: boolean;\n required?: boolean;\n onPaste?: (event: ClipboardEvent, items: ItemData[]) => void;\n onAdd?: (value: ItemData) => void;\n onRemove?: (value: ItemData) => void;\n onKeyValidate?: (key: string, value: ItemData[]) => string | undefined;\n onValueValidate?: (value: string, key: string, items: ItemData[]) => string | undefined;\n}\n\n/**\n * KeyValue — danh sách cặp khoá/giá trị sửa được: trường tuỳ biến của bản ghi CRM, header /\n * metadata của webhook ở trang quản trị. Dán nhiều dòng `KEY=value` (hoặc `KEY: value`, hoặc\n * cách bằng tab) vào ô khoá là tách thành nhiều cặp.\n */\nfunction KeyValue(props: KeyValueProps) {\n const {\n value: valueProp,\n defaultValue,\n onValueChange,\n onPaste,\n onAdd,\n onRemove,\n onKeyValidate,\n onValueValidate,\n maxItems,\n minItems = 0,\n labels: labelsProp,\n keyPlaceholder: keyPlaceholderProp,\n valuePlaceholder: valuePlaceholderProp,\n allowDuplicateKeys = false,\n asChild,\n enablePaste = true,\n trim = true,\n stripQuotes = true,\n disabled = false,\n readOnly = false,\n required = false,\n className,\n id,\n name,\n ref,\n ...rootProps\n } = props;\n\n const instanceId = React.useId();\n const rootId = id ?? instanceId;\n\n const labels = React.useMemo<KeyValueLabels>(() => ({ ...DEFAULT_KEY_VALUE_LABELS, ...labelsProp }), [labelsProp]);\n const keyPlaceholder = keyPlaceholderProp ?? labels.keyPlaceholder;\n const valuePlaceholder = valuePlaceholderProp ?? labels.valuePlaceholder;\n\n const [formTrigger, setFormTrigger] = React.useState<RootElement | null>(null);\n const composedRef = useComposedRefs(ref, (node) => setFormTrigger(node));\n const isFormControl = formTrigger ? !!formTrigger.closest(\"form\") : true;\n\n const listenersRef = useLazyRef(() => new Set<() => void>());\n const stateRef = useLazyRef<KeyValueState>(() => ({\n value: valueProp ?? defaultValue ?? [{ id: createItemId(), key: \"\", value: \"\" }],\n focusedId: null,\n errors: {}\n }));\n const propsRef = useAsRef({ onValueChange });\n\n const store = React.useMemo<Store>(() => {\n return {\n subscribe: (cb) => {\n listenersRef.current.add(cb);\n return () => listenersRef.current.delete(cb);\n },\n getState: () => stateRef.current,\n setState: (key, val) => {\n if (Object.is(stateRef.current[key], val)) return;\n\n if (key === \"value\" && Array.isArray(val)) {\n stateRef.current.value = val as ItemData[];\n propsRef.current.onValueChange?.(val as ItemData[]);\n } else {\n stateRef.current[key] = val;\n }\n\n store.notify();\n },\n notify: () => {\n for (const cb of listenersRef.current) {\n cb();\n }\n }\n };\n }, [listenersRef, stateRef, propsRef]);\n\n const value = useStore((state) => state.value, store);\n const errors = useStore((state) => state.errors, store);\n const isInvalid = Object.keys(errors).length > 0;\n\n useIsomorphicLayoutEffect(() => {\n if (valueProp !== undefined) {\n store.setState(\"value\", valueProp);\n }\n }, [valueProp]);\n\n const contextValue = React.useMemo<KeyValueContextValue>(\n () => ({\n onPaste,\n onAdd,\n onRemove,\n onKeyValidate,\n onValueValidate,\n rootId,\n maxItems,\n minItems,\n keyPlaceholder,\n valuePlaceholder,\n labels,\n allowDuplicateKeys,\n enablePaste,\n trim,\n stripQuotes,\n disabled,\n readOnly,\n required\n }),\n [\n onPaste,\n onAdd,\n onRemove,\n onKeyValidate,\n onValueValidate,\n rootId,\n disabled,\n readOnly,\n required,\n maxItems,\n minItems,\n keyPlaceholder,\n valuePlaceholder,\n labels,\n allowDuplicateKeys,\n enablePaste,\n trim,\n stripQuotes\n ]\n );\n\n const RootPrimitive = asChild ? Slot : \"div\";\n\n return (\n <StoreContext.Provider value={store}>\n <KeyValueContext.Provider value={contextValue}>\n <RootPrimitive\n id={id}\n data-slot=\"key-value\"\n data-disabled={disabled ? \"\" : undefined}\n data-invalid={isInvalid ? \"\" : undefined}\n data-readonly={readOnly ? \"\" : undefined}\n {...rootProps}\n ref={composedRef}\n className={cn(\"flex flex-col gap-2\", className)}\n />\n {isFormControl && (\n <VisuallyHiddenInput\n type=\"hidden\"\n control={formTrigger}\n name={name}\n value={value}\n disabled={disabled}\n readOnly={readOnly}\n required={required}\n />\n )}\n </KeyValueContext.Provider>\n </StoreContext.Provider>\n );\n}\n\ninterface KeyValueListProps extends DivProps {\n orientation?: Orientation;\n}\n\nfunction KeyValueList(props: KeyValueListProps) {\n const { orientation = \"vertical\", asChild, className, ...listProps } = props;\n\n const value = useStore((state) => state.value);\n\n const ListPrimitive = asChild ? Slot : \"div\";\n\n return (\n <ListPrimitive\n role=\"list\"\n /*\n * ⚠ Khác thượng nguồn (a11y): bỏ `aria-orientation`. Thuộc tính đó KHÔNG được phép trên\n * `role=\"list\"` (ARIA 1.2 chỉ cho nó ở listbox, menu, tablist, toolbar, radiogroup, slider…)\n * — axe báo `aria-allowed-attr`. Hướng vẫn còn ở `data-orientation` cho CSS.\n */\n data-slot=\"key-value-list\"\n data-orientation={orientation}\n {...listProps}\n className={cn(\"flex\", orientation === \"vertical\" ? \"flex-col gap-2\" : \"flex-row gap-2\", className)}\n >\n {value.map((item) => {\n const children = React.Children.toArray(props.children);\n\n return (\n <KeyValueItemContext.Provider key={item.id} value={item}>\n {children}\n </KeyValueItemContext.Provider>\n );\n })}\n </ListPrimitive>\n );\n}\n\nconst KeyValueItemContext = React.createContext<ItemData | null>(null);\n\nfunction useKeyValueItemContext(consumerName: string) {\n const context = React.useContext(KeyValueItemContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${LIST_NAME}\\``);\n }\n return context;\n}\n\ninterface KeyValueItemProps extends React.ComponentProps<\"div\"> {\n asChild?: boolean;\n}\n\nfunction KeyValueItem(props: KeyValueItemProps) {\n const { asChild, className, ...itemProps } = props;\n const itemData = useKeyValueItemContext(ITEM_NAME);\n\n const focusedId = useStore((state) => state.focusedId);\n\n const ItemPrimitive = asChild ? Slot : \"div\";\n\n return (\n <ItemPrimitive\n role=\"listitem\"\n data-slot=\"key-value-item\"\n data-highlighted={focusedId === itemData.id ? \"\" : undefined}\n {...itemProps}\n className={cn(\"flex items-start gap-2\", className)}\n />\n );\n}\n\ninterface KeyValueKeyInputProps extends React.ComponentProps<\"input\"> {\n asChild?: boolean;\n}\n\nfunction KeyValueKeyInput(props: KeyValueKeyInputProps) {\n const {\n onChange: onChangeProp,\n onPaste: onPasteProp,\n asChild,\n disabled,\n readOnly,\n required,\n ref,\n ...keyInputProps\n } = props;\n\n const context = useKeyValueContext(KEY_INPUT_NAME);\n const itemData = useKeyValueItemContext(KEY_INPUT_NAME);\n const store = useStoreContext(KEY_INPUT_NAME);\n const errors = useStore((state) => state.errors);\n const focusedId = useStore((state) => state.focusedId);\n\n const inputRef = React.useRef<KeyInputElement>(null);\n const composedRef = useComposedRefs(ref, inputRef);\n\n /*\n * ⚠ Khác thượng nguồn (a11y): `KeyValueAdd` ghi id dòng mới vào `focusedId` nhưng bản gốc không\n * bao giờ dùng nó để đưa focus — bấm \"Thêm\" xong focus vẫn đứng ở nút, người dùng bàn phím phải\n * tự Tab ngược lên dòng vừa thêm. Ở đây ô KHOÁ của dòng mới tự nhận focus. Chỉ chạy khi\n * `focusedId` ĐỔI sang dòng này (mà chỉ `KeyValueAdd` ghi nó), nên dòng có sẵn lúc mount và dòng\n * sinh ra do dán không bị cướp focus.\n */\n React.useEffect(() => {\n if (focusedId === itemData.id) {\n inputRef.current?.focus();\n }\n }, [focusedId, itemData.id]);\n\n const propsRef = useAsRef({\n onChange: onChangeProp,\n onPaste: onPasteProp\n });\n\n const isDisabled = disabled || context.disabled;\n const isReadOnly = readOnly || context.readOnly;\n const isRequired = required || context.required;\n const isInvalid = errors[itemData.id]?.key !== undefined;\n\n const onChange = React.useCallback(\n (event: React.ChangeEvent<KeyInputElement>) => {\n const state = store.getState();\n const newValue = state.value.map((item) => {\n if (item.id !== itemData.id) return item;\n const updated = { ...item, key: event.target.value };\n if (context.trim) updated.key = updated.key.trim();\n return updated;\n });\n\n store.setState(\"value\", newValue);\n\n const updatedItemData = newValue.find((item) => item.id === itemData.id);\n if (updatedItemData) {\n const errors: { key?: string; value?: string } = {};\n\n if (context.onKeyValidate) {\n const keyError = context.onKeyValidate(updatedItemData.key, newValue);\n if (keyError) errors.key = keyError;\n }\n\n if (!context.allowDuplicateKeys) {\n const duplicateKey = newValue.find(\n (item) => item.id !== updatedItemData.id && item.key === updatedItemData.key && updatedItemData.key !== \"\"\n );\n if (duplicateKey) {\n errors.key = context.labels.duplicateKey;\n }\n }\n\n if (context.onValueValidate) {\n const valueError = context.onValueValidate(updatedItemData.value, updatedItemData.key, newValue);\n if (valueError) errors.value = valueError;\n }\n\n const newErrorsState = { ...state.errors };\n if (Object.keys(errors).length > 0) {\n newErrorsState[itemData.id] = errors;\n } else {\n delete newErrorsState[itemData.id];\n }\n store.setState(\"errors\", newErrorsState);\n }\n\n propsRef.current.onChange?.(event);\n },\n [store, itemData.id, context, propsRef]\n );\n\n const onPaste = React.useCallback(\n (event: React.ClipboardEvent<KeyInputElement>) => {\n if (!context.enablePaste) return;\n\n propsRef.current.onPaste?.(event);\n if (event.defaultPrevented) return;\n\n const content = event.clipboardData.getData(\"text\");\n const lines = content.split(/\\r?\\n/).filter((line) => line.trim());\n\n if (lines.length > 1) {\n event.preventDefault();\n\n const parsed: ItemData[] = [];\n\n for (const line of lines) {\n let key = \"\";\n let value = \"\";\n\n if (line.includes(\"=\")) {\n const parts = line.split(\"=\");\n key = parts[0]?.trim() ?? \"\";\n value = removeQuotes(parts.slice(1).join(\"=\").trim(), context.stripQuotes);\n } else if (line.includes(\":\")) {\n const parts = line.split(\":\");\n key = parts[0]?.trim() ?? \"\";\n value = removeQuotes(parts.slice(1).join(\":\").trim(), context.stripQuotes);\n } else if (/\\s{2,}|\\t/.test(line)) {\n const parts = line.split(/\\s{2,}|\\t/);\n key = parts[0]?.trim() ?? \"\";\n value = removeQuotes(parts.slice(1).join(\" \").trim(), context.stripQuotes);\n }\n\n if (key) {\n parsed.push({ id: createItemId(), key, value });\n }\n }\n\n if (parsed.length > 0) {\n const state = store.getState();\n const currentIndex = state.value.findIndex((item) => item.id === itemData.id);\n\n let newValue: ItemData[];\n if (itemData.key === \"\" && itemData.value === \"\") {\n newValue = [...state.value.slice(0, currentIndex), ...parsed, ...state.value.slice(currentIndex + 1)];\n } else {\n newValue = [...state.value.slice(0, currentIndex + 1), ...parsed, ...state.value.slice(currentIndex + 1)];\n }\n\n if (context.maxItems !== undefined) {\n newValue = newValue.slice(0, context.maxItems);\n }\n\n store.setState(\"value\", newValue);\n\n if (context.onPaste) {\n context.onPaste(event.nativeEvent as unknown as ClipboardEvent, parsed);\n }\n }\n }\n },\n [context, store, itemData, propsRef]\n );\n\n const KeyInputPrimitive = asChild ? Slot : Input;\n\n return (\n <KeyInputPrimitive\n aria-invalid={isInvalid}\n aria-describedby={isInvalid ? getErrorId(context.rootId, itemData.id, \"key\") : undefined}\n data-slot=\"key-value-key-input\"\n autoCapitalize=\"off\"\n autoComplete=\"off\"\n autoCorrect=\"off\"\n spellCheck=\"false\"\n disabled={isDisabled}\n readOnly={isReadOnly}\n required={isRequired}\n placeholder={context.keyPlaceholder}\n {...keyInputProps}\n ref={composedRef}\n value={itemData.key}\n onChange={onChange}\n onPaste={onPaste}\n />\n );\n}\n\ninterface KeyValueValueInputProps extends Omit<React.ComponentProps<\"textarea\">, \"rows\"> {\n maxRows?: number;\n asChild?: boolean;\n}\n\nfunction KeyValueValueInput(props: KeyValueValueInputProps) {\n const {\n onChange: onChangeProp,\n asChild,\n disabled,\n readOnly,\n required,\n className,\n maxRows,\n style,\n ...valueInputProps\n } = props;\n\n const context = useKeyValueContext(VALUE_INPUT_NAME);\n const itemData = useKeyValueItemContext(VALUE_INPUT_NAME);\n const store = useStoreContext(VALUE_INPUT_NAME);\n const errors = useStore((state) => state.errors);\n\n const propsRef = useAsRef({\n onChange: onChangeProp\n });\n\n const isDisabled = disabled || context.disabled;\n const isReadOnly = readOnly || context.readOnly;\n const isRequired = required || context.required;\n const isInvalid = errors[itemData.id]?.value !== undefined;\n const maxHeight = maxRows ? `calc(${maxRows} * 1.5em + 1rem)` : undefined;\n\n const onChange = React.useCallback(\n (event: React.ChangeEvent<HTMLTextAreaElement>) => {\n propsRef.current.onChange?.(event);\n\n const state = store.getState();\n const newValue = state.value.map((item) => {\n if (item.id !== itemData.id) return item;\n const updated = { ...item, value: event.target.value };\n if (context.trim) updated.value = updated.value.trim();\n return updated;\n });\n\n store.setState(\"value\", newValue);\n\n const updatedItemData = newValue.find((item) => item.id === itemData.id);\n if (updatedItemData) {\n const errors: { key?: string; value?: string } = {};\n\n if (context.onKeyValidate) {\n const keyError = context.onKeyValidate(updatedItemData.key, newValue);\n if (keyError) errors.key = keyError;\n }\n\n if (!context.allowDuplicateKeys) {\n const duplicateKey = newValue.find(\n (item) => item.id !== updatedItemData.id && item.key === updatedItemData.key && updatedItemData.key !== \"\"\n );\n if (duplicateKey) {\n errors.key = context.labels.duplicateKey;\n }\n }\n\n if (context.onValueValidate) {\n const valueError = context.onValueValidate(updatedItemData.value, updatedItemData.key, newValue);\n if (valueError) errors.value = valueError;\n }\n\n const newErrorsState = { ...state.errors };\n if (Object.keys(errors).length > 0) {\n newErrorsState[itemData.id] = errors;\n } else {\n delete newErrorsState[itemData.id];\n }\n store.setState(\"errors\", newErrorsState);\n }\n },\n [store, itemData.id, context, propsRef]\n );\n\n const ValueInputPrimitive = asChild ? Slot : Textarea;\n\n return (\n <ValueInputPrimitive\n aria-invalid={isInvalid}\n aria-describedby={isInvalid ? getErrorId(context.rootId, itemData.id, \"value\") : undefined}\n data-slot=\"key-value-value-input\"\n autoCapitalize=\"off\"\n autoComplete=\"off\"\n autoCorrect=\"off\"\n spellCheck=\"false\"\n disabled={isDisabled}\n readOnly={isReadOnly}\n required={isRequired}\n placeholder={context.valuePlaceholder}\n {...valueInputProps}\n className={cn(\n /*\n * ⚠ Khác thượng nguồn: ô giá trị phải trông như ô khoá (`Input`) đứng ngay cạnh khi còn MỘT\n * dòng. `Textarea` của gói theo comitor-ds: `text-base md:text-sm` + `py-2` (cao 38px ở\n * desktop, 42px và chữ 16px ở mobile), nền `bg-transparent dark:bg-input-fill`, có\n * `shadow-xs`; còn `Input` là `h-9 text-sm bg-background`, không bóng. Ghi đè ở ĐÂY chứ\n * không sửa hai primitive: `text-sm` ở mọi cỡ màn, `min-h-9` + `py-1.5` (dòng chữ 20px cách\n * mép trên 7px — đúng chỗ `Input` căn giữa dòng chữ trong 36px), `bg-background` ở cả hai\n * theme, bỏ bóng. Nhiều dòng thì `field-sizing-content` vẫn cho ô cao dần như cũ.\n */\n \"field-sizing-content min-h-9 resize-none py-1.5 text-sm md:text-sm bg-background dark:bg-background shadow-none\",\n maxRows && \"overflow-y-auto\",\n className\n )}\n style={{\n ...style,\n ...(maxHeight && { maxHeight })\n }}\n value={itemData.value}\n onChange={onChange}\n />\n );\n}\n\ninterface KeyValueRemoveProps extends React.ComponentProps<typeof Button> {}\n\nfunction KeyValueRemove(props: KeyValueRemoveProps) {\n const { onClick: onClickProp, children, className, ...removeProps } = props;\n\n const context = useKeyValueContext(REMOVE_NAME);\n const itemData = useKeyValueItemContext(REMOVE_NAME);\n const store = useStoreContext(REMOVE_NAME);\n\n const propsRef = useAsRef({\n onClick: onClickProp\n });\n const value = useStore((state) => state.value);\n const isDisabled = context.disabled || value.length <= context.minItems;\n const itemIndex = value.findIndex((item) => item.id === itemData.id);\n\n const onClick = React.useCallback(\n (event: React.MouseEvent<RemoveElement>) => {\n propsRef.current.onClick?.(event);\n\n const state = store.getState();\n if (state.value.length <= context.minItems) return;\n\n const itemToRemove = state.value.find((item) => item.id === itemData.id);\n if (!itemToRemove) return;\n\n /*\n * ⚠ Khác thượng nguồn (a11y): nút đang giữ focus biến mất cùng dòng của nó, và focus rơi về\n * `<body>` — người dùng bàn phím phải Tab lại từ đầu trang (WCAG 2.4.3). Nếu nút có focus lúc\n * bấm thì sau khi xoá, đưa focus sang nút xoá của dòng kế (hoặc dòng trước nếu vừa xoá dòng\n * cuối), không còn nút nào dùng được thì sang nút thêm.\n */\n const button = event.currentTarget;\n const hadFocus = button.ownerDocument.activeElement === button;\n const root = button.closest<HTMLElement>('[data-slot=\"key-value\"]');\n const removedIndex = state.value.indexOf(itemToRemove);\n\n const newValue = state.value.filter((item) => item.id !== itemData.id);\n const newErrors = { ...state.errors };\n delete newErrors[itemData.id];\n\n store.setState(\"value\", newValue);\n store.setState(\"errors\", newErrors);\n\n context.onRemove?.(itemToRemove);\n\n if (hadFocus && root) {\n requestAnimationFrame(() => {\n const removeButtons = root.querySelectorAll<HTMLElement>('[data-slot=\"key-value-remove\"]:not(:disabled)');\n const nextTarget =\n removeButtons[Math.min(removedIndex, removeButtons.length - 1)] ??\n root.querySelector<HTMLElement>('[data-slot=\"key-value-add\"]:not(:disabled)');\n nextTarget?.focus();\n });\n }\n },\n [store, context, itemData.id, propsRef]\n );\n\n return (\n <Button\n type=\"button\"\n data-slot=\"key-value-remove\"\n variant=\"outline\"\n size=\"icon\"\n /*\n * ⚠ Khác thượng nguồn (a11y): nút chỉ có icon ✕ và bản gốc không đặt tên nào — trình đọc màn\n * hình đọc \"nút\" trơn, lặp lại ở mọi dòng. Tên mặc định nói RÕ dòng nào: \"Xoá API_KEY\", hoặc\n * \"Xoá dòng 3\" khi khoá còn trống. Đổi qua `labels.remove` của `KeyValue`, hoặc `aria-label`.\n */\n aria-label={context.labels.remove(itemData.key, itemIndex + 1)}\n disabled={isDisabled}\n {...removeProps}\n // ⚠ Khác thượng nguồn: `shrink-0` — nút là mục flex cạnh hai ô `w-full`; thiếu nó thì flex\n // bóp nút còn ~18×36px. `size=\"icon\"` của `Button` đã là ô vuông 36×36 (`h-9 w-9`).\n className={cn(\"shrink-0\", className)}\n onClick={onClick}\n >\n {/* `size-4`: `Button` của gói không tự đặt cỡ cho svg con như shadcn — thiếu là icon 24px. */}\n {children ?? <X aria-hidden=\"true\" className=\"size-4\" />}\n </Button>\n );\n}\n\ntype KeyValueAddProps = React.ComponentProps<typeof Button>;\n\nfunction KeyValueAdd(props: KeyValueAddProps) {\n const { onClick: onClickProp, children, ...addProps } = props;\n\n const context = useKeyValueContext(ADD_NAME);\n const store = useStoreContext(ADD_NAME);\n\n const propsRef = useAsRef({\n onClick: onClickProp\n });\n const value = useStore((state) => state.value);\n const isDisabled = context.disabled || (context.maxItems !== undefined && value.length >= context.maxItems);\n\n const onClick = React.useCallback(\n (event: React.MouseEvent<AddElement>) => {\n propsRef.current.onClick?.(event);\n\n const state = store.getState();\n if (context.maxItems !== undefined && state.value.length >= context.maxItems) {\n return;\n }\n\n const newItem: ItemData = {\n id: createItemId(),\n key: \"\",\n value: \"\"\n };\n\n const newValue = [...state.value, newItem];\n store.setState(\"value\", newValue);\n store.setState(\"focusedId\", newItem.id);\n\n context.onAdd?.(newItem);\n },\n [store, context, propsRef]\n );\n\n return (\n <Button\n type=\"button\"\n data-slot=\"key-value-add\"\n variant=\"outline\"\n disabled={isDisabled}\n {...addProps}\n onClick={onClick}\n >\n {children ?? (\n <>\n <Plus aria-hidden=\"true\" className=\"size-4\" />\n {context.labels.add}\n </>\n )}\n </Button>\n );\n}\n\ninterface KeyValueErrorProps extends DivProps {\n field: Field;\n}\n\nfunction KeyValueError(props: KeyValueErrorProps) {\n const { field, asChild, className, ...errorProps } = props;\n\n const context = useKeyValueContext(ERROR_NAME);\n const itemData = useKeyValueItemContext(ERROR_NAME);\n\n const errors = useStore((state) => state.errors);\n const error = errors[itemData.id]?.[field];\n\n if (!error) return null;\n\n const ErrorPrimitive = asChild ? Slot : \"span\";\n\n return (\n <ErrorPrimitive\n id={getErrorId(context.rootId, itemData.id, field)}\n role=\"alert\"\n {...errorProps}\n className={cn(\n // ⚠ Khác thượng nguồn: `text-destructive` (bậc TÔ NỀN) → `text-destructive-ink`, bậc dành\n // cho chữ trên nền trang — cùng token với chữ lỗi của `Input`.\n \"text-sm font-medium text-destructive-ink\",\n className\n )}\n >\n {error}\n </ErrorPrimitive>\n );\n}\n\nexport {\n type ItemData as KeyValueItemData,\n KeyValue,\n KeyValueAdd,\n type KeyValueAddProps,\n KeyValueError,\n type KeyValueErrorProps,\n KeyValueItem,\n type KeyValueItemProps,\n KeyValueKeyInput,\n type KeyValueKeyInputProps,\n KeyValueList,\n type KeyValueListProps,\n type KeyValueProps,\n KeyValueRemove,\n type KeyValueRemoveProps,\n KeyValueValueInput,\n type KeyValueValueInputProps,\n useStore as useKeyValueStore\n};\n"],"mappings":"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","names":["errors"]}
1
+ {"version":3,"sources":["../../../src/components/ui/key-value.tsx"],"sourcesContent":["\"use client\";\n\n/*\n * Port từ Dice UI (https://diceui.com/docs/components/key-value) — 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 { Plus, X } from \"lucide-react\";\nimport * as React from \"react\";\nimport { useComitorLabels } from \"../../i18n/locale-provider.js\";\nimport { cn } from \"../../lib/cn.js\";\nimport { useComposedRefs } from \"../../lib/compose-refs.js\";\nimport { useAsRef } from \"../../lib/use-as-ref.js\";\nimport { useIsomorphicLayoutEffect } from \"../../lib/use-isomorphic-layout-effect.js\";\nimport { useLazyRef } from \"../../lib/use-lazy-ref.js\";\nimport { VisuallyHiddenInput } from \"../../lib/visually-hidden-input.js\";\nimport { Button } from \"./button.js\";\nimport { Input } from \"./input.js\";\nimport type { KeyValueLabels } from \"./key-value-constants.js\";\nimport { Textarea } from \"./textarea.js\";\n\nconst ROOT_NAME = \"KeyValue\";\nconst LIST_NAME = \"KeyValueList\";\nconst ITEM_NAME = \"KeyValueItem\";\nconst KEY_INPUT_NAME = \"KeyValueKeyInput\";\nconst VALUE_INPUT_NAME = \"KeyValueValueInput\";\nconst REMOVE_NAME = \"KeyValueRemove\";\nconst ADD_NAME = \"KeyValueAdd\";\nconst ERROR_NAME = \"KeyValueError\";\n\ntype Orientation = \"vertical\" | \"horizontal\";\ntype Field = \"key\" | \"value\";\n\ninterface DivProps extends React.ComponentProps<\"div\"> {\n asChild?: boolean;\n}\n\ntype RootElement = React.ComponentRef<typeof KeyValue>;\ntype KeyInputElement = React.ComponentRef<typeof KeyValueKeyInput>;\ntype RemoveElement = React.ComponentRef<typeof KeyValueRemove>;\ntype AddElement = React.ComponentRef<typeof KeyValueAdd>;\n\nfunction getErrorId(rootId: string, itemId: string, field: Field) {\n return `${rootId}-${itemId}-${field}-error`;\n}\n\n/*\n * ⚠ Khác thượng nguồn: bản gốc gọi thẳng `crypto.randomUUID()`. Hàm đó chỉ tồn tại trong NGỮ CẢNH\n * AN TOÀN (HTTPS hoặc localhost) — mở trang quản trị qua `http://` bằng IP nội bộ là `TypeError`\n * ngay lúc render dòng đầu tiên. Id ở đây chỉ làm key của React và nối vào id của thông báo lỗi,\n * không cần ngẫu nhiên mật mã, nên có đường lui.\n */\nlet fallbackIdCounter = 0;\n\nfunction createItemId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n fallbackIdCounter += 1;\n return `kv-${Date.now().toString(36)}-${fallbackIdCounter}`;\n}\n\nfunction removeQuotes(string: string, shouldStrip: boolean): string {\n if (!shouldStrip) return string;\n\n const trimmed = string.trim();\n if ((trimmed.startsWith('\"') && trimmed.endsWith('\"')) || (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))) {\n return trimmed.slice(1, -1);\n }\n return trimmed;\n}\n\ninterface Store {\n subscribe: (callback: () => void) => () => void;\n getState: () => KeyValueState;\n setState: <K extends keyof KeyValueState>(key: K, value: KeyValueState[K]) => void;\n notify: () => void;\n}\n\nfunction useStore<T>(selector: (state: KeyValueState) => T, ogStore?: Store | null): T {\n const contextStore = React.useContext(StoreContext);\n\n const store = ogStore ?? contextStore;\n\n if (!store) {\n throw new Error(`\\`useKeyValueStore\\` phải được gọi bên trong \\`${ROOT_NAME}\\``);\n }\n\n const getSnapshot = React.useCallback(() => selector(store.getState()), [store, selector]);\n\n return React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);\n}\n\ninterface ItemData {\n id: string;\n key: string;\n value: string;\n}\n\ninterface KeyValueState {\n value: ItemData[];\n focusedId: string | null;\n errors: Record<string, { key?: string; value?: string }>;\n}\n\nconst StoreContext = React.createContext<Store | null>(null);\n\nfunction useStoreContext(consumerName: string) {\n const context = React.useContext(StoreContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\ninterface KeyValueContextValue {\n onPaste?: (event: ClipboardEvent, items: ItemData[]) => void;\n onAdd?: (value: ItemData) => void;\n onRemove?: (value: ItemData) => void;\n onKeyValidate?: (key: string, value: ItemData[]) => string | undefined;\n onValueValidate?: (value: string, key: string, items: ItemData[]) => string | undefined;\n rootId: string;\n maxItems?: number;\n minItems: number;\n keyPlaceholder: string;\n valuePlaceholder: string;\n labels: KeyValueLabels;\n allowDuplicateKeys: boolean;\n enablePaste: boolean;\n trim: boolean;\n stripQuotes: boolean;\n disabled: boolean;\n readOnly: boolean;\n required: boolean;\n}\n\nconst KeyValueContext = React.createContext<KeyValueContextValue | null>(null);\n\nfunction useKeyValueContext(consumerName: string) {\n const context = React.useContext(KeyValueContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${ROOT_NAME}\\``);\n }\n return context;\n}\n\n/**\n * Ghi MỘT ô (khoá hoặc giá trị) của một dòng vào store rồi kiểm lỗi lại dòng đó. Dùng chung cho\n * hai ô nhập — trước `3.0.1` khối này chép nguyên hai lần, mỗi ô một bản.\n */\nfunction commitItemField(store: Store, context: KeyValueContextValue, itemId: string, field: Field, text: string) {\n const state = store.getState();\n const newValue = state.value.map((item) => (item.id === itemId ? { ...item, [field]: text } : item));\n\n store.setState(\"value\", newValue);\n\n const updatedItemData = newValue.find((item) => item.id === itemId);\n if (!updatedItemData) return;\n\n const errors: { key?: string; value?: string } = {};\n\n if (context.onKeyValidate) {\n const keyError = context.onKeyValidate(updatedItemData.key, newValue);\n if (keyError) errors.key = keyError;\n }\n\n if (!context.allowDuplicateKeys) {\n const duplicateKey = newValue.find(\n (item) => item.id !== updatedItemData.id && item.key === updatedItemData.key && updatedItemData.key !== \"\"\n );\n if (duplicateKey) {\n errors.key = context.labels.duplicateKey;\n }\n }\n\n if (context.onValueValidate) {\n const valueError = context.onValueValidate(updatedItemData.value, updatedItemData.key, newValue);\n if (valueError) errors.value = valueError;\n }\n\n const newErrorsState = { ...state.errors };\n if (Object.keys(errors).length > 0) {\n newErrorsState[itemId] = errors;\n } else {\n delete newErrorsState[itemId];\n }\n store.setState(\"errors\", newErrorsState);\n}\n\n/*\n * ⚠ Khác thượng nguồn (3.0.1): với `trim`, Ô NHẬP hiện đúng chữ đang gõ, còn STORE nhận bản đã cắt.\n * Bản gốc cắt ngay trong `onChange` rồi đưa chính chuỗi đã cắt về lại ô, nên dấu cách vừa gõ ở cuối\n * biến mất trước khi chữ kế tiếp tới — với `trim` mặc định `true`, không gõ được \"Contract term\" hay\n * \"Bearer token\" theo cách bình thường (ra \"Contractterm\").\n * Mọi thứ app nhận (`onValueChange`, ô ẩn trong form, kiểm lỗi, trùng khoá) vẫn LUÔN là bản đã cắt,\n * đúng như bản gốc — kể cả khi Enter gửi form ngay sau một dấu cách. Chỉ phần hiển thị giữ khoảng\n * trắng, cho tới khi rời ô.\n */\nfunction useTrimDraft(committed: string) {\n const [draft, setDraft] = React.useState<string | null>(null);\n // Bản nháp chỉ được hiện khi nó còn khớp store: store đổi từ nơi khác (app đặt `value`, dán nhiều\n // dòng) thì hiện giá trị mới.\n const shown = draft !== null && draft.trim() === committed ? draft : committed;\n return [shown, setDraft] as const;\n}\n\ninterface KeyValueProps extends Omit<DivProps, \"onPaste\" | \"defaultValue\"> {\n id?: string;\n defaultValue?: ItemData[];\n value?: ItemData[];\n onValueChange?: (value: ItemData[]) => void;\n maxItems?: number;\n minItems?: number;\n /** Placeholder của ô khoá — thắng `labels.keyPlaceholder` (mặc định \"Key\"). */\n keyPlaceholder?: string;\n /** Placeholder của ô giá trị — thắng `labels.valuePlaceholder` (mặc định \"Value\"). */\n valuePlaceholder?: string;\n /**\n * Chuỗi hiển thị và chuỗi cho trình đọc màn hình — truyền MỘT PHẦN là đủ, phần còn lại theo\n * namespace `keyValue` của `ComitorLocaleProvider` (mặc định tiếng Anh). ⚠ Thêm so với thượng\n * nguồn (bản gốc chôn cứng \"Add\" / \"Duplicate key\" và để nút xoá không có tên).\n */\n labels?: Partial<KeyValueLabels>;\n name?: string;\n allowDuplicateKeys?: boolean;\n enablePaste?: boolean;\n trim?: boolean;\n stripQuotes?: boolean;\n disabled?: boolean;\n readOnly?: boolean;\n required?: boolean;\n onPaste?: (event: ClipboardEvent, items: ItemData[]) => void;\n onAdd?: (value: ItemData) => void;\n onRemove?: (value: ItemData) => void;\n onKeyValidate?: (key: string, value: ItemData[]) => string | undefined;\n onValueValidate?: (value: string, key: string, items: ItemData[]) => string | undefined;\n}\n\n/**\n * KeyValue — danh sách cặp khoá/giá trị sửa được: trường tuỳ biến của bản ghi CRM, header /\n * metadata của webhook ở trang quản trị. Dán nhiều dòng `KEY=value` (hoặc `KEY: value`, hoặc\n * cách bằng tab) vào ô khoá là tách thành nhiều cặp.\n */\nfunction KeyValue(props: KeyValueProps) {\n const {\n value: valueProp,\n defaultValue,\n onValueChange,\n onPaste,\n onAdd,\n onRemove,\n onKeyValidate,\n onValueValidate,\n maxItems,\n minItems = 0,\n labels: labelsProp,\n keyPlaceholder: keyPlaceholderProp,\n valuePlaceholder: valuePlaceholderProp,\n allowDuplicateKeys = false,\n asChild,\n enablePaste = true,\n trim = true,\n stripQuotes = true,\n disabled = false,\n readOnly = false,\n required = false,\n className,\n id,\n name,\n ref,\n ...rootProps\n } = props;\n\n const instanceId = React.useId();\n const rootId = id ?? instanceId;\n\n const labels = useComitorLabels(\"keyValue\", labelsProp);\n const keyPlaceholder = keyPlaceholderProp ?? labels.keyPlaceholder;\n const valuePlaceholder = valuePlaceholderProp ?? labels.valuePlaceholder;\n\n const [formTrigger, setFormTrigger] = React.useState<RootElement | null>(null);\n const composedRef = useComposedRefs(ref, (node) => setFormTrigger(node));\n const isFormControl = formTrigger ? !!formTrigger.closest(\"form\") : true;\n\n const listenersRef = useLazyRef(() => new Set<() => void>());\n const stateRef = useLazyRef<KeyValueState>(() => ({\n value: valueProp ?? defaultValue ?? [{ id: createItemId(), key: \"\", value: \"\" }],\n focusedId: null,\n errors: {}\n }));\n const propsRef = useAsRef({ onValueChange });\n\n const store = React.useMemo<Store>(() => {\n return {\n subscribe: (cb) => {\n listenersRef.current.add(cb);\n return () => listenersRef.current.delete(cb);\n },\n getState: () => stateRef.current,\n setState: (key, val) => {\n if (Object.is(stateRef.current[key], val)) return;\n\n if (key === \"value\" && Array.isArray(val)) {\n stateRef.current.value = val as ItemData[];\n propsRef.current.onValueChange?.(val as ItemData[]);\n } else {\n stateRef.current[key] = val;\n }\n\n store.notify();\n },\n notify: () => {\n for (const cb of listenersRef.current) {\n cb();\n }\n }\n };\n }, [listenersRef, stateRef, propsRef]);\n\n const value = useStore((state) => state.value, store);\n const errors = useStore((state) => state.errors, store);\n const isInvalid = Object.keys(errors).length > 0;\n\n useIsomorphicLayoutEffect(() => {\n if (valueProp !== undefined) {\n store.setState(\"value\", valueProp);\n }\n }, [valueProp]);\n\n const contextValue = React.useMemo<KeyValueContextValue>(\n () => ({\n onPaste,\n onAdd,\n onRemove,\n onKeyValidate,\n onValueValidate,\n rootId,\n maxItems,\n minItems,\n keyPlaceholder,\n valuePlaceholder,\n labels,\n allowDuplicateKeys,\n enablePaste,\n trim,\n stripQuotes,\n disabled,\n readOnly,\n required\n }),\n [\n onPaste,\n onAdd,\n onRemove,\n onKeyValidate,\n onValueValidate,\n rootId,\n disabled,\n readOnly,\n required,\n maxItems,\n minItems,\n keyPlaceholder,\n valuePlaceholder,\n labels,\n allowDuplicateKeys,\n enablePaste,\n trim,\n stripQuotes\n ]\n );\n\n const RootPrimitive = asChild ? Slot : \"div\";\n\n return (\n <StoreContext.Provider value={store}>\n <KeyValueContext.Provider value={contextValue}>\n <RootPrimitive\n id={id}\n data-slot=\"key-value\"\n data-disabled={disabled ? \"\" : undefined}\n data-invalid={isInvalid ? \"\" : undefined}\n data-readonly={readOnly ? \"\" : undefined}\n {...rootProps}\n ref={composedRef}\n className={cn(\"flex flex-col gap-2\", className)}\n />\n {isFormControl && (\n <VisuallyHiddenInput\n type=\"hidden\"\n control={formTrigger}\n name={name}\n value={value}\n disabled={disabled}\n readOnly={readOnly}\n required={required}\n />\n )}\n </KeyValueContext.Provider>\n </StoreContext.Provider>\n );\n}\n\ninterface KeyValueListProps extends DivProps {\n orientation?: Orientation;\n}\n\nfunction KeyValueList(props: KeyValueListProps) {\n const { orientation = \"vertical\", asChild, className, ...listProps } = props;\n\n const value = useStore((state) => state.value);\n\n const ListPrimitive = asChild ? Slot : \"div\";\n\n return (\n <ListPrimitive\n role=\"list\"\n /*\n * ⚠ Khác thượng nguồn (a11y): bỏ `aria-orientation`. Thuộc tính đó KHÔNG được phép trên\n * `role=\"list\"` (ARIA 1.2 chỉ cho nó ở listbox, menu, tablist, toolbar, radiogroup, slider…)\n * — axe báo `aria-allowed-attr`. Hướng vẫn còn ở `data-orientation` cho CSS.\n */\n data-slot=\"key-value-list\"\n data-orientation={orientation}\n {...listProps}\n className={cn(\"flex\", orientation === \"vertical\" ? \"flex-col gap-2\" : \"flex-row gap-2\", className)}\n >\n {value.map((item) => {\n const children = React.Children.toArray(props.children);\n\n return (\n <KeyValueItemContext.Provider key={item.id} value={item}>\n {children}\n </KeyValueItemContext.Provider>\n );\n })}\n </ListPrimitive>\n );\n}\n\nconst KeyValueItemContext = React.createContext<ItemData | null>(null);\n\nfunction useKeyValueItemContext(consumerName: string) {\n const context = React.useContext(KeyValueItemContext);\n if (!context) {\n throw new Error(`\\`${consumerName}\\` phải nằm bên trong \\`${LIST_NAME}\\``);\n }\n return context;\n}\n\ninterface KeyValueItemProps extends React.ComponentProps<\"div\"> {\n asChild?: boolean;\n}\n\nfunction KeyValueItem(props: KeyValueItemProps) {\n const { asChild, className, ...itemProps } = props;\n const itemData = useKeyValueItemContext(ITEM_NAME);\n\n const focusedId = useStore((state) => state.focusedId);\n\n const ItemPrimitive = asChild ? Slot : \"div\";\n\n return (\n <ItemPrimitive\n role=\"listitem\"\n data-slot=\"key-value-item\"\n data-highlighted={focusedId === itemData.id ? \"\" : undefined}\n {...itemProps}\n className={cn(\"flex items-start gap-2\", className)}\n />\n );\n}\n\ninterface KeyValueKeyInputProps extends React.ComponentProps<\"input\"> {\n asChild?: boolean;\n}\n\nfunction KeyValueKeyInput(props: KeyValueKeyInputProps) {\n const {\n onChange: onChangeProp,\n onBlur: onBlurProp,\n onPaste: onPasteProp,\n asChild,\n disabled,\n readOnly,\n required,\n ref,\n ...keyInputProps\n } = props;\n\n const context = useKeyValueContext(KEY_INPUT_NAME);\n const itemData = useKeyValueItemContext(KEY_INPUT_NAME);\n const store = useStoreContext(KEY_INPUT_NAME);\n const errors = useStore((state) => state.errors);\n const focusedId = useStore((state) => state.focusedId);\n\n const inputRef = React.useRef<KeyInputElement>(null);\n const composedRef = useComposedRefs(ref, inputRef);\n\n /*\n * ⚠ Khác thượng nguồn (a11y): `KeyValueAdd` ghi id dòng mới vào `focusedId` nhưng bản gốc không\n * bao giờ dùng nó để đưa focus — bấm \"Thêm\" xong focus vẫn đứng ở nút, người dùng bàn phím phải\n * tự Tab ngược lên dòng vừa thêm. Ở đây ô KHOÁ của dòng mới tự nhận focus. Chỉ chạy khi\n * `focusedId` ĐỔI sang dòng này (mà chỉ `KeyValueAdd` ghi nó), nên dòng có sẵn lúc mount và dòng\n * sinh ra do dán không bị cướp focus.\n */\n React.useEffect(() => {\n if (focusedId === itemData.id) {\n inputRef.current?.focus();\n }\n }, [focusedId, itemData.id]);\n\n const propsRef = useAsRef({\n onChange: onChangeProp,\n onBlur: onBlurProp,\n onPaste: onPasteProp\n });\n\n const isDisabled = disabled || context.disabled;\n const isReadOnly = readOnly || context.readOnly;\n const isRequired = required || context.required;\n const isInvalid = errors[itemData.id]?.key !== undefined;\n const [shownKey, setKeyDraft] = useTrimDraft(itemData.key);\n\n const onChange = React.useCallback(\n (event: React.ChangeEvent<KeyInputElement>) => {\n const text = event.target.value;\n if (context.trim) setKeyDraft(text);\n commitItemField(store, context, itemData.id, \"key\", context.trim ? text.trim() : text);\n propsRef.current.onChange?.(event);\n },\n [store, itemData.id, context, propsRef, setKeyDraft]\n );\n\n const onBlur = React.useCallback(\n (event: React.FocusEvent<KeyInputElement>) => {\n propsRef.current.onBlur?.(event);\n setKeyDraft(null);\n },\n [propsRef, setKeyDraft]\n );\n\n const onPaste = React.useCallback(\n (event: React.ClipboardEvent<KeyInputElement>) => {\n if (!context.enablePaste) return;\n\n propsRef.current.onPaste?.(event);\n if (event.defaultPrevented) return;\n\n const content = event.clipboardData.getData(\"text\");\n const lines = content.split(/\\r?\\n/).filter((line) => line.trim());\n\n if (lines.length > 1) {\n event.preventDefault();\n\n const parsed: ItemData[] = [];\n\n for (const line of lines) {\n let key = \"\";\n let value = \"\";\n\n if (line.includes(\"=\")) {\n const parts = line.split(\"=\");\n key = parts[0]?.trim() ?? \"\";\n value = removeQuotes(parts.slice(1).join(\"=\").trim(), context.stripQuotes);\n } else if (line.includes(\":\")) {\n const parts = line.split(\":\");\n key = parts[0]?.trim() ?? \"\";\n value = removeQuotes(parts.slice(1).join(\":\").trim(), context.stripQuotes);\n } else if (/\\s{2,}|\\t/.test(line)) {\n const parts = line.split(/\\s{2,}|\\t/);\n key = parts[0]?.trim() ?? \"\";\n value = removeQuotes(parts.slice(1).join(\" \").trim(), context.stripQuotes);\n }\n\n if (key) {\n parsed.push({ id: createItemId(), key, value });\n }\n }\n\n if (parsed.length > 0) {\n const state = store.getState();\n const currentIndex = state.value.findIndex((item) => item.id === itemData.id);\n\n let newValue: ItemData[];\n if (itemData.key === \"\" && itemData.value === \"\") {\n newValue = [...state.value.slice(0, currentIndex), ...parsed, ...state.value.slice(currentIndex + 1)];\n } else {\n newValue = [...state.value.slice(0, currentIndex + 1), ...parsed, ...state.value.slice(currentIndex + 1)];\n }\n\n if (context.maxItems !== undefined) {\n newValue = newValue.slice(0, context.maxItems);\n }\n\n store.setState(\"value\", newValue);\n\n if (context.onPaste) {\n context.onPaste(event.nativeEvent as unknown as ClipboardEvent, parsed);\n }\n }\n }\n },\n [context, store, itemData, propsRef]\n );\n\n const KeyInputPrimitive = asChild ? Slot : Input;\n\n return (\n <KeyInputPrimitive\n aria-invalid={isInvalid}\n aria-describedby={isInvalid ? getErrorId(context.rootId, itemData.id, \"key\") : undefined}\n data-slot=\"key-value-key-input\"\n autoCapitalize=\"off\"\n autoComplete=\"off\"\n autoCorrect=\"off\"\n spellCheck=\"false\"\n disabled={isDisabled}\n readOnly={isReadOnly}\n required={isRequired}\n placeholder={context.keyPlaceholder}\n {...keyInputProps}\n ref={composedRef}\n value={shownKey}\n onChange={onChange}\n onBlur={onBlur}\n onPaste={onPaste}\n />\n );\n}\n\ninterface KeyValueValueInputProps extends Omit<React.ComponentProps<\"textarea\">, \"rows\"> {\n maxRows?: number;\n asChild?: boolean;\n}\n\nfunction KeyValueValueInput(props: KeyValueValueInputProps) {\n const {\n onChange: onChangeProp,\n onBlur: onBlurProp,\n asChild,\n disabled,\n readOnly,\n required,\n className,\n maxRows,\n style,\n ...valueInputProps\n } = props;\n\n const context = useKeyValueContext(VALUE_INPUT_NAME);\n const itemData = useKeyValueItemContext(VALUE_INPUT_NAME);\n const store = useStoreContext(VALUE_INPUT_NAME);\n const errors = useStore((state) => state.errors);\n\n const propsRef = useAsRef({\n onChange: onChangeProp,\n onBlur: onBlurProp\n });\n\n const isDisabled = disabled || context.disabled;\n const isReadOnly = readOnly || context.readOnly;\n const isRequired = required || context.required;\n const isInvalid = errors[itemData.id]?.value !== undefined;\n const maxHeight = maxRows ? `calc(${maxRows} * 1.5em + 1rem)` : undefined;\n const [shownValue, setValueDraft] = useTrimDraft(itemData.value);\n\n const onChange = React.useCallback(\n (event: React.ChangeEvent<HTMLTextAreaElement>) => {\n propsRef.current.onChange?.(event);\n const text = event.target.value;\n if (context.trim) setValueDraft(text);\n commitItemField(store, context, itemData.id, \"value\", context.trim ? text.trim() : text);\n },\n [store, itemData.id, context, propsRef, setValueDraft]\n );\n\n const onBlur = React.useCallback(\n (event: React.FocusEvent<HTMLTextAreaElement>) => {\n propsRef.current.onBlur?.(event);\n setValueDraft(null);\n },\n [propsRef, setValueDraft]\n );\n\n const ValueInputPrimitive = asChild ? Slot : Textarea;\n\n return (\n <ValueInputPrimitive\n aria-invalid={isInvalid}\n aria-describedby={isInvalid ? getErrorId(context.rootId, itemData.id, \"value\") : undefined}\n data-slot=\"key-value-value-input\"\n autoCapitalize=\"off\"\n autoComplete=\"off\"\n autoCorrect=\"off\"\n spellCheck=\"false\"\n disabled={isDisabled}\n readOnly={isReadOnly}\n required={isRequired}\n placeholder={context.valuePlaceholder}\n {...valueInputProps}\n className={cn(\n /*\n * ⚠ Khác thượng nguồn: ô giá trị phải trông như ô khoá (`Input`) đứng ngay cạnh khi còn MỘT\n * dòng. `Textarea` của gói theo comitor-ds: `text-base md:text-sm` + `py-2` (cao 38px ở\n * desktop, 42px và chữ 16px ở mobile), nền `bg-transparent dark:bg-input-fill`, có\n * `shadow-xs`; còn `Input` là `h-9 text-sm bg-background`, không bóng. Ghi đè ở ĐÂY chứ\n * không sửa hai primitive: `text-sm` ở mọi cỡ màn, `min-h-9` + `py-1.5` (dòng chữ 20px cách\n * mép trên 7px — đúng chỗ `Input` căn giữa dòng chữ trong 36px), `bg-background` ở cả hai\n * theme, bỏ bóng. Nhiều dòng thì `field-sizing-content` vẫn cho ô cao dần như cũ.\n */\n \"field-sizing-content min-h-9 resize-none py-1.5 text-sm md:text-sm bg-background dark:bg-background shadow-none\",\n maxRows && \"overflow-y-auto\",\n className\n )}\n style={{\n ...style,\n ...(maxHeight && { maxHeight })\n }}\n value={shownValue}\n onChange={onChange}\n onBlur={onBlur}\n />\n );\n}\n\ninterface KeyValueRemoveProps extends React.ComponentProps<typeof Button> {}\n\nfunction KeyValueRemove(props: KeyValueRemoveProps) {\n const { onClick: onClickProp, children, className, ...removeProps } = props;\n\n const context = useKeyValueContext(REMOVE_NAME);\n const itemData = useKeyValueItemContext(REMOVE_NAME);\n const store = useStoreContext(REMOVE_NAME);\n\n const propsRef = useAsRef({\n onClick: onClickProp\n });\n const value = useStore((state) => state.value);\n const isDisabled = context.disabled || value.length <= context.minItems;\n const itemIndex = value.findIndex((item) => item.id === itemData.id);\n\n const onClick = React.useCallback(\n (event: React.MouseEvent<RemoveElement>) => {\n propsRef.current.onClick?.(event);\n\n const state = store.getState();\n if (state.value.length <= context.minItems) return;\n\n const itemToRemove = state.value.find((item) => item.id === itemData.id);\n if (!itemToRemove) return;\n\n /*\n * ⚠ Khác thượng nguồn (a11y): nút đang giữ focus biến mất cùng dòng của nó, và focus rơi về\n * `<body>` — người dùng bàn phím phải Tab lại từ đầu trang (WCAG 2.4.3). Nếu nút có focus lúc\n * bấm thì sau khi xoá, đưa focus sang nút xoá của dòng kế (hoặc dòng trước nếu vừa xoá dòng\n * cuối), không còn nút nào dùng được thì sang nút thêm.\n */\n const button = event.currentTarget;\n const hadFocus = button.ownerDocument.activeElement === button;\n const root = button.closest<HTMLElement>('[data-slot=\"key-value\"]');\n const removedIndex = state.value.indexOf(itemToRemove);\n\n const newValue = state.value.filter((item) => item.id !== itemData.id);\n const newErrors = { ...state.errors };\n delete newErrors[itemData.id];\n\n store.setState(\"value\", newValue);\n store.setState(\"errors\", newErrors);\n\n context.onRemove?.(itemToRemove);\n\n if (hadFocus && root) {\n requestAnimationFrame(() => {\n const removeButtons = root.querySelectorAll<HTMLElement>('[data-slot=\"key-value-remove\"]:not(:disabled)');\n const nextTarget =\n removeButtons[Math.min(removedIndex, removeButtons.length - 1)] ??\n root.querySelector<HTMLElement>('[data-slot=\"key-value-add\"]:not(:disabled)');\n nextTarget?.focus();\n });\n }\n },\n [store, context, itemData.id, propsRef]\n );\n\n return (\n <Button\n type=\"button\"\n data-slot=\"key-value-remove\"\n variant=\"outline\"\n size=\"icon\"\n /*\n * ⚠ Khác thượng nguồn (a11y): nút chỉ có icon ✕ và bản gốc không đặt tên nào — trình đọc màn\n * hình đọc \"nút\" trơn, lặp lại ở mọi dòng. Tên mặc định nói RÕ dòng nào: \"Remove API_KEY\",\n * hoặc \"Remove row 3\" khi khoá còn trống. Đổi qua `labels.remove` của `KeyValue`, hoặc `aria-label`.\n */\n aria-label={context.labels.remove(itemData.key, itemIndex + 1)}\n disabled={isDisabled}\n {...removeProps}\n // ⚠ Khác thượng nguồn: `shrink-0` — nút là mục flex cạnh hai ô `w-full`; thiếu nó thì flex\n // bóp nút còn ~18×36px. `size=\"icon\"` của `Button` đã là ô vuông 36×36 (`h-9 w-9`).\n className={cn(\"shrink-0\", className)}\n onClick={onClick}\n >\n {/* `size-4`: `Button` của gói không tự đặt cỡ cho svg con như shadcn — thiếu là icon 24px. */}\n {children ?? <X aria-hidden=\"true\" className=\"size-4\" />}\n </Button>\n );\n}\n\ntype KeyValueAddProps = React.ComponentProps<typeof Button>;\n\nfunction KeyValueAdd(props: KeyValueAddProps) {\n const { onClick: onClickProp, children, ...addProps } = props;\n\n const context = useKeyValueContext(ADD_NAME);\n const store = useStoreContext(ADD_NAME);\n\n const propsRef = useAsRef({\n onClick: onClickProp\n });\n const value = useStore((state) => state.value);\n const isDisabled = context.disabled || (context.maxItems !== undefined && value.length >= context.maxItems);\n\n const onClick = React.useCallback(\n (event: React.MouseEvent<AddElement>) => {\n propsRef.current.onClick?.(event);\n\n const state = store.getState();\n if (context.maxItems !== undefined && state.value.length >= context.maxItems) {\n return;\n }\n\n const newItem: ItemData = {\n id: createItemId(),\n key: \"\",\n value: \"\"\n };\n\n const newValue = [...state.value, newItem];\n store.setState(\"value\", newValue);\n store.setState(\"focusedId\", newItem.id);\n\n context.onAdd?.(newItem);\n },\n [store, context, propsRef]\n );\n\n return (\n <Button\n type=\"button\"\n data-slot=\"key-value-add\"\n variant=\"outline\"\n disabled={isDisabled}\n {...addProps}\n onClick={onClick}\n >\n {children ?? (\n <>\n <Plus aria-hidden=\"true\" className=\"size-4\" />\n {context.labels.add}\n </>\n )}\n </Button>\n );\n}\n\ninterface KeyValueErrorProps extends DivProps {\n field: Field;\n}\n\nfunction KeyValueError(props: KeyValueErrorProps) {\n const { field, asChild, className, ...errorProps } = props;\n\n const context = useKeyValueContext(ERROR_NAME);\n const itemData = useKeyValueItemContext(ERROR_NAME);\n\n const errors = useStore((state) => state.errors);\n const error = errors[itemData.id]?.[field];\n\n if (!error) return null;\n\n const ErrorPrimitive = asChild ? Slot : \"span\";\n\n return (\n <ErrorPrimitive\n id={getErrorId(context.rootId, itemData.id, field)}\n role=\"alert\"\n {...errorProps}\n className={cn(\n // ⚠ Khác thượng nguồn: `text-destructive` (bậc TÔ NỀN) → `text-destructive-ink`, bậc dành\n // cho chữ trên nền trang — cùng token với chữ lỗi của `Input`.\n \"text-sm font-medium text-destructive-ink\",\n className\n )}\n >\n {error}\n </ErrorPrimitive>\n );\n}\n\nexport {\n type ItemData as KeyValueItemData,\n KeyValue,\n KeyValueAdd,\n type KeyValueAddProps,\n KeyValueError,\n type KeyValueErrorProps,\n KeyValueItem,\n type KeyValueItemProps,\n KeyValueKeyInput,\n type KeyValueKeyInputProps,\n KeyValueList,\n type KeyValueListProps,\n type KeyValueProps,\n KeyValueRemove,\n type KeyValueRemoveProps,\n KeyValueValueInput,\n type KeyValueValueInputProps,\n useStore as useKeyValueStore\n};\n"],"mappings":"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","names":[]}
@@ -1,5 +1,4 @@
1
- declare const DEFAULT_CURRENCY = "VND";
2
- declare const DEFAULT_LOCALE = "vi-VN";
1
+ declare const DEFAULT_CURRENCY = "USD";
3
2
  declare const NUMERIC_MASK_PATTERNS: RegExp;
4
3
  declare const CURRENCY_PERCENTAGE_SYMBOLS: RegExp;
5
4
  declare const REGEX_CACHE: {
@@ -96,4 +95,4 @@ declare function getPatternCaretPosition(opts: {
96
95
  previousUnmasked?: string;
97
96
  }): number;
98
97
 
99
- export { CURRENCY_PERCENTAGE_SYMBOLS, DEFAULT_CURRENCY, DEFAULT_LOCALE, MASK_PATTERNS, type MaskPattern, type MaskPatternKey, NUMERIC_MASK_PATTERNS, REGEX_CACHE, type TransformOptions, applyCurrencyMask, applyMask, applyPercentageMask, fromUnmaskedIndex, getCurrencyCaretPosition, getPatternCaretPosition, getUnmaskedValue, isCurrencyAtEnd, isCurrencyMask, toUnmaskedIndex };
98
+ export { CURRENCY_PERCENTAGE_SYMBOLS, DEFAULT_CURRENCY, MASK_PATTERNS, type MaskPattern, type MaskPatternKey, NUMERIC_MASK_PATTERNS, REGEX_CACHE, type TransformOptions, applyCurrencyMask, applyMask, applyPercentageMask, fromUnmaskedIndex, getCurrencyCaretPosition, getPatternCaretPosition, getUnmaskedValue, isCurrencyAtEnd, isCurrencyMask, toUnmaskedIndex };
@@ -1,7 +1,7 @@
1
1
  const PAST_YEARS_LIMIT = 120;
2
2
  const FUTURE_YEARS_LIMIT = 10;
3
- const DEFAULT_CURRENCY = "VND";
4
- const DEFAULT_LOCALE = "vi-VN";
3
+ const DEFAULT_CURRENCY = "USD";
4
+ const DEFAULT_LOCALE = "en-US";
5
5
  const NUMERIC_MASK_PATTERNS = /^(phone|zipCode|zipCodeExtended|ssn|ein|time|date|creditCard|creditCardExpiry)$/;
6
6
  const CURRENCY_PERCENTAGE_SYMBOLS = /[€$%]/;
7
7
  const formattersCache = /* @__PURE__ */ new Map();
@@ -111,6 +111,27 @@ function getCurrencyFractionDigits(opts) {
111
111
  fractionDigitsCache.set(key, digits);
112
112
  return digits;
113
113
  }
114
+ function findCurrencyDecimalIndex(cleaned, decimal, group) {
115
+ const lastDot = cleaned.lastIndexOf(".");
116
+ const lastComma = cleaned.lastIndexOf(",");
117
+ if (lastDot !== -1 && lastComma !== -1) return Math.max(lastDot, lastComma);
118
+ const separator = lastDot !== -1 ? "." : lastComma !== -1 ? "," : null;
119
+ if (!separator) return -1;
120
+ const last = cleaned.lastIndexOf(separator);
121
+ if (separator === decimal) return last;
122
+ if (separator === group) {
123
+ return separator === "." && decimal === "," && last === cleaned.length - 1 ? last : -1;
124
+ }
125
+ const occurrences = cleaned.split(separator).length - 1;
126
+ const digitsAfter = cleaned.length - last - 1;
127
+ return occurrences === 1 && digitsAfter !== 3 ? last : -1;
128
+ }
129
+ function isCanonicalAmount(value, fractionDigits) {
130
+ const dot = value.indexOf(".");
131
+ const integerPart = dot === -1 ? value : value.slice(0, dot);
132
+ const fractionPart = dot === -1 ? "" : value.slice(dot + 1);
133
+ return /^\d*$/.test(integerPart) && /^\d*$/.test(fractionPart) && fractionPart.length <= fractionDigits;
134
+ }
114
135
  function isCurrencyAtEnd(opts) {
115
136
  const { locale, currency } = opts;
116
137
  const key = `${locale}|${currency}`;
@@ -244,88 +265,27 @@ const MASK_PATTERNS = {
244
265
  validate: (value) => REGEX_CACHE.zipCodeExtended.test(value.replace(REGEX_CACHE.nonDigits, ""))
245
266
  },
246
267
  /**
247
- * Tiền tệ — định dạng thật đi qua `Intl.NumberFormat` theo `currency`/`locale` (mặc định VND /
248
- * vi-VN → `1.234.567 ₫`). Chuỗi `pattern` ở đây chỉ là DẤU NHẬN DẠNG cho nhánh tiền tệ, không
249
- * phải khuôn chữ số.
268
+ * Tiền tệ — định dạng thật đi qua `Intl.NumberFormat` theo `currency`/`locale` (mặc định USD /
269
+ * en-US → `$1,234,567`; `VND` / `vi-VN` → `1.234.567 ₫`). Chuỗi `pattern` ở đây chỉ là DẤU NHẬN
270
+ * DẠNG cho nhánh tiền tệ, không phải khuôn chữ số.
250
271
  */
251
272
  currency: {
252
273
  pattern: "$###,###.##",
253
274
  transform: (value, { currency = DEFAULT_CURRENCY, locale = DEFAULT_LOCALE } = {}) => {
254
- if (getCurrencyFractionDigits({ currency, locale }) === 0) {
275
+ const fractionDigits = getCurrencyFractionDigits({ currency, locale });
276
+ if (fractionDigits === 0) {
255
277
  return value.replace(REGEX_CACHE.nonDigits, "");
256
278
  }
257
- let localeDecimalSeparator = ".";
258
- try {
259
- const formatter = getCachedFormatter(locale, {
260
- currency,
261
- minimumFractionDigits: 0,
262
- maximumFractionDigits: 2
263
- });
264
- const parts = formatter.formatToParts(1234.5);
265
- const decimalPart = parts.find((part) => part.type === "decimal");
266
- if (decimalPart) localeDecimalSeparator = decimalPart.value;
267
- } catch {
268
- }
279
+ if (isCanonicalAmount(value, fractionDigits)) return value;
280
+ const { decimal, group } = getCachedCurrencySymbols({ currency, locale });
269
281
  const cleaned = value.replace(REGEX_CACHE.nonCurrencyChars, "");
270
- const dotIndex = cleaned.indexOf(".");
271
- const commaIndex = cleaned.indexOf(",");
272
- let hasDecimalSeparator = false;
273
- let decimalIndex = -1;
274
- if (localeDecimalSeparator === ",") {
275
- const lastCommaIndex = cleaned.lastIndexOf(",");
276
- if (lastCommaIndex !== -1) {
277
- const afterComma = cleaned.substring(lastCommaIndex + 1);
278
- if (afterComma.length <= 2 && /^\d*$/.test(afterComma)) {
279
- hasDecimalSeparator = true;
280
- decimalIndex = lastCommaIndex;
281
- }
282
- }
283
- if (!hasDecimalSeparator && dotIndex !== -1) {
284
- const afterDot = cleaned.substring(dotIndex + 1);
285
- if (afterDot.length <= 2 && /^\d*$/.test(afterDot)) {
286
- hasDecimalSeparator = true;
287
- decimalIndex = dotIndex;
288
- }
289
- }
290
- if (!hasDecimalSeparator && cleaned.length >= 4) {
291
- const match = cleaned.match(/^(\d+)\.(\d{3})(\d{1,2})$/);
292
- if (match) {
293
- const [, beforeDot, thousandsPart, decimalPart] = match;
294
- const integerPart = (beforeDot ?? "") + (thousandsPart ?? "");
295
- const result = `${integerPart}.${decimalPart}`;
296
- return result;
297
- }
298
- }
299
- } else {
300
- const lastDotIndex = cleaned.lastIndexOf(".");
301
- if (lastDotIndex !== -1) {
302
- const afterDot = cleaned.substring(lastDotIndex + 1);
303
- if (afterDot.length <= 2 && /^\d*$/.test(afterDot)) {
304
- hasDecimalSeparator = true;
305
- decimalIndex = lastDotIndex;
306
- }
307
- }
308
- if (!hasDecimalSeparator && commaIndex !== -1) {
309
- const afterComma = cleaned.substring(commaIndex + 1);
310
- const looksLikeThousands = commaIndex <= 3 && afterComma.length >= 3;
311
- if (!looksLikeThousands && afterComma.length <= 2 && /^\d*$/.test(afterComma)) {
312
- hasDecimalSeparator = true;
313
- decimalIndex = commaIndex;
314
- }
315
- }
316
- }
317
- if (hasDecimalSeparator && decimalIndex !== -1) {
318
- const beforeDecimal = cleaned.substring(0, decimalIndex).replace(/[.,]/g, "");
319
- const afterDecimal = cleaned.substring(decimalIndex + 1).replace(/[.,]/g, "");
320
- if (afterDecimal === "") {
321
- const result2 = `${beforeDecimal}.`;
322
- return result2;
323
- }
324
- const result = `${beforeDecimal}.${afterDecimal.substring(0, 2)}`;
325
- return result;
282
+ const decimalIndex = findCurrencyDecimalIndex(cleaned, decimal, group);
283
+ if (decimalIndex === -1) {
284
+ return cleaned.replace(/[.,]/g, "");
326
285
  }
327
- const digitsOnly = cleaned.replace(/[.,]/g, "");
328
- return digitsOnly;
286
+ const integerPart = cleaned.substring(0, decimalIndex).replace(/[.,]/g, "");
287
+ const fractionPart = cleaned.substring(decimalIndex + 1).replace(/[.,]/g, "").substring(0, fractionDigits);
288
+ return `${integerPart}.${fractionPart}`;
329
289
  },
330
290
  validate: (value) => {
331
291
  if (!REGEX_CACHE.currencyValidation.test(value)) return false;
@@ -583,7 +543,6 @@ function getPatternCaretPosition(opts) {
583
543
  export {
584
544
  CURRENCY_PERCENTAGE_SYMBOLS,
585
545
  DEFAULT_CURRENCY,
586
- DEFAULT_LOCALE,
587
546
  MASK_PATTERNS,
588
547
  NUMERIC_MASK_PATTERNS,
589
548
  REGEX_CACHE,