@prolibu-suite/cobalt-core 0.9.5 → 0.10.0

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 (611) hide show
  1. package/custom-elements.json +750 -80
  2. package/dist/cjs/co-accordion.cjs.entry.js +1 -1
  3. package/dist/cjs/co-action-bar.cjs.entry.js +1 -1
  4. package/dist/cjs/co-app-shell.cjs.entry.js +4 -4
  5. package/dist/cjs/co-audio-player.cjs.entry.js +1 -1
  6. package/dist/cjs/co-autocomplete.cjs.entry.js +2 -2
  7. package/dist/cjs/co-avatar-group.cjs.entry.js +1 -1
  8. package/dist/cjs/co-avatar_2.cjs.entry.js +49 -17
  9. package/dist/cjs/co-badge.cjs.entry.js +11 -3
  10. package/dist/cjs/co-bottom-sheet.cjs.entry.js +1 -1
  11. package/dist/cjs/co-breadcrumb-item.cjs.entry.js +1 -1
  12. package/dist/cjs/co-breadcrumb.cjs.entry.js +1 -1
  13. package/dist/cjs/co-button-group.cjs.entry.js +1 -1
  14. package/dist/cjs/co-button.cjs.entry.js +2 -2
  15. package/dist/cjs/co-calendar-month_2.cjs.entry.js +55 -20
  16. package/dist/cjs/co-calendar_3.cjs.entry.js +27 -15
  17. package/dist/cjs/co-card.cjs.entry.js +1 -1
  18. package/dist/cjs/co-carousel-item.cjs.entry.js +1 -1
  19. package/dist/cjs/co-carousel.cjs.entry.js +2 -2
  20. package/dist/cjs/co-checkbox-group.cjs.entry.js +2 -2
  21. package/dist/cjs/co-checkbox.cjs.entry.js +6 -6
  22. package/dist/cjs/co-chip_2.cjs.entry.js +8 -5
  23. package/dist/cjs/co-color-picker.cjs.entry.js +1048 -27
  24. package/dist/cjs/co-column-picker.cjs.entry.js +3 -3
  25. package/dist/cjs/co-combobox.cjs.entry.js +2 -2
  26. package/dist/cjs/co-command-search.cjs.entry.js +1 -1
  27. package/dist/cjs/co-data-table-pagination.cjs.entry.js +5 -5
  28. package/dist/cjs/co-data-table.cjs.entry.js +1 -1
  29. package/dist/cjs/co-date-picker.cjs.entry.js +3 -3
  30. package/dist/cjs/co-date-range-picker.cjs.entry.js +3 -3
  31. package/dist/cjs/co-date-range.cjs.entry.js +2 -2
  32. package/dist/cjs/co-date-time-picker.cjs.entry.js +101 -130
  33. package/dist/cjs/co-drive-card.cjs.entry.js +2 -2
  34. package/dist/cjs/co-drop-zone.cjs.entry.js +2 -2
  35. package/dist/cjs/co-emoji-picker.cjs.entry.js +4 -4
  36. package/dist/cjs/co-empty-state.cjs.entry.js +4 -4
  37. package/dist/cjs/co-event-calendar.cjs.entry.js +4 -4
  38. package/dist/cjs/co-event-popover.cjs.entry.js +3 -3
  39. package/dist/cjs/co-fab.cjs.entry.js +3 -3
  40. package/dist/cjs/co-file-field.cjs.entry.js +102 -106
  41. package/dist/cjs/co-file-type-tile.cjs.entry.js +3 -3
  42. package/dist/cjs/co-helper-text.cjs.entry.js +3 -3
  43. package/dist/cjs/co-icon-button.cjs.entry.js +6 -6
  44. package/dist/cjs/co-icon.cjs.entry.js +3 -3
  45. package/dist/cjs/co-input.cjs.entry.js +26 -4
  46. package/dist/cjs/co-json-field.cjs.entry.js +5 -5
  47. package/dist/cjs/co-lightbox.cjs.entry.js +204 -21
  48. package/dist/cjs/co-list-footer.cjs.entry.js +2 -2
  49. package/dist/cjs/co-list-item.cjs.entry.js +5 -5
  50. package/dist/cjs/co-loader.cjs.entry.js +1 -1
  51. package/dist/cjs/co-media-thumb.cjs.entry.js +3 -3
  52. package/dist/cjs/co-menu-divider.cjs.entry.js +2 -2
  53. package/dist/cjs/co-menu-item.cjs.entry.js +84 -3
  54. package/dist/cjs/co-menu.cjs.entry.js +2 -2
  55. package/dist/cjs/co-modal.cjs.entry.js +6 -4
  56. package/dist/cjs/co-navbar.cjs.entry.js +4 -4
  57. package/dist/cjs/co-number-field.cjs.entry.js +272 -9
  58. package/dist/cjs/co-overlay.cjs.entry.js +6 -4
  59. package/dist/cjs/co-page-header.cjs.entry.js +2 -2
  60. package/dist/cjs/co-phone-field.cjs.entry.js +3 -3
  61. package/dist/cjs/co-popover.cjs.entry.js +58 -21
  62. package/dist/cjs/co-progress-bar.cjs.entry.js +3 -3
  63. package/dist/cjs/co-progress-circle.cjs.entry.js +3 -3
  64. package/dist/cjs/co-provider-logo_2.cjs.entry.js +47 -3
  65. package/dist/cjs/co-radio-group.cjs.entry.js +1 -1
  66. package/dist/cjs/co-radio.cjs.entry.js +4 -4
  67. package/dist/cjs/co-rating.cjs.entry.js +4 -4
  68. package/dist/cjs/co-ref-field.cjs.entry.js +4 -4
  69. package/dist/cjs/co-rich-text-editor.cjs.entry.js +11 -8
  70. package/dist/cjs/co-rich-text-toolbar.cjs.entry.js +7 -3
  71. package/dist/cjs/co-rich-text-viewer.cjs.entry.js +4 -3
  72. package/dist/cjs/co-row.cjs.entry.js +3 -3
  73. package/dist/cjs/co-segmented-bar.cjs.entry.js +1 -1
  74. package/dist/cjs/co-select.cjs.entry.js +2 -2
  75. package/dist/cjs/co-separator.cjs.entry.js +2 -2
  76. package/dist/cjs/co-sidebar-nav.cjs.entry.js +2 -2
  77. package/dist/cjs/co-sidebar.cjs.entry.js +3 -3
  78. package/dist/cjs/co-slider.cjs.entry.js +3 -3
  79. package/dist/cjs/co-switch.cjs.entry.js +6 -6
  80. package/dist/cjs/co-tab-group.cjs.entry.js +3 -3
  81. package/dist/cjs/co-tab.cjs.entry.js +3 -3
  82. package/dist/cjs/co-tags-field.cjs.entry.js +8 -8
  83. package/dist/cjs/co-textarea.cjs.entry.js +6 -6
  84. package/dist/cjs/co-time-field.cjs.entry.js +325 -0
  85. package/dist/cjs/co-toast.cjs.entry.js +2 -2
  86. package/dist/cjs/co-toggle-button-group.cjs.entry.js +4 -4
  87. package/dist/cjs/co-toggle-button.cjs.entry.js +4 -4
  88. package/dist/cjs/co-transfer-list.cjs.entry.js +1 -1
  89. package/dist/cjs/co-video.cjs.entry.js +32 -7
  90. package/dist/cjs/cobalt.cjs.js +2 -2
  91. package/dist/cjs/color-CML2Cfdh.js +142 -0
  92. package/dist/cjs/{dateI18n-wblvKRq_.js → dateI18n-BK2qHqoC.js} +36 -0
  93. package/dist/cjs/{fieldChip-BLzo9MEV.js → fieldChip-B6YIGU1V.js} +1 -1
  94. package/dist/cjs/fileI18n-6sdbKvo6.js +88 -0
  95. package/dist/cjs/{index-DFZ5YhIT.js → index-BYwrR87Z.js} +28 -10
  96. package/dist/cjs/{index-DK-2Lzmf.js → index-MDAnKsze.js} +25 -21
  97. package/dist/cjs/loader.cjs.js +2 -2
  98. package/dist/cjs/{positioning-DCj_AJ2T.js → positioning-CyatXeT_.js} +32 -13
  99. package/dist/cjs/{requiredMark-C1xcrzSZ.js → requiredMark-D-t-IPN0.js} +1 -1
  100. package/dist/cjs/{toolbar-config-BQfWTW6P.js → toolbar-config-BSGas-Wl.js} +10 -0
  101. package/dist/cobalt/cobalt.css +1 -1
  102. package/dist/cobalt/cobalt.esm.js +1 -1
  103. package/dist/cobalt/{p-f83b48fd.entry.js → p-011dc80b.entry.js} +1 -1
  104. package/dist/cobalt/{p-316c62c0.entry.js → p-0678c797.entry.js} +1 -1
  105. package/dist/cobalt/{p-43bd298d.entry.js → p-08e42e00.entry.js} +1 -1
  106. package/dist/cobalt/{p-1c68bc41.entry.js → p-10b82207.entry.js} +1 -1
  107. package/dist/cobalt/{p-a8c64cc3.entry.js → p-15d59169.entry.js} +1 -1
  108. package/dist/cobalt/{p-07d570a6.entry.js → p-16954cea.entry.js} +1 -1
  109. package/dist/cobalt/{p-85a61e28.entry.js → p-17244412.entry.js} +1 -1
  110. package/dist/cobalt/p-1788aab5.entry.js +1 -0
  111. package/dist/cobalt/p-1a589c8e.entry.js +1 -0
  112. package/dist/cobalt/{p-da546d08.entry.js → p-1dc55e43.entry.js} +1 -1
  113. package/dist/cobalt/p-20a39218.entry.js +1 -0
  114. package/dist/cobalt/{p-4c7e3984.entry.js → p-23ab0cc5.entry.js} +1 -1
  115. package/dist/cobalt/{p-fabe5fb2.entry.js → p-2636b7eb.entry.js} +1 -1
  116. package/dist/cobalt/{p-88a0659f.entry.js → p-27a7e549.entry.js} +1 -1
  117. package/dist/cobalt/{p-18d34b01.entry.js → p-290066ef.entry.js} +1 -1
  118. package/dist/cobalt/{p-89e38c5e.entry.js → p-2f9cbbd5.entry.js} +1 -1
  119. package/dist/cobalt/{p-ef5e1167.entry.js → p-325b91b6.entry.js} +1 -1
  120. package/dist/cobalt/{p-60cb66f5.entry.js → p-37f5036b.entry.js} +1 -1
  121. package/dist/cobalt/p-3cc3ff93.entry.js +1 -0
  122. package/dist/cobalt/p-410bee4d.entry.js +1 -0
  123. package/dist/cobalt/{p-6795a258.entry.js → p-44c4e4a3.entry.js} +1 -1
  124. package/dist/cobalt/{p-4b083da4.entry.js → p-44ea675f.entry.js} +1 -1
  125. package/dist/cobalt/{p-2828ecf6.entry.js → p-4592ca00.entry.js} +1 -1
  126. package/dist/cobalt/p-4908f33f.entry.js +1 -0
  127. package/dist/cobalt/{p-342e1da4.entry.js → p-4d65e713.entry.js} +1 -1
  128. package/dist/cobalt/{p-dca4cd5f.entry.js → p-4d897896.entry.js} +1 -1
  129. package/dist/cobalt/{p-33ea4a90.entry.js → p-50bcc76f.entry.js} +1 -1
  130. package/dist/cobalt/{p-ac91259e.entry.js → p-5298c030.entry.js} +1 -1
  131. package/dist/cobalt/p-54c987d7.entry.js +1 -0
  132. package/dist/cobalt/p-56551580.entry.js +1 -0
  133. package/dist/cobalt/p-58137c9e.entry.js +1 -0
  134. package/dist/cobalt/{p-4f754c9a.entry.js → p-58d9b650.entry.js} +1 -1
  135. package/dist/cobalt/p-59963937.entry.js +1 -0
  136. package/dist/cobalt/{p-2d329ac8.entry.js → p-623cc195.entry.js} +1 -1
  137. package/dist/cobalt/p-63825d7f.entry.js +1 -0
  138. package/dist/cobalt/{p-8e667eb6.entry.js → p-66b11b38.entry.js} +1 -1
  139. package/dist/cobalt/{p-fb3a095b.entry.js → p-6bf6bc3e.entry.js} +1 -1
  140. package/dist/cobalt/p-6f700f0d.entry.js +1 -0
  141. package/dist/cobalt/p-73c6d735.entry.js +1 -0
  142. package/dist/cobalt/{p-a6357340.entry.js → p-76249983.entry.js} +1 -1
  143. package/dist/cobalt/{p-bfc2a849.entry.js → p-82266f11.entry.js} +1 -1
  144. package/dist/cobalt/{p-a9b29cc2.entry.js → p-826ee074.entry.js} +1 -1
  145. package/dist/cobalt/{p-23b3ff3f.entry.js → p-83a9a05a.entry.js} +1 -1
  146. package/dist/cobalt/{p-568cfe8d.entry.js → p-83ea631d.entry.js} +1 -1
  147. package/dist/cobalt/p-85501c6a.entry.js +1 -0
  148. package/dist/cobalt/{p-dfd25f1d.entry.js → p-88195a63.entry.js} +1 -1
  149. package/dist/cobalt/p-8fa5dc4a.entry.js +1 -0
  150. package/dist/cobalt/{p-c8dba82f.entry.js → p-91e73a92.entry.js} +1 -1
  151. package/dist/cobalt/{p-ac466658.entry.js → p-92b092db.entry.js} +1 -1
  152. package/dist/cobalt/{p-36197363.entry.js → p-996f4e38.entry.js} +1 -1
  153. package/dist/cobalt/p-BRbgGqLw.js +1 -0
  154. package/dist/cobalt/{p-BL0sCfMH.js → p-Bryf3-Js.js} +1 -1
  155. package/dist/cobalt/p-DFHRS9cJ.js +1 -0
  156. package/dist/cobalt/{p-CrtiywTB.js → p-DH5lfRNj.js} +1 -1
  157. package/dist/{components/p-WeuPA9Rw.js → cobalt/p-DOL2zACE.js} +1 -1
  158. package/dist/cobalt/p-D_zA1Pv4.js +1 -0
  159. package/dist/cobalt/{p-fef5db54.entry.js → p-a32b20eb.entry.js} +1 -1
  160. package/dist/cobalt/p-aa9400bf.entry.js +1 -0
  161. package/dist/cobalt/{p-8eb485c8.entry.js → p-aaca6dab.entry.js} +1 -1
  162. package/dist/cobalt/{p-e5495539.entry.js → p-aae86f96.entry.js} +1 -1
  163. package/dist/cobalt/{p-8f38e24d.entry.js → p-ad33c40e.entry.js} +1 -1
  164. package/dist/cobalt/p-b0c4fc71.entry.js +1 -0
  165. package/dist/cobalt/{p-da18b5f4.entry.js → p-b1e8d69e.entry.js} +1 -1
  166. package/dist/cobalt/p-b48917c9.entry.js +1 -0
  167. package/dist/cobalt/{p-7e53e9c8.entry.js → p-b565104d.entry.js} +1 -1
  168. package/dist/cobalt/{p-b0319a2d.entry.js → p-b90d41e4.entry.js} +1 -1
  169. package/dist/cobalt/{p-c5684c79.entry.js → p-bd683db3.entry.js} +1 -1
  170. package/dist/cobalt/{p-1ddbc48b.entry.js → p-c124e82b.entry.js} +1 -1
  171. package/dist/cobalt/{p-95efe661.entry.js → p-c2ebf0ec.entry.js} +1 -1
  172. package/dist/cobalt/{p-76420ac1.entry.js → p-c32c176a.entry.js} +1 -1
  173. package/dist/cobalt/{p-54ae807d.entry.js → p-c465d619.entry.js} +1 -1
  174. package/dist/cobalt/{p-ab45d9bd.entry.js → p-c91d4fc6.entry.js} +1 -1
  175. package/dist/cobalt/{p-ce35c898.entry.js → p-d29bb0fa.entry.js} +1 -1
  176. package/dist/cobalt/{p-7c5e846a.entry.js → p-db805569.entry.js} +1 -1
  177. package/dist/cobalt/p-e01f9b9a.entry.js +1 -0
  178. package/dist/cobalt/p-e3aae282.entry.js +1 -0
  179. package/dist/cobalt/{p-d15d3a97.entry.js → p-e4264532.entry.js} +1 -1
  180. package/dist/cobalt/{p-93c68029.entry.js → p-e48f4e45.entry.js} +1 -1
  181. package/dist/cobalt/{p-3f0eed59.entry.js → p-e49a564c.entry.js} +1 -1
  182. package/dist/cobalt/p-e8a2f993.entry.js +1 -0
  183. package/dist/cobalt/p-e8a4e6b0.entry.js +1 -0
  184. package/dist/cobalt/p-ea20f048.entry.js +1 -0
  185. package/dist/cobalt/{p-c1e7fb32.entry.js → p-eb063cc0.entry.js} +1 -1
  186. package/dist/cobalt/p-eb82358d.entry.js +1 -0
  187. package/dist/cobalt/{p-2114c036.entry.js → p-eb8691f2.entry.js} +1 -1
  188. package/dist/cobalt/{p-e8878cf9.entry.js → p-ee2023da.entry.js} +1 -1
  189. package/dist/cobalt/p-ee9a623d.entry.js +1 -0
  190. package/dist/cobalt/p-ef5ca521.entry.js +1 -0
  191. package/dist/cobalt/p-f4e1c3c3.entry.js +1 -0
  192. package/dist/cobalt/{p-e364b8a5.entry.js → p-f57dffca.entry.js} +1 -1
  193. package/dist/cobalt/p-f6691108.entry.js +1 -0
  194. package/dist/cobalt/p-f68dd124.entry.js +1 -0
  195. package/dist/cobalt/p-fMqVDypp.js +1 -0
  196. package/dist/cobalt/{p-0c463d9a.entry.js → p-fd150cc6.entry.js} +1 -1
  197. package/dist/cobalt/{p-0e91e5c4.entry.js → p-fe7e8813.entry.js} +1 -1
  198. package/dist/cobalt/p-gKnOhsd2.js +1 -0
  199. package/dist/cobalt/p-jYd9gu_c.js +1 -0
  200. package/dist/collection/collection-manifest.json +1 -0
  201. package/dist/collection/components/co-app-shell/co-app-shell.css +107 -41
  202. package/dist/collection/components/co-app-shell/co-app-shell.js +2 -2
  203. package/dist/collection/components/co-autocomplete/co-autocomplete.js +1 -1
  204. package/dist/collection/components/co-avatar-group/co-avatar-group.js +1 -1
  205. package/dist/collection/components/co-badge/co-badge.css +18 -0
  206. package/dist/collection/components/co-badge/co-badge.js +29 -1
  207. package/dist/collection/components/co-button/co-button.css +4 -4
  208. package/dist/collection/components/co-checkbox/co-checkbox.css +12 -3
  209. package/dist/collection/components/co-checkbox/co-checkbox.js +6 -6
  210. package/dist/collection/components/co-checkbox-group/co-checkbox-group.css +1 -3
  211. package/dist/collection/components/co-checkbox-group/co-checkbox-group.js +1 -1
  212. package/dist/collection/components/co-color-picker/co-color-picker.css +252 -5
  213. package/dist/collection/components/co-color-picker/co-color-picker.js +932 -15
  214. package/dist/collection/components/co-color-picker/presets.js +113 -15
  215. package/dist/collection/components/co-column-picker/co-column-picker.js +2 -2
  216. package/dist/collection/components/co-combobox/co-combobox.js +1 -1
  217. package/dist/collection/components/co-command-search/co-command-search.js +1 -1
  218. package/dist/collection/components/co-data-table/co-data-table.js +1 -1
  219. package/dist/collection/components/co-data-table-pagination/co-data-table-pagination.js +4 -4
  220. package/dist/collection/components/co-date-field/co-date-field.js +4 -4
  221. package/dist/collection/components/co-date-range/co-date-range.js +1 -1
  222. package/dist/collection/components/co-date-range-picker/co-date-range-picker.js +2 -2
  223. package/dist/collection/components/co-date-time-picker/co-date-time-picker.css +128 -32
  224. package/dist/collection/components/co-date-time-picker/co-date-time-picker.js +142 -138
  225. package/dist/collection/components/co-drawer/co-drawer.css +99 -36
  226. package/dist/collection/components/co-drawer/co-drawer.js +19 -7
  227. package/dist/collection/components/co-drive-card/co-drive-card.js +1 -1
  228. package/dist/collection/components/co-drop-zone/co-drop-zone.js +1 -1
  229. package/dist/collection/components/co-emoji-picker/co-emoji-picker.js +2 -2
  230. package/dist/collection/components/co-empty-state/co-empty-state.css +28 -0
  231. package/dist/collection/components/co-empty-state/co-empty-state.js +2 -2
  232. package/dist/collection/components/co-event-calendar/co-event-calendar.js +2 -2
  233. package/dist/collection/components/co-event-popover/co-event-popover.js +1 -1
  234. package/dist/collection/components/co-fab/co-fab.js +2 -2
  235. package/dist/collection/components/co-file-field/co-file-field.css +55 -2
  236. package/dist/collection/components/co-file-field/co-file-field.js +41 -13
  237. package/dist/collection/components/co-file-field/co-file-field.utils.js +51 -4
  238. package/dist/collection/components/co-file-type-tile/co-file-type-tile.js +2 -2
  239. package/dist/collection/components/co-helper-text/co-helper-text.js +2 -2
  240. package/dist/collection/components/co-icon/co-icon.js +2 -2
  241. package/dist/collection/components/co-icon-button/co-icon-button.css +40 -2
  242. package/dist/collection/components/co-icon-button/co-icon-button.js +43 -4
  243. package/dist/collection/components/co-input/co-input.css +33 -0
  244. package/dist/collection/components/co-input/co-input.js +25 -2
  245. package/dist/collection/components/co-json-field/co-json-field.js +3 -3
  246. package/dist/collection/components/co-lightbox/co-lightbox.css +23 -0
  247. package/dist/collection/components/co-lightbox/co-lightbox.js +209 -20
  248. package/dist/collection/components/co-list-footer/co-list-footer.js +1 -1
  249. package/dist/collection/components/co-list-item/co-list-item.js +4 -4
  250. package/dist/collection/components/co-media-thumb/co-media-thumb.js +2 -2
  251. package/dist/collection/components/co-menu/co-menu.js +1 -1
  252. package/dist/collection/components/co-menu-divider/co-menu-divider.js +1 -1
  253. package/dist/collection/components/co-menu-item/co-menu-item.js +67 -3
  254. package/dist/collection/components/co-modal/co-modal.css +106 -37
  255. package/dist/collection/components/co-modal/co-modal.js +4 -2
  256. package/dist/collection/components/co-navbar/co-navbar.css +4 -2
  257. package/dist/collection/components/co-navbar/co-navbar.js +2 -2
  258. package/dist/collection/components/co-number-field/co-number-field.css +22 -0
  259. package/dist/collection/components/co-number-field/co-number-field.js +216 -9
  260. package/dist/collection/components/co-option-list/co-option-list.css +25 -4
  261. package/dist/collection/components/co-option-list/co-option-list.js +26 -3
  262. package/dist/collection/components/co-overlay/co-overlay.js +5 -3
  263. package/dist/collection/components/co-page-header/co-page-header.js +1 -1
  264. package/dist/collection/components/co-phone-field/co-phone-field.js +1 -1
  265. package/dist/collection/components/co-popover/co-popover.css +18 -3
  266. package/dist/collection/components/co-popover/co-popover.js +83 -20
  267. package/dist/collection/components/co-progress-bar/co-progress-bar.js +2 -2
  268. package/dist/collection/components/co-progress-circle/co-progress-circle.js +2 -2
  269. package/dist/collection/components/co-radio/co-radio.js +3 -3
  270. package/dist/collection/components/co-radio-group/co-radio-group.js +1 -1
  271. package/dist/collection/components/co-rating/co-rating.js +3 -3
  272. package/dist/collection/components/co-ref-field/co-ref-field.js +3 -3
  273. package/dist/collection/components/co-rich-text-editor/co-rich-text-editor.css +14 -1
  274. package/dist/collection/components/co-rich-text-editor/co-rich-text-editor.js +9 -6
  275. package/dist/collection/components/co-rich-text-toolbar/co-rich-text-toolbar.js +7 -3
  276. package/dist/collection/components/co-rich-text-viewer/co-rich-text-viewer.js +3 -2
  277. package/dist/collection/components/co-row/co-row.js +2 -2
  278. package/dist/collection/components/co-segmented-bar/co-segmented-bar.js +1 -1
  279. package/dist/collection/components/co-select/co-select.js +1 -1
  280. package/dist/collection/components/co-separator/co-separator.js +1 -1
  281. package/dist/collection/components/co-sidebar/co-sidebar.js +2 -2
  282. package/dist/collection/components/co-sidebar-nav/co-sidebar-nav.css +2 -2
  283. package/dist/collection/components/co-sidebar-nav/co-sidebar-nav.js +1 -1
  284. package/dist/collection/components/co-skeleton/co-skeleton.css +18 -0
  285. package/dist/collection/components/co-skeleton/co-skeleton.js +83 -1
  286. package/dist/collection/components/co-slider/co-slider.js +2 -2
  287. package/dist/collection/components/co-switch/co-switch.css +3 -3
  288. package/dist/collection/components/co-switch/co-switch.js +3 -3
  289. package/dist/collection/components/co-tab/co-tab.js +2 -2
  290. package/dist/collection/components/co-tab-group/co-tab-group.js +2 -2
  291. package/dist/collection/components/co-tags-field/co-tags-field.js +5 -5
  292. package/dist/collection/components/co-textarea/co-textarea.js +4 -4
  293. package/dist/collection/components/co-time-field/co-time-field.css +111 -0
  294. package/dist/collection/components/co-time-field/co-time-field.js +536 -0
  295. package/dist/collection/components/co-toast/co-toast.css +13 -7
  296. package/dist/collection/components/co-toast/co-toast.js +2 -2
  297. package/dist/collection/components/co-toggle-button/co-toggle-button.css +16 -11
  298. package/dist/collection/components/co-toggle-button/co-toggle-button.js +2 -2
  299. package/dist/collection/components/co-toggle-button-group/co-toggle-button-group.css +7 -1
  300. package/dist/collection/components/co-toggle-button-group/co-toggle-button-group.js +2 -2
  301. package/dist/collection/components/co-tooltip/co-tooltip.css +18 -1
  302. package/dist/collection/components/co-tooltip/co-tooltip.js +49 -16
  303. package/dist/collection/components/co-transfer-list/co-transfer-list.js +1 -1
  304. package/dist/collection/components/co-video/co-video.js +34 -9
  305. package/dist/collection/utils/amountText.js +95 -0
  306. package/dist/collection/utils/color.js +109 -3
  307. package/dist/collection/utils/colorPickerI18n.js +55 -0
  308. package/dist/collection/utils/dateI18n.js +36 -0
  309. package/dist/collection/utils/fileI18n.js +3 -0
  310. package/dist/collection/utils/positioning.js +37 -4
  311. package/dist/collection/utils/submenu.js +35 -0
  312. package/dist/components/co-accordion.js +1 -1
  313. package/dist/components/co-action-bar.js +1 -1
  314. package/dist/components/co-app-shell.js +1 -1
  315. package/dist/components/co-audio-player.js +1 -1
  316. package/dist/components/co-autocomplete.js +1 -1
  317. package/dist/components/co-avatar-group.js +1 -1
  318. package/dist/components/co-avatar.js +1 -1
  319. package/dist/components/co-badge.js +1 -1
  320. package/dist/components/co-breadcrumb-item.js +1 -1
  321. package/dist/components/co-breadcrumb.js +1 -1
  322. package/dist/components/co-button.js +1 -1
  323. package/dist/components/co-calendar-month.js +1 -1
  324. package/dist/components/co-calendar-timegrid.js +1 -1
  325. package/dist/components/co-calendar.js +1 -1
  326. package/dist/components/co-carousel.js +1 -1
  327. package/dist/components/co-checkbox-group.js +1 -1
  328. package/dist/components/co-checkbox.js +1 -1
  329. package/dist/components/co-chip.js +1 -1
  330. package/dist/components/co-color-picker.js +1 -1
  331. package/dist/components/co-column-picker.js +1 -1
  332. package/dist/components/co-combobox.js +1 -1
  333. package/dist/components/co-command-search.js +1 -1
  334. package/dist/components/co-data-table-pagination.js +1 -1
  335. package/dist/components/co-data-table.js +1 -1
  336. package/dist/components/co-date-field.js +1 -1
  337. package/dist/components/co-date-picker.js +1 -1
  338. package/dist/components/co-date-range-picker.js +1 -1
  339. package/dist/components/co-date-range.js +1 -1
  340. package/dist/components/co-date-time-picker.js +1 -1
  341. package/dist/components/co-drawer.js +1 -1
  342. package/dist/components/co-drive-card.js +1 -1
  343. package/dist/components/co-drop-zone.js +1 -1
  344. package/dist/components/co-emoji-picker.js +1 -1
  345. package/dist/components/co-empty-state.js +1 -1
  346. package/dist/components/co-event-calendar.js +1 -1
  347. package/dist/components/co-event-popover.js +1 -1
  348. package/dist/components/co-fab.js +1 -1
  349. package/dist/components/co-file-field.js +1 -1
  350. package/dist/components/co-file-type-tile.js +1 -1
  351. package/dist/components/co-helper-text.js +1 -1
  352. package/dist/components/co-icon-button.js +1 -1
  353. package/dist/components/co-icon.js +1 -1
  354. package/dist/components/co-input.js +1 -1
  355. package/dist/components/co-json-field.js +1 -1
  356. package/dist/components/co-lightbox.js +1 -1
  357. package/dist/components/co-list-footer.js +1 -1
  358. package/dist/components/co-list-item.js +1 -1
  359. package/dist/components/co-media-thumb.js +1 -1
  360. package/dist/components/co-menu-divider.js +1 -1
  361. package/dist/components/co-menu-item.js +1 -1
  362. package/dist/components/co-menu.js +1 -1
  363. package/dist/components/co-modal.js +1 -1
  364. package/dist/components/co-navbar.js +1 -1
  365. package/dist/components/co-number-field.js +1 -1
  366. package/dist/components/co-option-list.js +1 -1
  367. package/dist/components/co-overlay.js +1 -1
  368. package/dist/components/co-page-header.js +1 -1
  369. package/dist/components/co-phone-field.js +1 -1
  370. package/dist/components/co-popover.js +1 -1
  371. package/dist/components/co-progress-bar.js +1 -1
  372. package/dist/components/co-progress-circle.js +1 -1
  373. package/dist/components/co-radio-group.js +1 -1
  374. package/dist/components/co-radio.js +1 -1
  375. package/dist/components/co-rating.js +1 -1
  376. package/dist/components/co-ref-field.js +1 -1
  377. package/dist/components/co-rich-text-editor.js +1 -1
  378. package/dist/components/co-rich-text-toolbar.js +1 -1
  379. package/dist/components/co-rich-text-viewer.js +1 -1
  380. package/dist/components/co-row.js +1 -1
  381. package/dist/components/co-select.js +1 -1
  382. package/dist/components/co-separator.js +1 -1
  383. package/dist/components/co-sidebar-nav.js +1 -1
  384. package/dist/components/co-sidebar.js +1 -1
  385. package/dist/components/co-skeleton.js +1 -1
  386. package/dist/components/co-slider.js +1 -1
  387. package/dist/components/co-switch.js +1 -1
  388. package/dist/components/co-tab-group.js +1 -1
  389. package/dist/components/co-tab.js +1 -1
  390. package/dist/components/co-tags-field.js +1 -1
  391. package/dist/components/co-textarea.js +1 -1
  392. package/dist/components/co-time-field.d.ts +11 -0
  393. package/dist/components/co-time-field.js +1 -0
  394. package/dist/components/co-toast.js +1 -1
  395. package/dist/components/co-toggle-button-group.js +1 -1
  396. package/dist/components/co-toggle-button.js +1 -1
  397. package/dist/components/co-tooltip.js +1 -1
  398. package/dist/components/co-transfer-list.js +1 -1
  399. package/dist/components/co-video.js +1 -1
  400. package/dist/components/index.js +1 -1
  401. package/dist/components/p-9ceBPSd1.js +1 -0
  402. package/dist/components/p-B1QFLcY9.js +1 -0
  403. package/dist/components/p-B2IsXte7.js +1 -0
  404. package/dist/components/p-B4NCaKrR.js +1 -0
  405. package/dist/components/p-BBP5__CY.js +1 -0
  406. package/dist/components/{p-Dabi98BI.js → p-BGDqldEg.js} +1 -1
  407. package/dist/components/p-BRbgGqLw.js +1 -0
  408. package/dist/components/p-Be_kyNRE.js +1 -0
  409. package/dist/components/{p-BL0sCfMH.js → p-Bryf3-Js.js} +1 -1
  410. package/dist/components/p-BsTO1uUA.js +1 -0
  411. package/dist/components/{p-CuZXTvDM.js → p-Bv6U5y3d.js} +1 -1
  412. package/dist/components/p-BxP8OBw6.js +1 -0
  413. package/dist/components/{p-P8wvwhM2.js → p-CFFDmGPS.js} +1 -1
  414. package/dist/components/{p-CA_JAK9s.js → p-CT2enQ6h.js} +1 -1
  415. package/dist/components/p-CXPRaTuo.js +1 -0
  416. package/dist/components/{p-D5EdMieb.js → p-Cl3AdEQJ.js} +1 -1
  417. package/dist/components/p-CnX3L8aF.js +1 -0
  418. package/dist/components/p-DFHRS9cJ.js +1 -0
  419. package/dist/components/p-DIo66nBr.js +1 -0
  420. package/dist/components/{p-Dj1EZ5qD.js → p-DNJAIVfI.js} +1 -1
  421. package/dist/{cobalt/p-WeuPA9Rw.js → components/p-DOL2zACE.js} +1 -1
  422. package/dist/components/p-DRP8D9ro.js +1 -0
  423. package/dist/components/p-DkDTmHCg.js +1 -0
  424. package/dist/components/{p-Bxk96Zgc.js → p-Du_CgT5E.js} +1 -1
  425. package/dist/components/{p-BHYtxTzM.js → p-HxVRXXXC.js} +1 -1
  426. package/dist/components/{p-B0Dc-I_C.js → p-NNxjElcX.js} +1 -1
  427. package/dist/components/p-gKnOhsd2.js +1 -0
  428. package/dist/components/p-jYd9gu_c.js +1 -0
  429. package/dist/components/{p-D4qzGifz.js → p-vby0ITbe.js} +1 -1
  430. package/dist/components/{p-D6OUW6oW.js → p-x4grh-eZ.js} +1 -1
  431. package/dist/esm/co-accordion.entry.js +1 -1
  432. package/dist/esm/co-action-bar.entry.js +1 -1
  433. package/dist/esm/co-app-shell.entry.js +4 -4
  434. package/dist/esm/co-audio-player.entry.js +1 -1
  435. package/dist/esm/co-autocomplete.entry.js +2 -2
  436. package/dist/esm/co-avatar-group.entry.js +1 -1
  437. package/dist/esm/co-avatar_2.entry.js +49 -17
  438. package/dist/esm/co-badge.entry.js +11 -3
  439. package/dist/esm/co-bottom-sheet.entry.js +1 -1
  440. package/dist/esm/co-breadcrumb-item.entry.js +1 -1
  441. package/dist/esm/co-breadcrumb.entry.js +1 -1
  442. package/dist/esm/co-button-group.entry.js +1 -1
  443. package/dist/esm/co-button.entry.js +2 -2
  444. package/dist/esm/co-calendar-month_2.entry.js +37 -2
  445. package/dist/esm/co-calendar_3.entry.js +27 -15
  446. package/dist/esm/co-card.entry.js +1 -1
  447. package/dist/esm/co-carousel-item.entry.js +1 -1
  448. package/dist/esm/co-carousel.entry.js +2 -2
  449. package/dist/esm/co-checkbox-group.entry.js +2 -2
  450. package/dist/esm/co-checkbox.entry.js +6 -6
  451. package/dist/esm/co-chip_2.entry.js +8 -5
  452. package/dist/esm/co-color-picker.entry.js +1048 -27
  453. package/dist/esm/co-column-picker.entry.js +3 -3
  454. package/dist/esm/co-combobox.entry.js +2 -2
  455. package/dist/esm/co-command-search.entry.js +1 -1
  456. package/dist/esm/co-data-table-pagination.entry.js +5 -5
  457. package/dist/esm/co-data-table.entry.js +1 -1
  458. package/dist/esm/co-date-picker.entry.js +3 -3
  459. package/dist/esm/co-date-range-picker.entry.js +3 -3
  460. package/dist/esm/co-date-range.entry.js +2 -2
  461. package/dist/esm/co-date-time-picker.entry.js +101 -130
  462. package/dist/esm/co-drive-card.entry.js +2 -2
  463. package/dist/esm/co-drop-zone.entry.js +2 -2
  464. package/dist/esm/co-emoji-picker.entry.js +4 -4
  465. package/dist/esm/co-empty-state.entry.js +4 -4
  466. package/dist/esm/co-event-calendar.entry.js +4 -4
  467. package/dist/esm/co-event-popover.entry.js +3 -3
  468. package/dist/esm/co-fab.entry.js +3 -3
  469. package/dist/esm/co-file-field.entry.js +95 -99
  470. package/dist/esm/co-file-type-tile.entry.js +3 -3
  471. package/dist/esm/co-helper-text.entry.js +3 -3
  472. package/dist/esm/co-icon-button.entry.js +6 -6
  473. package/dist/esm/co-icon.entry.js +3 -3
  474. package/dist/esm/co-input.entry.js +26 -4
  475. package/dist/esm/co-json-field.entry.js +5 -5
  476. package/dist/esm/co-lightbox.entry.js +204 -21
  477. package/dist/esm/co-list-footer.entry.js +2 -2
  478. package/dist/esm/co-list-item.entry.js +5 -5
  479. package/dist/esm/co-loader.entry.js +1 -1
  480. package/dist/esm/co-media-thumb.entry.js +3 -3
  481. package/dist/esm/co-menu-divider.entry.js +2 -2
  482. package/dist/esm/co-menu-item.entry.js +84 -3
  483. package/dist/esm/co-menu.entry.js +2 -2
  484. package/dist/esm/co-modal.entry.js +6 -4
  485. package/dist/esm/co-navbar.entry.js +4 -4
  486. package/dist/esm/co-number-field.entry.js +272 -9
  487. package/dist/esm/co-overlay.entry.js +6 -4
  488. package/dist/esm/co-page-header.entry.js +2 -2
  489. package/dist/esm/co-phone-field.entry.js +3 -3
  490. package/dist/esm/co-popover.entry.js +58 -21
  491. package/dist/esm/co-progress-bar.entry.js +3 -3
  492. package/dist/esm/co-progress-circle.entry.js +3 -3
  493. package/dist/esm/co-provider-logo_2.entry.js +47 -3
  494. package/dist/esm/co-radio-group.entry.js +1 -1
  495. package/dist/esm/co-radio.entry.js +4 -4
  496. package/dist/esm/co-rating.entry.js +4 -4
  497. package/dist/esm/co-ref-field.entry.js +4 -4
  498. package/dist/esm/co-rich-text-editor.entry.js +11 -8
  499. package/dist/esm/co-rich-text-toolbar.entry.js +7 -3
  500. package/dist/esm/co-rich-text-viewer.entry.js +4 -3
  501. package/dist/esm/co-row.entry.js +3 -3
  502. package/dist/esm/co-segmented-bar.entry.js +1 -1
  503. package/dist/esm/co-select.entry.js +2 -2
  504. package/dist/esm/co-separator.entry.js +2 -2
  505. package/dist/esm/co-sidebar-nav.entry.js +2 -2
  506. package/dist/esm/co-sidebar.entry.js +3 -3
  507. package/dist/esm/co-slider.entry.js +3 -3
  508. package/dist/esm/co-switch.entry.js +6 -6
  509. package/dist/esm/co-tab-group.entry.js +3 -3
  510. package/dist/esm/co-tab.entry.js +3 -3
  511. package/dist/esm/co-tags-field.entry.js +8 -8
  512. package/dist/esm/co-textarea.entry.js +6 -6
  513. package/dist/esm/co-time-field.entry.js +323 -0
  514. package/dist/esm/co-toast.entry.js +2 -2
  515. package/dist/esm/co-toggle-button-group.entry.js +4 -4
  516. package/dist/esm/co-toggle-button.entry.js +4 -4
  517. package/dist/esm/co-transfer-list.entry.js +1 -1
  518. package/dist/esm/co-video.entry.js +32 -7
  519. package/dist/esm/cobalt.js +3 -3
  520. package/dist/esm/color-BRbgGqLw.js +136 -0
  521. package/dist/esm/{dateI18n-CnNpoKwg.js → dateI18n-jYd9gu_c.js} +36 -0
  522. package/dist/esm/{fieldChip-DsAfq1e0.js → fieldChip-uyggU8VV.js} +1 -1
  523. package/dist/esm/fileI18n-gKnOhsd2.js +84 -0
  524. package/dist/esm/{index-RuXxdKzC.js → index-68iUQp5j.js} +28 -10
  525. package/dist/esm/{index-CrtiywTB.js → index-DH5lfRNj.js} +25 -21
  526. package/dist/esm/loader.js +3 -3
  527. package/dist/esm/{positioning-BMdapAL8.js → positioning-DFHRS9cJ.js} +32 -13
  528. package/dist/esm/{requiredMark-DCD-ZA51.js → requiredMark-BCJUuZvC.js} +1 -1
  529. package/dist/esm/{toolbar-config-WeuPA9Rw.js → toolbar-config-DOL2zACE.js} +10 -0
  530. package/dist/types/components/co-badge/co-badge.d.ts +7 -0
  531. package/dist/types/components/co-checkbox/co-checkbox.d.ts +1 -1
  532. package/dist/types/components/co-color-picker/co-color-picker.d.ts +358 -4
  533. package/dist/types/components/co-color-picker/presets.d.ts +107 -4
  534. package/dist/types/components/co-date-time-picker/co-date-time-picker.d.ts +43 -21
  535. package/dist/types/components/co-drawer/co-drawer.d.ts +4 -3
  536. package/dist/types/components/co-file-field/co-file-field.d.ts +14 -0
  537. package/dist/types/components/co-file-field/co-file-field.utils.d.ts +18 -1
  538. package/dist/types/components/co-icon-button/co-icon-button.d.ts +9 -0
  539. package/dist/types/components/co-input/co-input.d.ts +4 -0
  540. package/dist/types/components/co-lightbox/co-lightbox.d.ts +60 -4
  541. package/dist/types/components/co-menu-item/co-menu-item.d.ts +16 -0
  542. package/dist/types/components/co-number-field/co-number-field.d.ts +42 -1
  543. package/dist/types/components/co-option-list/co-option-list.d.ts +3 -0
  544. package/dist/types/components/co-overlay/co-overlay.d.ts +4 -2
  545. package/dist/types/components/co-popover/co-popover.d.ts +16 -0
  546. package/dist/types/components/co-rich-text-toolbar/co-rich-text-toolbar.d.ts +1 -1
  547. package/dist/types/components/co-skeleton/co-skeleton.d.ts +13 -0
  548. package/dist/types/components/co-time-field/co-time-field.d.ts +60 -0
  549. package/dist/types/components/co-tooltip/co-tooltip.d.ts +5 -0
  550. package/dist/types/components/co-video/co-video.d.ts +4 -0
  551. package/dist/types/components.d.ts +451 -87
  552. package/dist/types/utils/amountText.d.ts +34 -0
  553. package/dist/types/utils/color.d.ts +44 -1
  554. package/dist/types/utils/colorPickerI18n.d.ts +26 -0
  555. package/dist/types/utils/dateI18n.d.ts +12 -0
  556. package/dist/types/utils/fileI18n.d.ts +1 -0
  557. package/dist/types/utils/positioning.d.ts +10 -0
  558. package/dist/types/utils/submenu.d.ts +44 -0
  559. package/package.json +3 -3
  560. package/dist/cjs/color-YhUkm10t.js +0 -32
  561. package/dist/cjs/time-LBHtzLHe.js +0 -42
  562. package/dist/cobalt/p-07904986.entry.js +0 -1
  563. package/dist/cobalt/p-09799193.entry.js +0 -1
  564. package/dist/cobalt/p-17ae943c.entry.js +0 -1
  565. package/dist/cobalt/p-23a103a0.entry.js +0 -1
  566. package/dist/cobalt/p-2f88d151.entry.js +0 -1
  567. package/dist/cobalt/p-3495fda1.entry.js +0 -1
  568. package/dist/cobalt/p-409f28bb.entry.js +0 -1
  569. package/dist/cobalt/p-682b3313.entry.js +0 -1
  570. package/dist/cobalt/p-6bf814f9.entry.js +0 -1
  571. package/dist/cobalt/p-7c88163e.entry.js +0 -1
  572. package/dist/cobalt/p-7cf4b4ae.entry.js +0 -1
  573. package/dist/cobalt/p-7ea87b75.entry.js +0 -1
  574. package/dist/cobalt/p-8183f56f.entry.js +0 -1
  575. package/dist/cobalt/p-8345b25f.entry.js +0 -1
  576. package/dist/cobalt/p-8b4b3589.entry.js +0 -1
  577. package/dist/cobalt/p-983af614.entry.js +0 -1
  578. package/dist/cobalt/p-BG4WRR22.js +0 -1
  579. package/dist/cobalt/p-BMdapAL8.js +0 -1
  580. package/dist/cobalt/p-CF8OB_TM.js +0 -1
  581. package/dist/cobalt/p-CnNpoKwg.js +0 -1
  582. package/dist/cobalt/p-T4la7ly_.js +0 -1
  583. package/dist/cobalt/p-a2d31248.entry.js +0 -1
  584. package/dist/cobalt/p-a6b5cadd.entry.js +0 -1
  585. package/dist/cobalt/p-b8581787.entry.js +0 -1
  586. package/dist/cobalt/p-bcedbd73.entry.js +0 -1
  587. package/dist/cobalt/p-d40a465f.entry.js +0 -1
  588. package/dist/cobalt/p-dea43204.entry.js +0 -1
  589. package/dist/cobalt/p-dfcf667d.entry.js +0 -1
  590. package/dist/cobalt/p-e6882ddd.entry.js +0 -1
  591. package/dist/cobalt/p-e84eda2e.entry.js +0 -1
  592. package/dist/cobalt/p-f25967fb.entry.js +0 -1
  593. package/dist/cobalt/p-f5f1b463.entry.js +0 -1
  594. package/dist/cobalt/p-fd39f410.entry.js +0 -1
  595. package/dist/cobalt/p-mAGnZXRn.js +0 -1
  596. package/dist/components/p-BMdapAL8.js +0 -1
  597. package/dist/components/p-BTQEg3UO.js +0 -1
  598. package/dist/components/p-BZIB4JDs.js +0 -1
  599. package/dist/components/p-Bbny3WUc.js +0 -1
  600. package/dist/components/p-C1Kv3zYZ.js +0 -1
  601. package/dist/components/p-CF8OB_TM.js +0 -1
  602. package/dist/components/p-CR0izsJC.js +0 -1
  603. package/dist/components/p-CnNpoKwg.js +0 -1
  604. package/dist/components/p-DP0bbhfN.js +0 -1
  605. package/dist/components/p-DbipMAyT.js +0 -1
  606. package/dist/components/p-DgUBcJIS.js +0 -1
  607. package/dist/components/p-DolCkNsL.js +0 -1
  608. package/dist/components/p-gI62K3Be.js +0 -1
  609. package/dist/components/p-hfGFsvaD.js +0 -1
  610. package/dist/esm/color-BG4WRR22.js +0 -30
  611. package/dist/esm/time-CF8OB_TM.js +0 -37
@@ -1,34 +1,228 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-DK-2Lzmf.js');
4
- var requiredMark = require('./requiredMark-C1xcrzSZ.js');
3
+ var index = require('./index-MDAnKsze.js');
4
+ var requiredMark = require('./requiredMark-D-t-IPN0.js');
5
+ var color = require('./color-CML2Cfdh.js');
6
+ var fileI18n = require('./fileI18n-6sdbKvo6.js');
5
7
 
6
8
  /**
7
- * Default color presets derived from Cobalt design tokens (base.json).
8
- * Uses primary colors + secondary-100 (full saturation, best contrast).
9
- * Names are English by default — consumers can override with translated presets.
9
+ * Textos de co-color-picker. Mismo patrón que fileI18n/dateI18n: el componente
10
+ * shipea es/en/pt keyado por la prop `locale`. Defaults en INGLÉS — un literal
11
+ * en español dentro de un co-* deja al host sin forma de traducirlo.
12
+ * Las plantillas usan `{n}` y se resuelven con `fillTemplate` de fileI18n
13
+ * (que ya existe exportado ahí: se reutiliza, no se duplica).
14
+ */
15
+ const DICT = {
16
+ en: {
17
+ swatches: 'Color presets',
18
+ groupNeutrals: 'Neutrals', groupBrand: 'Brand colors',
19
+ area: 'Saturation and brightness',
20
+ hue: 'Hue', hueValue: '{n} degrees',
21
+ saturation: 'Saturation', satValue: 'Saturation {n}%',
22
+ brightness: 'Brightness', briValue: 'Brightness {n}%',
23
+ area2D: '2D slider',
24
+ hexField: 'Hex code',
25
+ eyedropper: 'Pick a color from the screen',
26
+ copy: 'Copy',
27
+ },
28
+ es: {
29
+ swatches: 'Colores predefinidos',
30
+ groupNeutrals: 'Neutros', groupBrand: 'Colores de marca',
31
+ area: 'Saturación y brillo',
32
+ hue: 'Matiz', hueValue: '{n} grados',
33
+ saturation: 'Saturación', satValue: 'Saturación {n} %',
34
+ brightness: 'Brillo', briValue: 'Brillo {n} %',
35
+ area2D: 'Control 2D',
36
+ hexField: 'Código hexadecimal',
37
+ eyedropper: 'Elegir un color de la pantalla',
38
+ copy: 'Copiar',
39
+ },
40
+ pt: {
41
+ swatches: 'Cores predefinidas',
42
+ groupNeutrals: 'Neutros', groupBrand: 'Cores da marca',
43
+ area: 'Saturação e brilho',
44
+ hue: 'Matiz', hueValue: '{n} graus',
45
+ saturation: 'Saturação', satValue: 'Saturação {n} %',
46
+ brightness: 'Brilho', briValue: 'Brilho {n} %',
47
+ area2D: 'Controle 2D',
48
+ hexField: 'Código hexadecimal',
49
+ eyedropper: 'Escolher uma cor da tela',
50
+ copy: 'Copiar',
51
+ },
52
+ };
53
+ /**
54
+ * Resuelve los textos para un locale BCP-47. La resolución del idioma se
55
+ * reutiliza de `fileI18n` (mismo fallback a 'en'): tener dos implementaciones
56
+ * del mismo mapeo es exactamente la duplicación que el Step 0 vino a evitar
57
+ * cuando exigió reutilizar `fillTemplate` de ese archivo.
58
+ */
59
+ function getColorPickerStrings(locale) {
60
+ return DICT[fileI18n.langFromLocale(locale)];
61
+ }
62
+
63
+ /**
64
+ * Normaliza lo que llega por la prop `presets` a la forma interna, dejando
65
+ * anotado si la `key` vino declarada o se sintetizó.
66
+ *
67
+ * `ColorPreset.key` es OPCIONAL porque el tipo es superficie pública (lo
68
+ * re-exporta `components.d.ts`): exigirla rompería a todo host que hoy pasa
69
+ * `[{ name, value }]`. Puertas adentro la damos por garantizada, así que se
70
+ * rellena acá. Un hex suelto no tiene identidad traducible: su propio hex
71
+ * ES su identidad.
72
+ *
73
+ * Vive acá y no en el componente porque es el ÚNICO lugar que sintetiza keys, y
74
+ * `splitPaletteGroups` —su consumidor— depende de esa marca: separarlos deja el
75
+ * invariante a un import de distancia de romperse en silencio.
76
+ */
77
+ const resolvePreset = (p) => {
78
+ var _a;
79
+ if (typeof p === 'string')
80
+ return { key: p, name: p, value: p, synthesizedKey: true };
81
+ // La key declarada se conserva tal cual; si no vino, la cadena de siempre.
82
+ if (p.key != null)
83
+ return { key: p.key, name: p.name, value: p.value };
84
+ return { key: (_a = p.name) !== null && _a !== void 0 ? _a : p.value, name: p.name, value: p.value, synthesizedKey: true };
85
+ };
86
+ /**
87
+ * Paleta por default: 5 neutros + los 12 de marca (base.json).
88
+ * Los nombres vienen en inglés; el consumidor los traduce POR `key` — nunca
89
+ * duplicando la lista de valores, que fue lo que hizo derivar a FieldColor.vue.
90
+ *
91
+ * Sin blanco puro a propósito (spec §2): una etiqueta blanca desaparece sobre
92
+ * el fondo blanco. Los encabezados de documento lo pasan por la prop `presets`.
93
+ *
94
+ * Los hex son literales porque son DATA del picker, no estilo.
10
95
  */
11
96
  const DEFAULT_PRESETS = [
12
- { name: 'Green', value: '#02A270' },
13
- { name: 'Yellow', value: '#FDBF00' },
14
- { name: 'Blue', value: '#2563EB' },
15
- { name: 'Pink', value: '#F32A73' },
16
- { name: 'Red', value: '#EB1E1E' },
17
- { name: 'Orange', value: '#F0821E' },
18
- { name: 'Teal', value: '#00AFAF' },
19
- { name: 'Light blue', value: '#00BEE6' },
20
- { name: 'Electric blue', value: '#000AFF' },
21
- { name: 'Violet', value: '#5F4BD7' },
22
- { name: 'Burgundy', value: '#811137' },
23
- { name: 'Olive', value: '#AAB43C' },
97
+ { key: 'black', name: 'Black', value: '#1F1C1B' },
98
+ { key: 'gray', name: 'Gray', value: '#585858' },
99
+ { key: 'silver', name: 'Silver', value: '#C4C4C4' },
100
+ { key: 'smoke', name: 'Smoke', value: '#E3E3E3' },
101
+ { key: 'bone', name: 'Bone', value: '#F7F6F0' },
102
+ { key: 'green', name: 'Green', value: '#02A270' },
103
+ { key: 'olive', name: 'Olive', value: '#AAB43C' },
104
+ { key: 'yellow', name: 'Yellow', value: '#FDBF00' },
105
+ { key: 'orange', name: 'Orange', value: '#F0821E' },
106
+ { key: 'red', name: 'Red', value: '#EB1E1E' },
107
+ { key: 'pink', name: 'Pink', value: '#F32A73' },
108
+ { key: 'burgundy', name: 'Burgundy', value: '#811137' },
109
+ { key: 'violet', name: 'Violet', value: '#5F4BD7' },
110
+ { key: 'electricBlue', name: 'Electric blue', value: '#000AFF' },
111
+ { key: 'blue', name: 'Blue', value: '#2563EB' },
112
+ { key: 'lightBlue', name: 'Light blue', value: '#00BEE6' },
113
+ { key: 'teal', name: 'Teal', value: '#00AFAF' },
24
114
  ];
115
+ /**
116
+ * Los 5 primeros son neutros. Frontera ÚNICA: la grilla agrupa por acá y el
117
+ * seed sortea del resto. No repetir el `5` a mano en ningún otro lado.
118
+ */
119
+ const NEUTRAL_PRESET_KEYS = ['black', 'gray', 'silver', 'smoke', 'bone'];
120
+ /**
121
+ * Sólo las de marca, derivadas de la frontera. El seed aleatorio al CREAR un
122
+ * registro sortea de acá: nacer con una etiqueta gris es peor que el estado
123
+ * anterior.
124
+ */
125
+ const BRAND_PRESET_KEYS = DEFAULT_PRESETS
126
+ .filter((p) => !NEUTRAL_PRESET_KEYS.includes(p.key))
127
+ .map((p) => p.key);
128
+ // Índices de membresía, armados UNA vez a nivel de módulo: `splitPaletteGroups`
129
+ // corre en un getter que el render lee en cada pasada.
130
+ const NEUTRAL_KEYS = new Set(NEUTRAL_PRESET_KEYS);
131
+ const BRAND_KEYS = new Set(BRAND_PRESET_KEYS);
132
+ /**
133
+ * Parte una lista de presets en [neutros, marca], o devuelve `null` si no hay
134
+ * una partición que signifique algo.
135
+ *
136
+ * Se decide por MEMBRESÍA de `key`, nunca por identidad de referencia contra
137
+ * `DEFAULT_PRESETS`. La identidad es frágil por definición —dos arrays con el
138
+ * mismo contenido se comportan distinto— y ya costó un bug real: `FieldColor.vue`
139
+ * re-serializa la paleta para colgarle los nombres traducidos, así que llegaba
140
+ * como un array nuevo, caía en la rama "custom" y los `role="group"` +
141
+ * `aria-label` del spec §4 no se renderizaban NUNCA en la aplicación. La a11y
142
+ * existía sólo en los tests, que sí pasaban la paleta por identidad.
143
+ *
144
+ * Devuelve `null` en tres casos, y los tres terminan en un grupo único SIN
145
+ * rótulo:
146
+ * - alguna `key` la sintetizamos nosotros (`synthesizedKey`): el host no declaró
147
+ * nuestra paleta, y como doce de las keys son nombres de color CSS, mirar sólo
148
+ * el texto haría pasar por paleta nuestra a unos strings sueltos;
149
+ * - alguna `key` declarada es desconocida (paleta custom del host): no hay nada
150
+ * semántico que declarar;
151
+ * - falta alguno de los dos lados: un grupo solo no particiona nada, así que
152
+ * rotularlo anunciaría al lector de pantalla una frontera que no existe.
153
+ *
154
+ * ORDEN (decisión explícita): cuando la paleta se reconoce, se re-emite en orden
155
+ * canónico —neutros primero, marca después—, conservando el orden relativo del
156
+ * host DENTRO de cada lado. No es evitable: dos grupos contiguos no se pueden
157
+ * renderizar respetando un orden intercalado. Entre perder la agrupación
158
+ * semántica (spec §4) y perder un orden que el host no pudo curar sin adoptar
159
+ * antes nuestro vocabulario de keys, gana la agrupación. `flatPresets` y
160
+ * `focusedIndex` derivan de `presetGroups`, así que las flechas recorren el
161
+ * orden RENDERIZADO y no se desincronizan.
162
+ */
163
+ function splitPaletteGroups(presets) {
164
+ const neutrals = [];
165
+ const brand = [];
166
+ for (const p of presets) {
167
+ if (p.synthesizedKey)
168
+ return null;
169
+ if (NEUTRAL_KEYS.has(p.key))
170
+ neutrals.push(p);
171
+ else if (BRAND_KEYS.has(p.key))
172
+ brand.push(p);
173
+ else
174
+ return null;
175
+ }
176
+ if (!neutrals.length || !brand.length)
177
+ return null;
178
+ return { neutrals, brand };
179
+ }
25
180
 
26
- const coColorPickerCss = () => `:host{display:block;font-family:var(--co-font-family-primary);font-size:var(--co-font-size-14);letter-spacing:var(--co-font-letter-spacing-body);line-height:1}.co-color-picker{display:flex;flex-direction:column;gap:var(--co-spacing-sm2)}.co-color-picker--disabled{opacity:0.5;pointer-events:none}.co-color-picker__label{font-size:var(--co-font-size-14);font-weight:400;color:var(--co-semantic-text-secondary);padding:0 var(--co-spacing-xs)}.co-field-required{margin-left:2px;color:var(--co-color-status-error)}.co-field-required__caption{margin-left:4px;color:var(--co-semantic-text-muted);font-size:var(--co-font-size-12);font-weight:400}.co-field-required__caption::before{content:var(--co-field-required-text, ' (required)')}.co-color-picker co-popover{display:block;width:100%}.co-color-picker__trigger{display:flex;align-items:center;gap:var(--co-spacing-sm2);padding:var(--co-spacing-sm2) var(--co-spacing-md);background:var(--co-semantic-surface-page);border:1px solid var(--co-semantic-border-field);border-radius:var(--co-border-radius-xs);min-height:40px;box-sizing:border-box;cursor:pointer;transition:border-color var(--co-motion-duration-fast) var(--co-motion-ease-out), box-shadow var(--co-motion-duration-fast) var(--co-motion-ease-out)}.co-color-picker--s .co-color-picker__trigger{min-height:28px;padding:var(--co-spacing-xxs) var(--co-spacing-sm);font-size:var(--co-font-size-12)}.co-color-picker--sm .co-color-picker__trigger{min-height:32px;padding:var(--co-spacing-xs) var(--co-spacing-sm);font-size:var(--co-font-size-14)}.co-color-picker--lg .co-color-picker__trigger{min-height:48px;padding:var(--co-spacing-sm) var(--co-spacing-lg);font-size:var(--co-font-size-16)}.co-color-picker--s .co-color-picker__swatch,.co-color-picker--sm .co-color-picker__swatch{width:18px;height:18px}.co-color-picker__trigger:hover{border-color:var(--co-semantic-border-default)}.co-color-picker--open .co-color-picker__trigger{border-color:var(--co-semantic-border-focus);box-shadow:0 0 0 2px color-mix(in srgb, var(--co-semantic-border-focus) 15%, transparent)}.co-color-picker__trigger:focus-visible{outline:none;border-color:var(--co-semantic-border-focus);box-shadow:0 0 0 2px color-mix(in srgb, var(--co-semantic-border-focus) 15%, transparent)}.co-color-picker--error .co-color-picker__trigger{border-color:var(--co-color-status-error)}.co-color-picker__swatch{width:22px;height:22px;box-sizing:border-box;border-radius:var(--co-border-radius-full);border:1px solid var(--co-semantic-border-subtle);flex-shrink:0}.co-color-picker__value{flex:1;font-size:inherit;font-family:inherit;color:var(--co-semantic-text-default);font-weight:500;text-transform:uppercase}.co-color-picker__value--empty{color:var(--co-semantic-text-muted);font-weight:400}.co-color-picker__panel{padding:var(--co-spacing-md);display:flex;flex-direction:column;gap:var(--co-spacing-md)}.co-color-picker__grid{display:grid;grid-template-columns:repeat(8, 1fr);gap:var(--co-spacing-sm2)}.co-color-picker__grid-item{width:32px;height:32px;border-radius:var(--co-border-radius-xxs);border:2px solid transparent;cursor:pointer;transition:transform var(--co-motion-duration-fast) var(--co-motion-ease-out), border-color var(--co-motion-duration-fast) var(--co-motion-ease-out);box-sizing:border-box}.co-color-picker__grid-item:hover{transform:scale(1.1)}.co-color-picker__grid-item--selected{border-color:var(--co-semantic-border-focus);box-shadow:0 0 0 2px color-mix(in srgb, var(--co-semantic-border-focus) 25%, transparent)}.co-color-picker__hex-row{display:flex;align-items:center;gap:var(--co-spacing-sm2);padding:var(--co-spacing-xs) var(--co-spacing-sm);background:var(--co-semantic-surface-secondary);border:1px solid var(--co-semantic-border-subtle);border-radius:var(--co-border-radius-xxs)}.co-color-picker__hex-prefix{color:var(--co-semantic-text-muted);font-size:var(--co-font-size-14);font-weight:500}.co-color-picker__hex-value{flex:1;font-size:var(--co-font-size-14);font-family:var(--co-font-family-mono, monospace);color:var(--co-semantic-text-default);text-transform:uppercase;user-select:all}.co-color-picker__copy-btn{display:flex;align-items:center;justify-content:center;padding:var(--co-spacing-xs);border:none;background:transparent;cursor:pointer;color:var(--co-semantic-text-muted);border-radius:var(--co-border-radius-xxs);transition:color var(--co-motion-duration-fast) var(--co-motion-ease-out), background var(--co-motion-duration-fast) var(--co-motion-ease-out)}.co-color-picker__copy-btn:hover{color:var(--co-semantic-text-default);background:var(--co-semantic-surface-hover)}.co-color-picker__copy-btn--copied{color:var(--co-color-status-success)}.co-color-picker__helper{display:flex;align-items:center;gap:var(--co-spacing-xs);font-size:var(--co-font-size-14);color:var(--co-semantic-text-muted);padding:0 var(--co-spacing-xs)}.co-color-picker__helper-icon{flex-shrink:0;display:flex;align-items:center}.co-color-picker--error .co-color-picker__helper{color:var(--co-semantic-status-error)}:host([layout='horizontal']) .co-color-picker{display:grid;grid-template-columns:var(--co-field-label-width, max-content) 1fr;align-items:start;column-gap:var(--co-spacing-md);row-gap:var(--co-spacing-sm2)}:host([layout='horizontal']) .co-color-picker__label{grid-column:1;grid-row:1;padding-top:var(--co-spacing-sm2);min-width:0}:host([layout='horizontal']) .co-color-picker__label{white-space:normal}:host([layout='horizontal']) .co-color-picker>:not(.co-color-picker__label){grid-column:2;min-width:0}`;
181
+ const coColorPickerCss = () => `:host{display:block;font-family:var(--co-font-family-primary);font-size:var(--co-font-size-14);letter-spacing:var(--co-font-letter-spacing-body);line-height:1}.co-color-picker{display:flex;flex-direction:column;gap:var(--co-spacing-sm2)}.co-color-picker--disabled{opacity:0.5;pointer-events:none}.co-color-picker__label{font-size:var(--co-font-size-14);font-weight:400;color:var(--co-semantic-text-secondary);padding:0 var(--co-spacing-xs)}.co-field-required{margin-left:2px;color:var(--co-color-status-error)}.co-field-required__caption{margin-left:4px;color:var(--co-semantic-text-muted);font-size:var(--co-font-size-12);font-weight:400}.co-field-required__caption::before{content:var(--co-field-required-text, ' (required)')}.co-color-picker co-popover{display:block;width:100%}.co-color-picker__trigger{display:flex;align-items:center;gap:var(--co-spacing-sm2);padding:var(--co-spacing-sm2) var(--co-spacing-md);background:var(--co-semantic-surface-page);border:1px solid var(--co-semantic-border-field);border-radius:var(--co-border-radius-xs);min-height:40px;box-sizing:border-box;cursor:pointer;transition:border-color var(--co-motion-duration-fast) var(--co-motion-ease-out), box-shadow var(--co-motion-duration-fast) var(--co-motion-ease-out)}.co-color-picker--s .co-color-picker__trigger{min-height:28px;padding:var(--co-spacing-xxs) var(--co-spacing-sm);font-size:var(--co-font-size-12)}.co-color-picker--sm .co-color-picker__trigger{min-height:32px;padding:var(--co-spacing-xs) var(--co-spacing-sm);font-size:var(--co-font-size-14)}.co-color-picker--lg .co-color-picker__trigger{min-height:48px;padding:var(--co-spacing-sm) var(--co-spacing-lg);font-size:var(--co-font-size-16)}.co-color-picker--s .co-color-picker__swatch,.co-color-picker--sm .co-color-picker__swatch{width:18px;height:18px}.co-color-picker__trigger:hover{border-color:var(--co-semantic-border-default)}.co-color-picker--open .co-color-picker__trigger{border-color:var(--co-semantic-border-focus);box-shadow:0 0 0 2px color-mix(in srgb, var(--co-semantic-border-focus) 15%, transparent)}.co-color-picker__trigger:focus-visible{outline:none;border-color:var(--co-semantic-border-focus);box-shadow:0 0 0 2px color-mix(in srgb, var(--co-semantic-border-focus) 15%, transparent)}.co-color-picker--error .co-color-picker__trigger{border-color:var(--co-color-status-error)}.co-color-picker__swatch{width:22px;height:22px;box-sizing:border-box;border-radius:var(--co-border-radius-full);border:1px solid var(--co-semantic-border-subtle);flex-shrink:0}.co-color-picker__value{flex:1;font-size:inherit;font-family:inherit;color:var(--co-semantic-text-default);font-weight:500;text-transform:uppercase}.co-color-picker__value--empty{color:var(--co-semantic-text-muted);font-weight:400}.co-color-picker__panel{padding:var(--co-spacing-md);display:flex;flex-direction:column;gap:var(--co-spacing-md)}.co-color-picker__area{position:relative;height:132px;border-radius:var(--co-border-radius-xxs);cursor:crosshair;touch-action:none;background:linear-gradient(to top, black, transparent), linear-gradient(to right, white, transparent), hsl(var(--co-color-picker-hue, 0) 100% 50%)}.co-color-picker__area-thumb{position:absolute;width:14px;height:14px;margin:-7px 0 0 -7px;border-radius:var(--co-border-radius-full);border:2px solid var(--co-semantic-surface-page);box-shadow:0 0 0 1px var(--co-semantic-border-default);box-sizing:border-box;pointer-events:none}.co-color-picker__channel{position:absolute;inset:0;opacity:0;pointer-events:none;margin:0}.co-color-picker__area:focus-within{outline:2px solid var(--co-semantic-border-focus);outline-offset:2px}.co-color-picker__hue-input{width:100%;height:12px;margin:0;appearance:none;-webkit-appearance:none;border-radius:var(--co-border-radius-full);background:linear-gradient(to right, hsl(0 100% 50%), hsl(60 100% 50%), hsl(120 100% 50%), hsl(180 100% 50%), hsl(240 100% 50%), hsl(300 100% 50%), hsl(360 100% 50%));cursor:pointer}.co-color-picker__hue-input::-webkit-slider-thumb{appearance:none;-webkit-appearance:none;width:16px;height:16px;border-radius:var(--co-border-radius-full);background:var(--co-semantic-surface-page);box-shadow:0 0 0 1px var(--co-semantic-border-default);cursor:grab}.co-color-picker__hue-input::-moz-range-thumb{width:16px;height:16px;border:none;border-radius:var(--co-border-radius-full);background:var(--co-semantic-surface-page);box-shadow:0 0 0 1px var(--co-semantic-border-default)}.co-color-picker__hue-input:focus-visible{outline:2px solid var(--co-semantic-border-focus);outline-offset:2px}.co-color-picker__grid{display:flex;flex-direction:column;gap:var(--co-spacing-md)}.co-color-picker__grid-group{display:grid;grid-template-columns:repeat(6, 32px);gap:var(--co-spacing-sm2)}.co-color-picker__grid-item{width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:var(--co-border-radius-xxs);border:2px solid transparent;cursor:pointer;box-sizing:border-box;transition:transform var(--co-motion-duration-fast) var(--co-motion-ease-out), border-color var(--co-motion-duration-fast) var(--co-motion-ease-out)}.co-color-picker__grid-item:hover{transform:scale(1.1)}.co-color-picker__grid-item--selected{border-color:var(--co-semantic-border-focus);box-shadow:0 0 0 2px color-mix(in srgb, var(--co-semantic-border-focus) 25%, transparent)}.co-color-picker__grid-item--light{box-shadow:inset 0 0 0 1px var(--co-semantic-border-default)}.co-color-picker__grid-item--light.co-color-picker__grid-item--selected{box-shadow:inset 0 0 0 1px var(--co-semantic-border-default), 0 0 0 2px color-mix(in srgb, var(--co-semantic-border-focus) 25%, transparent)}.co-color-picker__grid-item:focus-visible{outline:none;box-shadow:0 0 0 2px var(--co-semantic-surface-page), 0 0 0 4px var(--co-semantic-border-focus)}.co-color-picker__grid-item--light:focus-visible{box-shadow:inset 0 0 0 1px var(--co-semantic-border-default), 0 0 0 2px var(--co-semantic-surface-page), 0 0 0 4px var(--co-semantic-border-focus)}.co-color-picker__grid-check{color:var(--co-semantic-surface-page)}.co-color-picker__grid-item--light .co-color-picker__grid-check{color:var(--co-semantic-text-default)}.co-color-picker__hex-row{display:flex;align-items:center;gap:var(--co-spacing-sm2);padding:var(--co-spacing-xs) var(--co-spacing-sm);background:var(--co-semantic-surface-secondary);border:1px solid var(--co-semantic-border-subtle);border-radius:var(--co-border-radius-xxs)}.co-color-picker__hex-prefix{color:var(--co-semantic-text-muted);font-size:var(--co-font-size-14);font-weight:500}.co-color-picker__hex-row:has(>.co-color-picker__hex-input:focus){border-color:var(--co-semantic-border-focus);box-shadow:0 0 0 2px var(--co-semantic-border-focus-ring)}.co-color-picker__hex-input{flex:1;min-width:0;box-sizing:border-box;border:none;background:transparent;padding:0;font-size:var(--co-font-size-14);font-family:var(--co-font-family-mono, monospace);color:var(--co-semantic-text-default);text-transform:uppercase}.co-color-picker__hex-input:focus,.co-color-picker__hex-input:focus-visible{outline:none}.co-color-picker__hex-input:disabled{color:var(--co-semantic-text-muted);cursor:not-allowed;opacity:1;-webkit-text-fill-color:var(--co-semantic-text-muted)}.co-color-picker__eyedropper{display:flex;align-items:center;justify-content:center;padding:var(--co-spacing-xs);border:none;background:transparent;cursor:pointer;color:var(--co-semantic-text-muted);border-radius:var(--co-border-radius-xxs);transition:color var(--co-motion-duration-fast) var(--co-motion-ease-out), background var(--co-motion-duration-fast) var(--co-motion-ease-out)}.co-color-picker__eyedropper:hover:not(:disabled){color:var(--co-semantic-text-default);background:var(--co-semantic-surface-hover)}.co-color-picker__eyedropper:focus-visible{outline:none;box-shadow:0 0 0 2px var(--co-semantic-border-focus-ring)}.co-color-picker__eyedropper:disabled{cursor:not-allowed;opacity:0.5}.co-color-picker__copy-btn{display:flex;align-items:center;justify-content:center;padding:var(--co-spacing-xs);border:none;background:transparent;cursor:pointer;color:var(--co-semantic-text-muted);border-radius:var(--co-border-radius-xxs);transition:color var(--co-motion-duration-fast) var(--co-motion-ease-out), background var(--co-motion-duration-fast) var(--co-motion-ease-out)}.co-color-picker__copy-btn:hover:not(:disabled){color:var(--co-semantic-text-default);background:var(--co-semantic-surface-hover)}.co-color-picker__copy-btn:focus-visible{outline:none;box-shadow:0 0 0 2px var(--co-semantic-border-focus-ring)}.co-color-picker__copy-btn:disabled{cursor:not-allowed;opacity:0.5}.co-color-picker__copy-btn--copied{color:var(--co-color-status-success)}.co-color-picker__helper{display:flex;align-items:center;gap:var(--co-spacing-xs);font-size:var(--co-font-size-14);color:var(--co-semantic-text-muted);padding:0 var(--co-spacing-xs)}.co-color-picker__helper-icon{flex-shrink:0;display:flex;align-items:center}.co-color-picker--error .co-color-picker__helper{color:var(--co-semantic-status-error)}:host([layout='horizontal']) .co-color-picker{display:grid;grid-template-columns:var(--co-field-label-width, max-content) 1fr;align-items:start;column-gap:var(--co-spacing-md);row-gap:var(--co-spacing-sm2)}:host([layout='horizontal']) .co-color-picker__label{grid-column:1;grid-row:1;padding-top:var(--co-spacing-sm2);min-width:0}:host([layout='horizontal']) .co-color-picker__label{white-space:normal}:host([layout='horizontal']) .co-color-picker>:not(.co-color-picker__label){grid-column:2;min-width:0}`;
27
182
 
183
+ /** Columnas de la grilla. 6×32 + 5×8 de gap + 24 de padding = 256px. */
184
+ const GRID_COLS = 6;
185
+ /** Paso grueso de Shift+flecha (SLDS). La flecha sola usa el paso nativo del range: 1. */
186
+ const SHIFT_STEP = 10;
187
+ /**
188
+ * Un pegado que YA es hex, o el principio de uno (`02`, `#0263`). Es lo único
189
+ * que se deja caer al escape cuando `parseCssColor` no reconoce el texto: así
190
+ * se puede pegar un fragmento y seguir tipeando, sin que un pegado que no es un
191
+ * color (un nombre CSS, una frase) se convierta en un hex inventado.
192
+ */
193
+ const HEX_FRAGMENT = /^#?[0-9a-f]*$/i;
194
+ /**
195
+ * De dónde parte el área cuando el campo está VACÍO: rojo puro, con el thumb en
196
+ * la esquina viva.
197
+ *
198
+ * No es cosmético. El vértice negro (`{0,0,0}`) deja DOS de los tres controles
199
+ * sin poder producir color: con `v=0`, mover el matiz o la saturación da
200
+ * `#000000` haga lo que haga el usuario. Y en suite-v2 `coChange` significa
201
+ * commit, así que un gesto exploratorio sobre un campo vacío lo dejaba en negro
202
+ * Y con "cambios sin guardar", sin que nadie haya elegido nada.
203
+ *
204
+ * El seed es de DISPLAY: no toca `value` ni emite. Hasta que el usuario actúa,
205
+ * el trigger sigue mostrando su placeholder.
206
+ *
207
+ * Congelado: es un objeto de MÓDULO, compartido por el initializer, el caché y
208
+ * el fallback de `componentWillLoad`. Hoy nadie lo muta —`previewHsv` hace
209
+ * spread y `commit` reasigna—, pero un `this.hsv.h = …` futuro envenenaría a
210
+ * todas las instancias de la página a la vez, y ése es un bug que no se
211
+ * encuentra mirando el componente que lo sufre.
212
+ *
213
+ * El tipo es `Readonly<Hsv>` y no `Hsv`: anotarlo como `Hsv` BORRA el
214
+ * `Readonly` que devuelve `Object.freeze`, y la protección queda sólo en
215
+ * runtime — TS no marcaría `EMPTY_HSV.h = 1` en compilación. Sigue siendo
216
+ * asignable a `this.hsv: Hsv`.
217
+ */
218
+ const EMPTY_HSV = Object.freeze({ h: 0, s: 100, v: 100 });
219
+ /** Los swatches de todos los grupos, en orden de render. */
220
+ const flattenGroups = (groups) => groups.reduce((acc, g) => acc.concat(g.items), []);
28
221
  const CoColorPicker = class {
29
222
  constructor(hostRef) {
30
223
  index.registerInstance(this, hostRef);
31
224
  this.coChange = index.createEvent(this, "coChange", 7);
225
+ this.coInput = index.createEvent(this, "coInput", 7);
32
226
  /** Current color value as hex string (e.g. "#0066FF"). */
33
227
  this.value = '';
34
228
  /** Placeholder text when no color is selected. */
@@ -48,13 +242,108 @@ const CoColorPicker = class {
48
242
  * or plain hex strings. When set programmatically, accepts an actual array.
49
243
  */
50
244
  this.presets = '';
245
+ /** Idioma de los textos accesibles. Misma prop que co-file-field/co-date-picker. */
246
+ this.locale = 'en';
51
247
  this.isOpen = false;
52
248
  this.copied = false;
249
+ /**
250
+ * El estado AUTORITATIVO del color mientras el picker está vivo: HSV en punto
251
+ * flotante. El hex es una derivación de presentación, no la fuente.
252
+ *
253
+ * ⛔ No redondear: el redondeo a entero rompe el round-trip (#02A270 vuelve
254
+ * como #02A370) y ése es el temblor del cursor al arrastrar. El redondeo va
255
+ * sólo en el borde (el `value` de los range y los aria-valuetext).
256
+ */
257
+ this.hsv = EMPTY_HSV;
258
+ /**
259
+ * El TEXTO del campo hex (sin `#`), que mientras se tipea puede no ser un
260
+ * color: `12` es un hex a medio escribir, no un error. El valor real sigue
261
+ * siendo `value`; esto es sólo lo que se ve en el campo.
262
+ */
263
+ this.hexDraft = '';
264
+ /**
265
+ * Si el usuario está tipeando en el campo hex. Mientras lo esté, el campo NO
266
+ * se re-espeja desde `value`: como el commit es en vivo, tipear `F00` emite
267
+ * `#FF0000` y espejarlo le reescribiría el texto bajo el cursor (react-colorful
268
+ * hace lo mismo, pero mirándole el foco al input; acá es un flag explícito
269
+ * porque el foco dentro de un shadow root no sale por `document.activeElement`
270
+ * y porque un flag es observable desde los tests).
271
+ *
272
+ * Se apaga en el blur y al reabrir el panel: un texto a medias abandonado por
273
+ * una vía que no entrega blur (Escape desmonta el panel entero) no puede
274
+ * dejar el espejo roto para siempre.
275
+ */
276
+ this.hexEditing = false;
277
+ /**
278
+ * Cuál de los dos ejes del área tiene el tab stop. El otro sale del tab order
279
+ * (`tabindex=-1`) y del árbol de accesibilidad (`aria-hidden`), así que el
280
+ * formulario lista UN control por campo y el lector anuncia uno solo — pero
281
+ * los dos siguen operables, porque la flecha del eje oculto le mueve el foco
282
+ * por código. Es @State porque de él dependen atributos pintados.
283
+ */
284
+ this.areaAxis = 's';
285
+ /**
286
+ * Último hex que escribimos en `value`. Es el anti-drift de la capa de estado:
287
+ * si el host nos devuelve el mismo hex que acabamos de emitir, NO se
288
+ * re-convierte a HSV — un redondeo distinto movería el cursor solo.
289
+ * (El otro anti-drift está en color.ts: Hsv es float, nunca entero.)
290
+ *
291
+ * Guardaba también el HSV que produjo ese hex, y nadie lo leía nunca: los
292
+ * cuatro puntos que sellan el caché lo hacen inmediatamente después de
293
+ * asignar `this.hsv`, así que la copia era `this.hsv` por otro nombre —
294
+ * imposible de desincronizar y, por lo mismo, imposible de aprovechar. Un
295
+ * campo muerto dentro de un anti-drift es una invitación a "usarlo" y
296
+ * reintroducir justo el drift que esto evita.
297
+ */
298
+ this.emitted = '';
299
+ /**
300
+ * El último hex realmente COMMITEADO (`coChange`), que es cosa distinta de
301
+ * `emitted`: ése lo sella también cada frame de preview, así que no puede
302
+ * decir a qué color volver cuando un gesto termina sin commitear.
303
+ *
304
+ * Es la línea de base del deshacer: a él vuelve un texto que quedó a medias
305
+ * y —el agujero que esto además tapa— un arrastre abortado, que hoy dejaba
306
+ * `value` en el color previsualizado sin que el host se hubiera enterado
307
+ * nunca por `coChange`.
308
+ */
309
+ this.committed = '';
310
+ /**
311
+ * Índice del swatch enfocado, para la navegación por flechas (roving tabindex).
312
+ * Es @State y no un campo suelto porque el `tabIndex` de cada opción se pinta
313
+ * a partir de él: sin reactividad, las flechas moverían el foco pero el DOM
314
+ * quedaría con el tabbable original y salir/volver con Tab caería en el
315
+ * swatch equivocado.
316
+ */
317
+ this.focusedIndex = 0;
318
+ /**
319
+ * Si hay un arrastre ABIERTO sobre el área (hubo `pointerdown` acá que sí
320
+ * pudo traducir el punto). Sin esto, cualquier `pointerup` que aterrice sobre
321
+ * el área commitea: un arrastre iniciado en otra parte del panel y soltado
322
+ * encima emitía un `coChange` que el usuario nunca pidió — y en suite-v2
323
+ * commit significa formulario sucio.
324
+ */
325
+ this.areaDragging = false;
53
326
  this.handlePopoverOpen = () => {
54
327
  this.isOpen = true;
328
+ // Toda reapertura arranca sin gesto abierto: si el anterior se abortó por
329
+ // una vía que no entrega ningún evento al área (Escape con el botón
330
+ // apretado desmonta el panel), este es el punto por el que sí se pasa.
331
+ this.areaDragging = false;
332
+ // Y sin edición de texto abierta: el panel se desmonta al cerrar, así que un
333
+ // texto a medias que se fue sin blur (Escape) no puede dejar el campo
334
+ // congelado en un draft ya divorciado del color.
335
+ this.resetHexDraft();
336
+ // Al abrir, el foco arranca en el color ya elegido (0 si no hay ninguno).
337
+ const i = this.flatPresets.findIndex((p) => p.value.toUpperCase() === (this.value || '').toUpperCase());
338
+ this.focusedIndex = i >= 0 ? i : 0;
55
339
  };
56
340
  this.handlePopoverClose = () => {
57
341
  this.isOpen = false;
342
+ // El cierre del panel TAMBIÉN cierra el gesto del campo, y no es un detalle:
343
+ // el navegador NO emite `blur` al remover un elemento enfocado, así que
344
+ // tipear un color y salir con Escape (o clickeando afuera) se perdería en
345
+ // silencio. Cubre además el arrastre abortado, que deja un preview colgado.
346
+ this.finishHexEdit();
58
347
  this.restoreTriggerFocus();
59
348
  };
60
349
  this.handleTriggerKeyDown = (e) => {
@@ -69,22 +358,492 @@ const CoColorPicker = class {
69
358
  this.isOpen = true;
70
359
  }
71
360
  };
361
+ /**
362
+ * Coordenadas del puntero → saturación/brillo.
363
+ *
364
+ * ⚠️ Un `rect` degenerado NO se convierte en un color: con `rect.width === 0`
365
+ * (área todavía sin layout, o con `display:none`) la división da **Infinity**
366
+ * —no NaN: NaN sólo sale si el numerador es exactamente 0— y el clamp lo
367
+ * lleva a 1, así que un pointerdown escribiría `s=100, v=0`, o sea NEGRO, y
368
+ * lo emitiría como si el usuario lo hubiera elegido. Guard: area.spec.
369
+ */
370
+ this.pointerToHsv = (e) => {
371
+ var _a;
372
+ const rect = (_a = this.areaEl) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
373
+ if (!rect || !(rect.width > 0) || !(rect.height > 0))
374
+ return false;
375
+ const x = Math.min(Math.max((e.clientX - rect.left) / rect.width, 0), 1);
376
+ const y = Math.min(Math.max((e.clientY - rect.top) / rect.height, 0), 1);
377
+ this.previewHsv({ s: x * 100, v: (1 - y) * 100 });
378
+ return true;
379
+ };
380
+ this.handleAreaPointerDown = (e) => {
381
+ var _a, _b;
382
+ // Sólo el botón PRIMARIO pinta: con el secundario, el click derecho abría
383
+ // el menú contextual y de paso cambiaba y commiteaba el color.
384
+ if (this.disabled || e.button !== 0)
385
+ return;
386
+ // Captura sobre el ÁREA (el thumb es pointer-events:none, así que el target
387
+ // ya es ella) para no perder el arrastre al salirse del panel. Llamada
388
+ // opcional: no todo entorno la implementa (jsdom no la tiene) y el arrastre
389
+ // dentro del área funciona igual sin captura.
390
+ (_b = (_a = this.areaEl) === null || _a === void 0 ? void 0 : _a.setPointerCapture) === null || _b === void 0 ? void 0 : _b.call(_a, e.pointerId);
391
+ // El gesto queda abierto SÓLO si el área pudo traducir el punto: con un
392
+ // rect degenerado no hay nada que arrastrar, y por lo tanto nada que
393
+ // commitear al soltar.
394
+ this.areaDragging = this.pointerToHsv(e);
395
+ };
396
+ this.handleAreaPointerMove = (e) => {
397
+ // Sólo dentro de un arrastre abierto en el área y con el botón principal
398
+ // apretado: sin lo primero, un arrastre que empezó en otro lado repinta al
399
+ // pasar por encima; sin lo segundo, lo hace el hover a secas.
400
+ if (this.disabled || !this.areaDragging || e.buttons !== 1)
401
+ return;
402
+ this.pointerToHsv(e);
403
+ };
404
+ /**
405
+ * Un arrastre ABORTADO cierra el gesto sin commitear. Sin esto, el flag queda
406
+ * en `true` para siempre en esa instancia y el próximo `pointerup` suelto
407
+ * commitea — el mismo bug del gesto sin `pointerdown`, por otra puerta.
408
+ */
409
+ this.handleAreaPointerCancel = () => {
410
+ this.areaDragging = false;
411
+ };
412
+ this.handleAreaPointerUp = (e) => {
413
+ // Sólo cierra un gesto ABIERTO en esta área. Un `pointerup` suelto no
414
+ // commitea nada.
415
+ if (!this.areaDragging || e.button !== 0)
416
+ return;
417
+ this.areaDragging = false;
418
+ if (this.disabled)
419
+ return;
420
+ this.commit(color.hsvToHex(this.hsv));
421
+ };
422
+ /**
423
+ * Teclado del área: la flecha decide el eje, y ese eje pasa a ser el
424
+ * enfocado. El foco programático entra igual en el input con `tabindex=-1`
425
+ * —por eso el par tabindex-1 + aria-hidden no deja ningún eje inalcanzable—.
426
+ * SLDS: flecha = 1, Shift+flecha = 10.
427
+ */
428
+ this.handleAreaKeyDown = (e) => {
429
+ if (this.disabled)
430
+ return;
431
+ const move = CoColorPicker.AREA_KEYS[e.key];
432
+ // Home/End/PageUp/PageDown quedan DELEGADOS al range nativo, sobre su propio
433
+ // eje. ⚠️ Es el único resquicio de redondeo que queda en el camino del
434
+ // estado: el nativo opera sobre el `value` del DOM, que ya viene redondeado
435
+ // por el borde de presentación, así que PageUp/PageDown pierden la fracción
436
+ // al re-entrar por `onInput`. Es preexistente y deliberado —el salto de esas
437
+ // teclas es de 10 o al extremo, donde la fracción no significa nada—, pero
438
+ // queda anotado para que nadie lo lea como un descuido.
439
+ if (!move)
440
+ return;
441
+ e.preventDefault();
442
+ const step = e.shiftKey ? SHIFT_STEP : 1;
443
+ const next = Math.min(100, Math.max(0, this.hsv[move.axis] + move.dir * step));
444
+ this.focusAxis(move.axis);
445
+ this.previewHsv({ [move.axis]: next });
446
+ // Un teclazo es un gesto completo: preview + commit, no un arrastre abierto.
447
+ // Son DOS eventos por tecla (coInput y coChange), no uno.
448
+ this.commit(color.hsvToHex(this.hsv));
449
+ };
450
+ /**
451
+ * El matiz es un slider 1D suelto: las cuatro flechas son SU eje, así que el
452
+ * range nativo ya resuelve el paso de 1 y acá sólo se intercepta Shift.
453
+ */
454
+ this.handleHueKeyDown = (e) => {
455
+ if (this.disabled || !e.shiftKey)
456
+ return;
457
+ const dir = e.key === 'ArrowRight' || e.key === 'ArrowUp' ? 1
458
+ : e.key === 'ArrowLeft' || e.key === 'ArrowDown' ? -1
459
+ : 0;
460
+ if (!dir)
461
+ return;
462
+ // El range nativo aplicaría ADEMÁS su paso de 1 sobre el mismo evento.
463
+ e.preventDefault();
464
+ const next = Math.min(360, Math.max(0, this.hsv.h + dir * SHIFT_STEP));
465
+ this.previewHsv({ h: next });
466
+ this.commit(color.hsvToHex(this.hsv));
467
+ };
468
+ this.handleGridKeyDown = (e) => {
469
+ var _a;
470
+ // `presetGroups` re-parsea el JSON de `presets` y remapea en CADA lectura, y
471
+ // todos los consumidores reales pasan presets custom por prop: se resuelve
472
+ // UNA vez por tecla y se pasa por parámetro, no dos veces por getter.
473
+ const groups = this.presetGroups;
474
+ const presets = flattenGroups(groups);
475
+ const n = presets.length;
476
+ if (!n)
477
+ return;
478
+ // Un `focusedIndex` fuera de rango (los presets cambiaron con el panel
479
+ // abierto) se clampea en vez de indexar `undefined`.
480
+ const current = Math.min(Math.max(this.focusedIndex, 0), n - 1);
481
+ let next = current;
482
+ switch (e.key) {
483
+ // Wrap cíclico: regla de SLDS. APG lo trata como opcional.
484
+ case 'ArrowRight':
485
+ next = (current + 1) % n;
486
+ break;
487
+ case 'ArrowLeft':
488
+ next = (current - 1 + n) % n;
489
+ break;
490
+ case 'ArrowDown':
491
+ next = this.verticalNeighbor(groups, current, 1);
492
+ break;
493
+ case 'ArrowUp':
494
+ next = this.verticalNeighbor(groups, current, -1);
495
+ break;
496
+ case 'Home':
497
+ next = 0;
498
+ break;
499
+ case 'End':
500
+ next = n - 1;
501
+ break;
502
+ case 'Enter':
503
+ case ' ':
504
+ e.preventDefault();
505
+ this.handleSwatchClick(presets[current].value);
506
+ return;
507
+ default: return;
508
+ }
509
+ e.preventDefault();
510
+ this.focusedIndex = next;
511
+ // Query, NO `children`: los swatches cuelgan de dos `role=group`, así que
512
+ // el índice plano no coincide con los hijos directos del listbox.
513
+ (_a = this.optionEls()[next]) === null || _a === void 0 ? void 0 : _a.focus();
514
+ };
515
+ /**
516
+ * Tipear PREVISUALIZA (`coInput`), no commitea.
517
+ *
518
+ * El campo es el único control del panel donde el gesto se estira en el
519
+ * tiempo, y tratarlo como commit por caracter tiene un costo que no se ve
520
+ * hasta que se mira de cerca: corregir un typo de `0263EB` a `026` emitiría
521
+ * `coChange('#002266')` — el usuario está BORRANDO y el componente commitea
522
+ * un color nuevo. Con el preview, el campo queda igual que sus tres hermanos
523
+ * (área, matiz, swatches): en vivo mientras dura el gesto, commit al
524
+ * soltarlo. El `#002266` que pinta al pasar por `026` es un frame intermedio
525
+ * de preview, ni más ni menos que cualquier frame de arrastre.
526
+ */
527
+ this.handleHexInput = (e) => {
528
+ var _a, _b;
529
+ if (this.disabled)
530
+ return;
531
+ const el = e.target;
532
+ const raw = this.escapeHex(el.value);
533
+ // El escape se fuerza en el DOM: si el texto escapado no cambió (tipear `zz`
534
+ // sobre `12` sigue dando `12`), el vdom no ve diferencia y no repinta — y el
535
+ // usuario se queda mirando `12zz` en el campo.
536
+ if (el.value !== raw) {
537
+ // Reasignar `value` manda el caret al final: con `1234` y el caret en 2,
538
+ // tipear `z` lo mandaba al 4 y el siguiente caracter salía en otro lugar.
539
+ // La posición se recalcula contando cuántos caracteres SOBREVIVEN al
540
+ // escape por delante del caret.
541
+ const caretIn = (_a = el.selectionStart) !== null && _a !== void 0 ? _a : el.value.length;
542
+ const caretOut = Math.min(this.escapeHex(el.value.slice(0, caretIn)).length, raw.length);
543
+ el.value = raw;
544
+ (_b = el.setSelectionRange) === null || _b === void 0 ? void 0 : _b.call(el, caretOut, caretOut);
545
+ }
546
+ this.hexEditing = true;
547
+ this.hexDraft = raw;
548
+ if (color.isValidHex(raw))
549
+ this.previewHex(this.expandHex(raw));
550
+ };
551
+ this.handleHexBlur = () => {
552
+ this.finishHexEdit();
553
+ };
554
+ /** Enter cierra el gesto sin salir del campo (y no submitea ningún form). */
555
+ this.handleHexKeyDown = (e) => {
556
+ if (e.key !== 'Enter')
557
+ return;
558
+ e.preventDefault();
559
+ this.finishHexEdit();
560
+ };
561
+ /**
562
+ * Sin interceptar el pegado, el escape convierte `rgb(2, 99, 235)` en
563
+ * `299235` — basura silenciosa que ADEMÁS commitea sola, porque el `input` que
564
+ * sigue al pegado nativo ve 6 dígitos válidos.
565
+ *
566
+ * `parseCssColor` no cubre nombres CSS (ver color.ts): `rebeccapurple` escapa
567
+ * a `EBECCA`, un hex perfectamente válido que nadie eligió. Por eso lo que no
568
+ * es un color se CANCELA en vez de dejarse caer al escape; lo único que pasa
569
+ * de largo es un hex o el principio de uno, para poder pegar `02` y seguir
570
+ * tipeando.
571
+ */
572
+ this.handleHexPaste = (e) => {
573
+ var _a, _b;
574
+ if (this.disabled)
575
+ return;
576
+ const text = ((_b = (_a = e.clipboardData) === null || _a === void 0 ? void 0 : _a.getData('text')) !== null && _b !== void 0 ? _b : '').trim();
577
+ const parsed = color.parseCssColor(text);
578
+ if (parsed) {
579
+ e.preventDefault();
580
+ // Un pegado entrega un color COMPLETO en un acto atómico, como clickear
581
+ // un swatch: commitea al instante en vez de esperar al fin de gesto, y
582
+ // por lo mismo CIERRA cualquier edición de texto que estuviera abierta
583
+ // (si no, el blur posterior volvería a commitear lo mismo).
584
+ this.hexEditing = false;
585
+ this.hexDraft = this.escapeHex(parsed);
586
+ this.commit(parsed);
587
+ return;
588
+ }
589
+ if (!HEX_FRAGMENT.test(text))
590
+ e.preventDefault();
591
+ };
592
+ /**
593
+ * El cuentagotas entrega un color COMPLETO en un acto atómico, igual que un
594
+ * swatch o un pegado: entra por `commit` —no se duplica ni la asignación ni
595
+ * el emit— y se normaliza con `parseCssColor`, porque la API devuelve el hex
596
+ * en minúscula (`#ff0000`) y el resto del picker trabaja en mayúscula.
597
+ *
598
+ * ⚠️ `finishHexEdit` va PRIMERO y SÍNCRONO, antes del `await`: clickear otro
599
+ * control del panel es el fin del gesto del campo hex, y ese gesto puede
600
+ * durar lo que el usuario tarde en recorrer la pantalla. Sin esto, un texto a
601
+ * medias (`12`) se queda escrito y `hexEditing` colgado durante todo el
602
+ * cuentagotas, y si el usuario CANCELA nadie lo deshace: el preview vivo
603
+ * sobrevive a un gesto que no commiteó nada. Es el mismo cierre que hace el
604
+ * pegado, por la misma razón. Correrlo dos veces es inocuo (el blur real del
605
+ * navegador lo dispara también): la segunda pasada ve `hexEditing` en false y
606
+ * `value === committed`, y sale sin emitir.
607
+ */
608
+ this.handleEyeDropper = async () => {
609
+ this.finishHexEdit();
610
+ // El guard va DESPUÉS del cierre del gesto, y eso es lo único que tiene de
611
+ // interesante. `hasEyeDropper` no es reactivo: la presencia del botón se
612
+ // decide en el render y nunca se re-evalúa, así que existe el camino "API
613
+ // presente al renderizar, ausente al clickear" — el botón sigue en el DOM.
614
+ // Con el guard ADELANTE, ese click no hacía nada Y dejaba la edición del
615
+ // hex abierta: un control visible que se comporta distinto a todos sus
616
+ // hermanos del panel. Acá abajo el camino raro cierra el gesto igual que
617
+ // los demás y sólo se saltea el cuentagotas.
618
+ //
619
+ // Puesto así el guard ya no cambia nada observable —sin él, `new Ctor()`
620
+ // tira un TypeError que el `catch` atrapa y el estado queda idéntico—, y
621
+ // por eso ningún test lo distingue. Se queda por ser explícito sobre una
622
+ // precondición, no por un caso que lo necesite.
623
+ if (!this.hasEyeDropper)
624
+ return;
625
+ try {
626
+ const Ctor = window.EyeDropper;
627
+ const { sRGBHex } = await new Ctor().open();
628
+ const hex = color.parseCssColor(sRGBHex);
629
+ // Lo que no es un color no se commitea: el picker no inventa negro.
630
+ if (hex)
631
+ this.commit(hex);
632
+ }
633
+ catch (_a) {
634
+ /* El usuario canceló con Escape: no es un error que valga reportar. */
635
+ }
636
+ };
637
+ }
638
+ /**
639
+ * Un valor entrante que YA es el que acabamos de emitir se descarta.
640
+ *
641
+ * Sin esto, un host controlado (el que guarda lo emitido y lo devuelve por la
642
+ * prop) reinyecta el hex derivado, que se re-convierte a HSV con otro
643
+ * redondeo y mueve el cursor solo en pleno arrastre. La comparación es
644
+ * case-insensitive porque el host normaliza el string —guardar en minúsculas
645
+ * es lo habitual— y el mismo color escrito distinto no es un cambio.
646
+ */
647
+ syncFromValue(next) {
648
+ // El campo hex espeja el valor por esta vía ÚNICA, ANTES del guard: todo
649
+ // camino que cambia el color pasa por acá (el arrastre y el commit escriben
650
+ // `value`, y el host también). Si el espejo viviera después del guard, el
651
+ // campo quedaría congelado en el color anterior justo en el caso más común
652
+ // —arrastrar el área—, porque ese camino sella el caché antes de asignar.
653
+ this.syncHexDraft(next);
654
+ if ((next || '').toUpperCase() === (this.emitted || '').toUpperCase())
655
+ return;
656
+ // Un valor que llega de afuera ES la verdad del host, PARSEE O NO: pasa a
657
+ // ser la línea de base a la que vuelve un gesto que termina sin commitear.
658
+ //
659
+ // ⛔ Va ANTES del guard de parseo, y eso es lo único que separa esto de un
660
+ // bug de pérdida de datos: si el host BORRA el color (`value = ''`) o pone
661
+ // algo que no es un hex (`var(--co-brand)`), con la línea abajo `committed`
662
+ // se quedaba en el color VIEJO — y como el cierre del panel deshace todo
663
+ // preview colgado, abrir y cerrar sin tocar nada le devolvía al host el
664
+ // color que acababa de borrar, por `value` y por `coInput`.
665
+ //
666
+ // Y va DESPUÉS del guard de `emitted`, que es igual de deliberado: un host
667
+ // controlado que espeja `coInput` de vuelta a la prop nos devuelve nuestro
668
+ // propio preview, y tomar eso por un commit del host haría irreversible
669
+ // justo lo que este mecanismo existe para revertir.
670
+ this.committed = next;
671
+ // `emitted` se sella acá arriba por la misma razón, y también está medido:
672
+ // gateado por el parseo, un host que PASA por un valor no-hex y vuelve a un
673
+ // color que ya habíamos tenido lo dejaba stale apuntando a ese color, el
674
+ // guard de arriba tomaba el regreso por eco propio, `committed` no se
675
+ // actualizaba y el cierre del panel reemplazaba el color del host por el
676
+ // valor intermedio. Sellar lo que el host escribió —parsee o no— es además
677
+ // lo que el guard significa: "esto ya lo tenemos, no hay nada que
678
+ // re-derivar", que de un valor no parseable es trivialmente cierto.
679
+ this.emitted = next;
680
+ const parsed = color.hexToHsv(next || '');
681
+ // Un hex inválido no se convierte en un color: se ignora y el estado
682
+ // anterior sobrevive (el picker no tiene por qué inventar negro).
683
+ if (!parsed)
684
+ return;
685
+ this.hsv = parsed;
686
+ }
687
+ /**
688
+ * Siembra del estado. Es OBLIGATORIA acá, no basta el initializer del campo:
689
+ * - los @Watch no corren para el valor inicial de la prop;
690
+ * - el initializer de un miembro DECORADO no sobrevive en el entorno de spec
691
+ * (@stencil/vitest define el accessor encima del campo ya inicializado, así
692
+ * que `this.hsv` llega `undefined` al primer render y el destructuring de
693
+ * `renderArea` tira). Los otros @State del componente lo toleraban porque
694
+ * `undefined` es falsy justo donde se usan.
695
+ * Sin hex válido el estado arranca en negro, que es lo que pinta el área
696
+ * mientras no hay color elegido.
697
+ */
698
+ componentWillLoad() {
699
+ const parsed = color.hexToHsv(this.value || '');
700
+ this.hsv = parsed !== null && parsed !== void 0 ? parsed : EMPTY_HSV;
701
+ // Mismo motivo que `hsv`: el tab stop del área arranca en la saturación.
702
+ this.areaAxis = 's';
703
+ // El campo hex arranca del VALOR, no del seed del área.
704
+ //
705
+ // Es una siembra DEFENSIVA, y conviene decirlo con precisión porque el
706
+ // comentario anterior mentía: quitarla no pinta `FF0000` en ningún frame
707
+ // —`hexDraft` se queda en su initializer `''`—, y midiendo el shadow DOM
708
+ // cada 5ms desde el keydown del trigger, el input ya nace con el valor
709
+ // correcto porque `coOpen` (y con él `resetHexDraft`) llega ANTES de que el
710
+ // panel sea alcanzable. O sea: la re-siembra del popover le gana la carrera
711
+ // en todo entorno medido, y por eso ningún test la distingue. Se queda
712
+ // igual —sembrar en el load es correcto por construcción y no cuesta nada—,
713
+ // pero como cobertura no vale nada.
714
+ this.resetHexDraft();
715
+ // ⛔ NINGUNO de los dos sellos va detrás de `if (parsed)`, y no es simetría:
716
+ // cada uno abre su propia puerta al mismo bug de pérdida de datos, porque en
717
+ // Stencil el @Watch NO corre para el valor inicial y este es el único lugar
718
+ // donde se pueden sembrar.
719
+ //
720
+ // · `committed` es la línea de base del deshacer. Gateado, un `value`
721
+ // inicial que no parsea (`var(--co-brand)`, un nombre CSS) lo dejaba en
722
+ // `''`, y como el cierre del panel deshace todo preview colgado, abrir y
723
+ // cerrar SIN TOCAR NADA le borraba el valor al host y se lo anunciaba por
724
+ // `coInput`. Es el mismo razonamiento que el del @Watch, con el síntoma
725
+ // invertido: allá resucitaba el color viejo, acá borra el nuevo, porque
726
+ // el initializer es `''` en vez de un hex.
727
+ //
728
+ // · `emitted` es el caché anti-drift, no la línea de base — pero gatearlo
729
+ // abre la MISMA pérdida por composición, y está medido: con `committed`
730
+ // ya arreglado y `emitted` en `''`, un host que BORRA el color escribe
731
+ // justo el `''` que el guard toma por "esto ya lo emitimos nosotros",
732
+ // corta antes de actualizar `committed`, y el cierre del panel le
733
+ // devuelve el token que acababa de borrar. Sembrarlo con el valor inicial
734
+ // además es lo correcto por definición: el guard existe para saltear la
735
+ // re-derivación de un valor que ya tenemos, y al montar `value` ES lo que
736
+ // tenemos (`componentWillLoad` acaba de derivarlo).
737
+ this.committed = this.value;
738
+ this.emitted = this.value;
739
+ }
740
+ /**
741
+ * Movimiento en vivo: actualiza la UI y avisa, sin commitear.
742
+ *
743
+ * ⚠️ El caché se sella ANTES de tocar `this.value`: el setter de una @Prop
744
+ * corre sus @Watch de forma SÍNCRONA, así que con el caché todavía en el
745
+ * color anterior `syncFromValue` vería un color "nuevo", re-parsearía el hex
746
+ * y pisaría este HSV flotante con el redondeado — el temblor, en el mismo
747
+ * frame y sin que el host haya hecho nada. Guard: area.spec.
748
+ */
749
+ previewHsv(next) {
750
+ this.hsv = Object.assign(Object.assign({}, this.hsv), next);
751
+ this.emitPreview(color.hsvToHex(this.hsv));
752
+ }
753
+ /**
754
+ * Lo mismo, pero entrando por un hex ENTERO en vez de por un eje: es lo que
755
+ * produce el campo de texto, donde el color no llega como "más saturación"
756
+ * sino como un color completo. Comparte el sellado con `previewHsv` para que
757
+ * el orden crítico (sellar → asignar → avisar) exista en UN solo lugar.
758
+ */
759
+ previewHex(hex) {
760
+ const parsed = color.hexToHsv(hex);
761
+ if (parsed)
762
+ this.hsv = parsed;
763
+ this.emitPreview(hex);
764
+ }
765
+ emitPreview(hex) {
766
+ this.emitted = hex;
767
+ this.value = hex;
768
+ this.coInput.emit(hex);
769
+ }
770
+ /**
771
+ * Commit: lo que los consumidores ya escuchan hoy (soltar el arrastre,
772
+ * clickear un swatch).
773
+ *
774
+ * El HSV se re-deriva SÓLO si el hex viene de afuera —un swatch, un hex
775
+ * tipeado—, y eso se detecta preguntándole al propio estado si ese hex es el
776
+ * que produce. Re-derivar siempre tiene dos daños:
777
+ *
778
+ * 1. 🔴 En un color ACROMÁTICO el hex no lleva matiz: `#000000` es negro y
779
+ * punto, así que `hexToHsv` devuelve h=0 (rojo) y le BORRA al usuario el
780
+ * matiz que acababa de elegir. Con el campo vacío —el estado inicial de
781
+ * tres consumidores de suite-v2— el área se ponía azul al arrastrar el
782
+ * matiz y volvía a roja al soltar.
783
+ * 2. En un color cromático no lo borra pero lo REDONDEA (200 → 199.875):
784
+ * el estado interno pasando por la grilla del hex es justo lo que esta
785
+ * task existe para evitar.
786
+ */
787
+ commit(hex) {
788
+ if (color.hsvToHex(this.hsv) !== hex) {
789
+ const parsed = color.hexToHsv(hex);
790
+ if (parsed)
791
+ this.hsv = parsed;
792
+ }
793
+ this.emitted = hex;
794
+ this.committed = hex;
795
+ this.value = hex;
796
+ this.coChange.emit(hex);
797
+ }
798
+ get strings() {
799
+ return getColorPickerStrings(this.locale);
72
800
  }
73
801
  get parsedPresets() {
74
802
  if (Array.isArray(this.presets)) {
75
- return this.presets.map(p => typeof p === 'string' ? { name: p, value: p } : p);
803
+ return this.presets.map(resolvePreset);
76
804
  }
77
805
  if (typeof this.presets === 'string' && this.presets.trim()) {
78
806
  try {
79
807
  const parsed = JSON.parse(this.presets);
80
808
  if (Array.isArray(parsed)) {
81
- return parsed.map((p) => typeof p === 'string' ? { name: p, value: p } : p);
809
+ return parsed.map((p) => resolvePreset(p));
82
810
  }
83
811
  }
84
812
  catch ( /* ignore */_a) { /* ignore */ }
85
813
  }
86
814
  return DEFAULT_PRESETS;
87
815
  }
816
+ /**
817
+ * Los grupos EN EL ORDEN EN QUE SE RENDERIZAN, cada uno con el índice plano
818
+ * de su primer swatch (`from`). La navegación por flechas se indexa contra
819
+ * este aplanado, no contra `parsedPresets`: si el orden del render y el del
820
+ * array divergieran, una flecha movería el foco a otro swatch.
821
+ *
822
+ * La frontera neutros/marca sale de `NEUTRAL_PRESET_KEYS` — la única fuente
823
+ * de la paleta. Nada de `slice(0, 5)`: ese `5` ya estaba duplicado en tres
824
+ * lugares y es lo que la task anterior vino a eliminar.
825
+ */
826
+ get presetGroups() {
827
+ const presets = this.parsedPresets;
828
+ // La partición sale de la MEMBRESÍA de `key` (`splitPaletteGroups`), no de
829
+ // comparar identidad contra `DEFAULT_PRESETS`: el consumidor real manda la
830
+ // misma paleta re-serializada con los nombres traducidos, y por identidad
831
+ // eso caía siempre en "custom" — los rótulos no se anunciaban nunca.
832
+ const split = splitPaletteGroups(presets);
833
+ // Sin partición que signifique algo (hexes sueltos, keys desconocidas, un
834
+ // solo lado) va todo en un grupo, sin rótulo inventado.
835
+ if (!split) {
836
+ return [{ label: undefined, items: presets, from: 0 }];
837
+ }
838
+ return [
839
+ { label: this.strings.groupNeutrals, items: split.neutrals, from: 0 },
840
+ { label: this.strings.groupBrand, items: split.brand, from: split.neutrals.length },
841
+ ];
842
+ }
843
+ /** Los swatches aplanados en orden de render: la lista que recorren las flechas. */
844
+ get flatPresets() {
845
+ return flattenGroups(this.presetGroups);
846
+ }
88
847
  /** Devuelve el foco al trigger al cerrar el panel (Escape, selección),
89
848
  * salvo que el cierre venga de un click-outside que ya movió el foco a
90
849
  * otro elemento — en ese caso no robarlo. */
@@ -96,11 +855,120 @@ const CoColorPicker = class {
96
855
  }
97
856
  }
98
857
  handleSwatchClick(hex) {
99
- this.value = hex;
100
- this.coChange.emit(hex);
858
+ // Elegir un preset es un commit como cualquier otro: la asignación y el
859
+ // emit viven en `commit`, no duplicados acá (si no, el swatch dejaría el
860
+ // HSV del color anterior y el área abriría en el color equivocado).
861
+ this.commit(hex);
101
862
  this.isOpen = false;
102
863
  this.restoreTriggerFocus();
103
864
  }
865
+ /** Mueve el tab stop del área (y el foco) al eje pedido. */
866
+ focusAxis(axis) {
867
+ this.areaAxis = axis;
868
+ const el = axis === 's' ? this.satEl : this.valEl;
869
+ if (!el)
870
+ return;
871
+ // El render de Stencil es ASÍNCRONO: enfocar mientras el input todavía
872
+ // tiene `aria-hidden` puede hacer que el lector de pantalla se coma el
873
+ // anuncio (el nodo no está en el árbol en el instante del evento), y un
874
+ // frame después no hay ningún evento nuevo que lo dispare. Se sincroniza a
875
+ // mano y el próximo render converge al mismo valor. Guard: area.spec.
876
+ //
877
+ // El `tabindex` NO hace falta tocarlo: `focus()` entra igual en un
878
+ // `tabindex=-1` —es exactamente lo que hace operable al eje oculto— y el
879
+ // tab order se corrige en el render, dentro del mismo frame.
880
+ el.removeAttribute('aria-hidden');
881
+ el.focus();
882
+ }
883
+ optionEls() {
884
+ var _a, _b;
885
+ // `Array.from`, NO spread: el build de Stencil tipa con `lib: ["dom","es2020"]`
886
+ // SIN `dom.iterable`, así que spreadear un NodeList no compila (y `tsc --noEmit`
887
+ // con este tsconfig no lo detecta — sólo revienta en `stencil build`).
888
+ return Array.from((_b = (_a = this.gridEl) === null || _a === void 0 ? void 0 : _a.querySelectorAll('[role="option"]')) !== null && _b !== void 0 ? _b : []);
889
+ }
890
+ /**
891
+ * Vecino de arriba/abajo EN PANTALLA.
892
+ *
893
+ * La grilla no es una matriz única: son N grillas de 6 columnas apiladas, una
894
+ * por grupo, y la de neutros tiene 5 celdas. Por eso un stride plano de ±6
895
+ * sobre el índice global se corre una columna al cruzar la frontera (Black,
896
+ * columna 0, caía en Olive, columna 1). Fila y columna se calculan DENTRO del
897
+ * grupo; al cruzar al grupo vecino se conserva la columna, que es lo que
898
+ * "fila anterior / siguiente" significa visualmente.
899
+ *
900
+ * En el borde de la grilla el foco NO se mueve: colapsarlo al extremo mandaba
901
+ * cualquier neutro de la primera fila a Black.
902
+ *
903
+ * Asimetría DELIBERADA con las flechas horizontales, que sí wrappean (0↔16):
904
+ * el wrap cíclico en un eje y el tope duro en el otro es lo que hace APG para
905
+ * grillas, y es lo que deja claro dónde termina la paleta.
906
+ */
907
+ verticalNeighbor(groups, current, dir) {
908
+ const gi = groups.findIndex((g) => current >= g.from && current < g.from + g.items.length);
909
+ if (gi < 0)
910
+ return current;
911
+ const g = groups[gi];
912
+ const j = current - g.from;
913
+ const col = j % GRID_COLS;
914
+ const rows = Math.ceil(g.items.length / GRID_COLS);
915
+ const targetRow = Math.floor(j / GRID_COLS) + dir;
916
+ // Hay fila dentro del MISMO grupo. La última puede estar incompleta.
917
+ if (targetRow >= 0 && targetRow < rows) {
918
+ return g.from + Math.min(targetRow * GRID_COLS + col, g.items.length - 1);
919
+ }
920
+ const neighbor = groups[gi + dir];
921
+ if (!neighbor)
922
+ return current;
923
+ // Entrando desde arriba se aterriza en la primera fila; desde abajo, en la última.
924
+ const nRows = Math.ceil(neighbor.items.length / GRID_COLS) || 1;
925
+ const landingRow = dir === 1 ? 0 : nRows - 1;
926
+ return neighbor.from + Math.min(landingRow * GRID_COLS + col, neighbor.items.length - 1);
927
+ }
928
+ /**
929
+ * El área saturación×brillo.
930
+ *
931
+ * Es un `role="group"` con UN `<input type="range">` invisible por eje —el
932
+ * modelo de React Aria—, en vez de un `role="slider"` 2D a mano: así el eje
933
+ * lo maneja un control nativo (teclado, repetición de tecla, anuncio del
934
+ * lector de pantalla) y sólo el arrastre queda de nuestro lado.
935
+ *
936
+ * El matiz viaja al CSS por custom property: el gradiente es CSS puro, sin
937
+ * canvas y sin un hex literal en la hoja de estilos.
938
+ */
939
+ renderArea() {
940
+ const { h: hue, s, v } = this.hsv;
941
+ // El eje enfocado es el único con tab stop y el único anunciado.
942
+ const satFocused = this.areaAxis === 's';
943
+ return (index.h("div", { class: "co-color-picker__area", role: "group", "aria-label": this.strings.area, ref: (el) => (this.areaEl = el), style: { '--co-color-picker-hue': `${hue}` }, onPointerDown: this.handleAreaPointerDown, onPointerMove: this.handleAreaPointerMove, onPointerUp: this.handleAreaPointerUp, onPointerCancel: this.handleAreaPointerCancel }, index.h("span", { class: "co-color-picker__area-thumb", role: "presentation", style: { left: `${s}%`, top: `${100 - v}%`, background: this.value } }), index.h("input", { type: "range", min: "0", max: "100", step: "1", class: "co-color-picker__channel", "data-channel": "s", value: Math.round(s), ref: (el) => (this.satEl = el), tabIndex: satFocused ? 0 : -1, "aria-hidden": satFocused ? undefined : 'true', "aria-label": this.strings.saturation, "aria-roledescription": this.strings.area2D, "aria-valuetext": fileI18n.fillTemplate(this.strings.satValue, { n: Math.round(s) }), "aria-orientation": "horizontal", disabled: this.disabled, onFocus: () => (this.areaAxis = 's'), onInput: (e) => this.previewHsv({ s: +e.target.value }), onChange: () => this.commit(color.hsvToHex(this.hsv)), onKeyDown: this.handleAreaKeyDown }), index.h("input", { type: "range", min: "0", max: "100", step: "1", class: "co-color-picker__channel", "data-channel": "v", value: Math.round(v), ref: (el) => (this.valEl = el), tabIndex: satFocused ? -1 : 0, "aria-hidden": satFocused ? 'true' : undefined, "aria-label": this.strings.brightness, "aria-roledescription": this.strings.area2D, "aria-valuetext": fileI18n.fillTemplate(this.strings.briValue, { n: Math.round(v) }), "aria-orientation": "vertical", disabled: this.disabled, onFocus: () => (this.areaAxis = 'v'), onInput: (e) => this.previewHsv({ v: +e.target.value }), onChange: () => this.commit(color.hsvToHex(this.hsv)), onKeyDown: this.handleAreaKeyDown })));
944
+ }
945
+ renderHue() {
946
+ return (index.h("input", { type: "range", min: "0", max: "360", step: "1", class: "co-color-picker__hue-input", value: Math.round(this.hsv.h), "aria-label": this.strings.hue, "aria-valuetext": fileI18n.fillTemplate(this.strings.hueValue, { n: Math.round(this.hsv.h) }), disabled: this.disabled, onInput: (e) => this.previewHsv({ h: +e.target.value }), onChange: () => this.commit(color.hsvToHex(this.hsv)), onKeyDown: this.handleHueKeyDown }));
947
+ }
948
+ renderSwatches() {
949
+ return (index.h("div", { class: "co-color-picker__grid", role: "listbox", "aria-label": this.strings.swatches, ref: (el) => (this.gridEl = el), onKeyDown: this.handleGridKeyDown }, this.presetGroups.map((g) => (
950
+ // Agrupación SÓLO para lectores de pantalla: en pantalla los separa el
951
+ // gap, sin rótulos (costaban ~56px y no aportaban — spec §4).
952
+ // `key` por el índice plano de arranque (0 / 5), NO por el rótulo:
953
+ // el rótulo cambia con `locale` y remontaría los grupos al traducir.
954
+ //
955
+ // Sin rótulo el contenedor es PRESENTACIONAL: un `role="group"`
956
+ // anónimo particiona el listbox para el lector de pantalla anunciando
957
+ // una frontera que no significa nada. El div igual tiene que existir
958
+ // —es el que da las 6 columnas—, así que `presentation` lo saca del
959
+ // árbol de accesibilidad y las opciones quedan colgando del listbox.
960
+ index.h("div", { class: "co-color-picker__grid-group", key: g.from, role: g.label ? 'group' : 'presentation', "aria-label": g.label }, g.items.map((preset, j) => {
961
+ const i = g.from + j;
962
+ const selected = preset.value.toUpperCase() === (this.value || '').toUpperCase();
963
+ return (index.h("div", { key: preset.value, role: "option", "aria-selected": selected ? 'true' : 'false', "aria-label": preset.name, tabIndex: i === this.focusedIndex ? 0 : -1, class: {
964
+ 'co-color-picker__grid-item': true,
965
+ 'co-color-picker__grid-item--selected': selected,
966
+ // Un swatch claro se pierde contra el panel: se decide por
967
+ // luminancia, no por una lista de hex hardcodeada.
968
+ 'co-color-picker__grid-item--light': color.isLightColor(preset.value),
969
+ }, style: { background: preset.value }, onFocus: () => (this.focusedIndex = i), onClick: () => this.handleSwatchClick(preset.value) }, selected && (index.h("co-icon", { name: "check", size: 16, weight: "bold", class: "co-color-picker__grid-check" }))));
970
+ }))))));
971
+ }
104
972
  get statusIcon() {
105
973
  const map = {
106
974
  error: 'warning-circle',
@@ -109,6 +977,142 @@ const CoColorPicker = class {
109
977
  };
110
978
  return map[this.status] || null;
111
979
  }
980
+ /**
981
+ * Lo que se puede TIPEAR en el campo: dígitos hex, hasta 6. El 7º caracter y
982
+ * el `#` no entran, y con 8 dígitos (hex con alpha) se queda con los 6 de
983
+ * color — este picker no maneja alpha.
984
+ */
985
+ escapeHex(v) {
986
+ return (v || '').replace(/[^0-9a-f]/gi, '').substring(0, 6).toUpperCase();
987
+ }
988
+ /** `F00` → `#FF0000`: lo emitido es SIEMPRE de 6 dígitos. */
989
+ expandHex(v) {
990
+ const hx = v.replace('#', '');
991
+ const full = hx.length === 3 ? hx[0] + hx[0] + hx[1] + hx[1] + hx[2] + hx[2] : hx;
992
+ return `#${full.toUpperCase()}`;
993
+ }
994
+ /**
995
+ * Siembra el campo desde el valor REAL y cierra cualquier edición abierta.
996
+ *
997
+ * Con `value` vacío queda vacío: el estado interno arranca en EMPTY_HSV (rojo
998
+ * puro) para que el área tenga de dónde partir, pero eso es un seed de
999
+ * DISPLAY del área — espejarlo pondría `FF0000` escrito en un campo que el
1000
+ * usuario nunca tocó, anunciando un color que nadie eligió.
1001
+ */
1002
+ resetHexDraft() {
1003
+ // Apagar la edición va PRIMERO y es lo que hace incondicional a la
1004
+ // siembra: `syncHexDraft` se abstiene mientras el flag esté prendido, así
1005
+ // que sin esto un flag colgado dejaría la re-siembra en no-op.
1006
+ //
1007
+ // Hoy es defensivo y conviene decirlo: `finishHexEdit` —que corre en todo
1008
+ // cierre de panel— ya apaga el flag antes de cualquier otra cosa, así que
1009
+ // ningún test lo distingue. Se queda porque es la precondición de la línea
1010
+ // de abajo, no por un caso conocido que lo necesite.
1011
+ this.hexEditing = false;
1012
+ this.syncHexDraft(this.value);
1013
+ }
1014
+ /**
1015
+ * Espeja el valor real en el campo, salvo mientras el usuario lo está
1016
+ * tipeando.
1017
+ *
1018
+ * Sólo espeja lo que YA es un color (o el vacío, que limpia). `escapeHex`
1019
+ * sobre cualquier otra cosa fabrica un hex verosímil: un host que pase
1020
+ * `rebeccapurple` o `var(--co-color-primary-verde)` vería el campo mostrando
1021
+ * `EBECCA` / `ACCAED`. Es exactamente la falla que el pegado cancela unas
1022
+ * líneas más abajo, y entraba igual por la puerta de la prop. Los frames de
1023
+ * arrastre siempre escriben un hex de 6, así que no se pierde nada legítimo.
1024
+ */
1025
+ syncHexDraft(hex) {
1026
+ if (this.hexEditing)
1027
+ return;
1028
+ if (hex && !color.isValidHex(hex))
1029
+ return;
1030
+ this.hexDraft = this.escapeHex(hex);
1031
+ }
1032
+ /**
1033
+ * Fin del gesto del campo: blur, Enter, o el cierre del panel.
1034
+ *
1035
+ * Commitea SIEMPRE que haya un color tipeado, sin comparar contra `value`
1036
+ * —que a esta altura ya vale el color previsualizado, así que "commitear si
1037
+ * cambió" no dispararía nunca—. Es el precedente del `pointerup` del área: el
1038
+ * fin de gesto commitea, y si el usuario retipeó el mismo color, el `coChange`
1039
+ * redundante es el precio.
1040
+ *
1041
+ * ⚠️ Consecuencia documentada de esa regla: tipear un hex válido y después
1042
+ * clickear un swatch emite DOS `coChange` — el blur commitea el color
1043
+ * tipeado, y el swatch el suyo. Es el precio explícito de que el fin de gesto
1044
+ * no adivine intenciones, no un bug.
1045
+ *
1046
+ * Y si no hay nada que commitear, se DESHACE el preview vivo. Eso cubre dos
1047
+ * casos con el mismo movimiento: el texto que quedó a medias (`12`), y el
1048
+ * arrastre abortado —que emitía `coInput`, escribía `value` y no commiteaba
1049
+ * nunca, dejando al picker mostrando un color que el host jamás recibió—.
1050
+ */
1051
+ finishHexEdit() {
1052
+ const editing = this.hexEditing;
1053
+ this.hexEditing = false;
1054
+ // Un picker deshabilitado no emite ni escribe, ni siquiera para deshacer:
1055
+ // si el host lo apagó con un preview colgado, el `value` es asunto suyo.
1056
+ if (this.disabled)
1057
+ return;
1058
+ if (editing && color.isValidHex(this.hexDraft)) {
1059
+ const hex = this.expandHex(this.hexDraft);
1060
+ this.commit(hex);
1061
+ // El espejo se hace acá a mano porque el @Watch NO dispara: `commit`
1062
+ // reasigna a `value` el mismo hex que el preview ya había escrito, y
1063
+ // Stencil no corre el watcher cuando el valor no cambió. Sin esto, tipear
1064
+ // `F00` deja el campo mostrando `F00` mientras el color real ya es
1065
+ // `#FF0000` — el texto y el trigger diciendo cosas distintas.
1066
+ this.syncHexDraft(hex);
1067
+ return;
1068
+ }
1069
+ this.revertToCommitted();
1070
+ }
1071
+ /** Vuelve al último color commiteado y retira el preview que quedó colgado. */
1072
+ revertToCommitted() {
1073
+ const target = this.committed;
1074
+ // Por `syncHexDraft` y no por `escapeHex` a pelo: `committed` puede no ser
1075
+ // un hex (el host puede haber puesto `var(--co-brand)`), y escaparlo
1076
+ // fabricaría el mismo `ACBAD` verosímil que el guard de allá evita.
1077
+ this.syncHexDraft(target);
1078
+ // Volver a "sin color" devuelve el área a su vértice vivo. Si el gesto
1079
+ // abandonado terminó con `v=0`, reabrir dejaba el campo vacío Y el área en
1080
+ // negro, donde mover matiz o saturación no produce color alguno: es
1081
+ // exactamente el estado que EMPTY_HSV existe para evitar.
1082
+ if (!target)
1083
+ this.hsv = EMPTY_HSV;
1084
+ if ((this.value || '').toUpperCase() === (target || '').toUpperCase())
1085
+ return;
1086
+ // SIN sellar: acá el @Watch sí tiene que re-derivar el HSV, para que el área
1087
+ // vuelva al color commiteado y no se quede en el que se abandonó.
1088
+ this.value = target;
1089
+ // El @Watch no sella cuando `target` no es un hex (nunca se commiteó nada y
1090
+ // el campo vuelve a vacío), así que se sella acá.
1091
+ this.emitted = target;
1092
+ // El preview se anunció por `coInput`; retirarlo también. Un host que
1093
+ // previsualiza en vivo se quedaría si no con el color que nadie eligió.
1094
+ this.coInput.emit(target);
1095
+ }
1096
+ /**
1097
+ * Chrome/Edge 95+ solamente (MDN, 2026-09-02): Firefox, Safari y Chrome
1098
+ * Android no la tienen. Se resuelve en el render, no en una prop: si no está,
1099
+ * el botón no existe. Un control deshabilitado sin explicar es peor que su
1100
+ * ausencia — y una prop obligaría a cada host a repetir la detección.
1101
+ *
1102
+ * El `typeof window` es por el build de hydrate, donde no hay `window` y el
1103
+ * `in` tiraría.
1104
+ */
1105
+ get hasEyeDropper() {
1106
+ return typeof window !== 'undefined' && 'EyeDropper' in window;
1107
+ }
1108
+ renderHexRow() {
1109
+ const hasValue = !!this.value;
1110
+ return (index.h("div", { class: "co-color-picker__hex-row" }, index.h("span", { class: "co-color-picker__hex-prefix" }, "#"), index.h("input", { type: "text", class: "co-color-picker__hex-input", value: this.hexDraft, spellcheck: false, autocomplete: "off", maxLength: 6, "aria-label": this.strings.hexField, disabled: this.disabled, onInput: this.handleHexInput, onBlur: this.handleHexBlur, onKeyDown: this.handleHexKeyDown, onPaste: this.handleHexPaste }), this.hasEyeDropper && (index.h("button", { type: "button", class: "co-color-picker__eyedropper", title: this.strings.eyedropper, "aria-label": this.strings.eyedropper, disabled: this.disabled, onClick: this.handleEyeDropper }, index.h("co-icon", { name: "eyedropper", size: 16 }))), index.h("button", { type: "button", class: `co-color-picker__copy-btn ${this.copied ? 'co-color-picker__copy-btn--copied' : ''}`, title: this.strings.copy, "aria-label": this.strings.copy,
1111
+ // La fila ya no está detrás de `hasValue` —hay que poder tipear el
1112
+ // primer color—, así que el que se apaga es el botón: sin valor no
1113
+ // hay nada que copiar.
1114
+ disabled: this.disabled || !hasValue, onClick: () => this.handleCopy() }, index.h("co-icon", { name: this.copied ? 'check' : 'copy', size: 16 }))));
1115
+ }
112
1116
  async handleCopy() {
113
1117
  if (!this.value)
114
1118
  return;
@@ -120,15 +1124,21 @@ const CoColorPicker = class {
120
1124
  catch ( /* ignore */_a) { /* ignore */ }
121
1125
  }
122
1126
  render() {
123
- const presets = this.parsedPresets;
124
1127
  const hasValue = !!this.value;
125
1128
  const statusClass = this.status !== 'default' ? `co-color-picker--${this.status}` : '';
126
- return (index.h("div", { key: '5b99c6a39399a6731d09115e7fd2ce2d64baffb2', class: `co-color-picker co-color-picker--${this.size} ${statusClass} ${this.isOpen ? 'co-color-picker--open' : ''} ${this.disabled ? 'co-color-picker--disabled' : ''}` }, this.label && (index.h("label", { key: '816392c0b3cebcb2e84ea28ea7e6b7976503b6f9', class: "co-color-picker__label" }, this.label, index.h(requiredMark.RequiredMark, { key: 'e0e1c97522f4516763fc663878203e2dafb783b3', required: this.required }))), index.h("co-popover", { key: 'd49ba1f9cd64d2498940247f3ba02897dcc9d2d7', open: this.isOpen, placement: "bottom-start", matchWidth: true, offset: 4, onCoOpen: this.handlePopoverOpen, onCoClose: this.handlePopoverClose }, index.h("div", { key: '1121b429c89fb9cc066cc66564ae547687bf8ed3', slot: "trigger", class: "co-color-picker__trigger", role: "combobox", "aria-expanded": this.isOpen ? 'true' : 'false', "aria-haspopup": "dialog", "aria-controls": this.isOpen ? CoColorPicker.PANEL_ID : undefined, "aria-label": this.label || undefined, "aria-disabled": this.disabled ? 'true' : undefined, tabIndex: this.disabled ? -1 : 0, ref: (el) => (this.triggerEl = el), onKeyDown: this.handleTriggerKeyDown }, index.h("span", { key: '2567db35022b5ffdd9921d8bec263c90103fd5f3', class: "co-color-picker__swatch", style: { background: hasValue ? this.value : 'transparent' } }), index.h("span", { key: '7fecc93b5ecc91acf2c874a26ed1f9d8770d9adf', class: `co-color-picker__value ${!hasValue ? 'co-color-picker__value--empty' : ''}` }, hasValue ? this.value : this.placeholder)), this.isOpen && (index.h("div", { key: '44d904e4156fac15b302ffe86d68cef72bc7518e', class: "co-color-picker__panel", id: CoColorPicker.PANEL_ID, role: "dialog", "aria-label": this.label || this.placeholder }, index.h("div", { key: 'a566f189c87792f0af3e493c00eed7240dcd49c9', class: "co-color-picker__grid" }, presets.map((preset) => {
127
- var _a;
128
- return (index.h("button", { type: "button", key: preset.value, class: `co-color-picker__grid-item ${preset.value.toUpperCase() === ((_a = this.value) === null || _a === void 0 ? void 0 : _a.toUpperCase()) ? 'co-color-picker__grid-item--selected' : ''}`, style: { background: preset.value }, title: preset.name, onClick: () => this.handleSwatchClick(preset.value) }));
129
- })), hasValue && (index.h("div", { key: 'bae8ffe387fe30710b654975379e70a4b3724ec9', class: "co-color-picker__hex-row" }, index.h("span", { key: '671a5a64abc2f824c8d1ef8c2404023d8d51c28d', class: "co-color-picker__hex-prefix" }, "#"), index.h("span", { key: '3a6742eb528c5a92fe16b2f2e5d8b2ebdf885450', class: "co-color-picker__hex-value" }, this.value.replace(/^#/, '')), index.h("button", { key: 'f53957b494dbed0648d32fcb743673a2ada063b4', type: "button", class: `co-color-picker__copy-btn ${this.copied ? 'co-color-picker__copy-btn--copied' : ''}`, title: "Copy", onClick: () => this.handleCopy() }, index.h("co-icon", { key: 'c99e611beddc2108f3973ecee4f6012423cffd23', name: this.copied ? 'check' : 'copy', size: 16 }))))))), this.helperText && (index.h("div", { key: '1d6a6e97eab1eafcb9265944693cb0d1121e04ee', class: "co-color-picker__helper" }, this.statusIcon && (index.h("co-icon", { key: 'bcf943836fddf264cede2f339844f35aa167002f', name: this.statusIcon, size: 14, weight: "fill", class: "co-color-picker__helper-icon" })), index.h("span", { key: 'a439c4d102d17d0d6c9e55757dcf43ec8b3ade8f', class: "co-color-picker__helper-text" }, this.helperText)))));
1129
+ return (index.h("div", { key: 'd0069249895cc3cf148c963f149ff7b3a15ab939', class: `co-color-picker co-color-picker--${this.size} ${statusClass} ${this.isOpen ? 'co-color-picker--open' : ''} ${this.disabled ? 'co-color-picker--disabled' : ''}` }, this.label && (index.h("label", { key: 'e28d265aefc19f7e86ed36bfbfe6b6ec537d1ca2', class: "co-color-picker__label" }, this.label, index.h(requiredMark.RequiredMark, { key: '0aff2dde3002e1c9a79f2c3a385b64d33dc3418c', required: this.required }))), index.h("co-popover", { key: 'edac2d09e0d15c2f09dfff2ea0a2b95f5384d8de', open: this.isOpen, placement: "bottom-start",
1130
+ // Sin `matchWidth`: el panel tiene ancho INTRÍNSECO (grilla de 8
1131
+ // swatches fijos de 32px). Copiar el ancho del trigger achica los
1132
+ // tracks bajo 32px con un campo angosto (media columna de un modal) y
1133
+ // los swatches desbordan el card — guard: panel-width.spec.
1134
+ offset: 4, onCoOpen: this.handlePopoverOpen, onCoClose: this.handlePopoverClose }, index.h("div", { key: '98c2e3c5ed50f8cc869c1cf791ddce85e8887b8e', slot: "trigger", class: "co-color-picker__trigger", role: "combobox", "aria-expanded": this.isOpen ? 'true' : 'false', "aria-haspopup": "dialog", "aria-controls": this.isOpen ? CoColorPicker.PANEL_ID : undefined, "aria-label": this.label || undefined, "aria-disabled": this.disabled ? 'true' : undefined, tabIndex: this.disabled ? -1 : 0, ref: (el) => (this.triggerEl = el), onKeyDown: this.handleTriggerKeyDown }, index.h("span", { key: '65e49a6246c71b6366f7907c715c64259c30be46', class: "co-color-picker__swatch", style: { background: hasValue ? this.value : 'transparent' } }), index.h("span", { key: 'd8e6e852383ec925c4336f9b49a69e73d88e2234', class: `co-color-picker__value ${!hasValue ? 'co-color-picker__value--empty' : ''}` }, hasValue ? this.value : this.placeholder)), this.isOpen && (index.h("div", { key: '2893b57d82d7ac2edc4e3bd8eac266fdc6cbfba0', class: "co-color-picker__panel", id: CoColorPicker.PANEL_ID, role: "dialog", "aria-label": this.label || this.placeholder }, this.renderArea(), this.renderHue(), this.renderSwatches(), this.renderHexRow()))), this.helperText && (index.h("div", { key: 'ca583c8033afaafa5bdd59ccd63e711eaf02e6df', class: "co-color-picker__helper" }, this.statusIcon && (index.h("co-icon", { key: 'aca2fd8186658e7d4e13ab67dc7a6e93c2fd8b89', name: this.statusIcon, size: 14, weight: "fill", class: "co-color-picker__helper-icon" })), index.h("span", { key: 'e8e3cdf72353a1f5fb8b53fe725389386c7d75ea', class: "co-color-picker__helper-text" }, this.helperText)))));
130
1135
  }
131
1136
  get el() { return index.getElement(this); }
1137
+ static get watchers() { return {
1138
+ "value": [{
1139
+ "syncFromValue": 0
1140
+ }]
1141
+ }; }
132
1142
  };
133
1143
  /**
134
1144
  * Id del panel de presets, target de `aria-controls` del trigger. Constante
@@ -139,6 +1149,17 @@ const CoColorPicker = class {
139
1149
  * on-demand, así que cerrado el IDREF quedaría colgante.
140
1150
  */
141
1151
  CoColorPicker.PANEL_ID = 'co-color-picker-panel';
1152
+ /**
1153
+ * Qué eje mueve cada flecha DENTRO del área, y en qué sentido. Un range
1154
+ * horizontal nativo también responde a ↑/↓ moviendo SU eje, así que sin esta
1155
+ * tabla (y su `preventDefault`) la flecha de arriba subía la saturación.
1156
+ */
1157
+ CoColorPicker.AREA_KEYS = {
1158
+ ArrowRight: { axis: 's', dir: 1 },
1159
+ ArrowLeft: { axis: 's', dir: -1 },
1160
+ ArrowUp: { axis: 'v', dir: 1 },
1161
+ ArrowDown: { axis: 'v', dir: -1 },
1162
+ };
142
1163
  CoColorPicker.style = coColorPickerCss();
143
1164
 
144
1165
  exports.co_color_picker = CoColorPicker;