@prolibu-suite/cobalt-core 0.9.6 → 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 +12 -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-7532c739.entry.js +0 -1
  572. package/dist/cobalt/p-7c88163e.entry.js +0 -1
  573. package/dist/cobalt/p-7cf4b4ae.entry.js +0 -1
  574. package/dist/cobalt/p-7ea87b75.entry.js +0 -1
  575. package/dist/cobalt/p-8183f56f.entry.js +0 -1
  576. package/dist/cobalt/p-8345b25f.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-Bbny3WUc.js +0 -1
  599. package/dist/components/p-Bz0QZqnB.js +0 -1
  600. package/dist/components/p-CF8OB_TM.js +0 -1
  601. package/dist/components/p-CR0izsJC.js +0 -1
  602. package/dist/components/p-CnNpoKwg.js +0 -1
  603. package/dist/components/p-DI1ek0EB.js +0 -1
  604. package/dist/components/p-DP0bbhfN.js +0 -1
  605. package/dist/components/p-D_9BRkj6.js +0 -1
  606. package/dist/components/p-DbipMAyT.js +0 -1
  607. package/dist/components/p-DgUBcJIS.js +0 -1
  608. package/dist/components/p-DolCkNsL.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,14 +1,64 @@
1
1
  import { h } from "@stencil/core";
2
2
  import { RequiredMark } from "../../utils/requiredMark";
3
- import { DEFAULT_PRESETS } from "./presets";
3
+ import { hexToHsv, hsvToHex, isLightColor, isValidHex, parseCssColor } from "../../utils/color";
4
+ import { getColorPickerStrings } from "../../utils/colorPickerI18n";
5
+ // `{n}` de los aria-valuetext. Se reutiliza el de fileI18n —el mismo que ya
6
+ // resuelve las plantillas de co-file-field—, no se duplica acá.
7
+ import { fillTemplate } from "../../utils/fileI18n";
8
+ import { DEFAULT_PRESETS, resolvePreset, splitPaletteGroups, } from "./presets";
9
+ /** Columnas de la grilla. 6×32 + 5×8 de gap + 24 de padding = 256px. */
10
+ const GRID_COLS = 6;
11
+ /** Paso grueso de Shift+flecha (SLDS). La flecha sola usa el paso nativo del range: 1. */
12
+ const SHIFT_STEP = 10;
13
+ /**
14
+ * Un pegado que YA es hex, o el principio de uno (`02`, `#0263`). Es lo único
15
+ * que se deja caer al escape cuando `parseCssColor` no reconoce el texto: así
16
+ * se puede pegar un fragmento y seguir tipeando, sin que un pegado que no es un
17
+ * color (un nombre CSS, una frase) se convierta en un hex inventado.
18
+ */
19
+ const HEX_FRAGMENT = /^#?[0-9a-f]*$/i;
20
+ /**
21
+ * De dónde parte el área cuando el campo está VACÍO: rojo puro, con el thumb en
22
+ * la esquina viva.
23
+ *
24
+ * No es cosmético. El vértice negro (`{0,0,0}`) deja DOS de los tres controles
25
+ * sin poder producir color: con `v=0`, mover el matiz o la saturación da
26
+ * `#000000` haga lo que haga el usuario. Y en suite-v2 `coChange` significa
27
+ * commit, así que un gesto exploratorio sobre un campo vacío lo dejaba en negro
28
+ * Y con "cambios sin guardar", sin que nadie haya elegido nada.
29
+ *
30
+ * El seed es de DISPLAY: no toca `value` ni emite. Hasta que el usuario actúa,
31
+ * el trigger sigue mostrando su placeholder.
32
+ *
33
+ * Congelado: es un objeto de MÓDULO, compartido por el initializer, el caché y
34
+ * el fallback de `componentWillLoad`. Hoy nadie lo muta —`previewHsv` hace
35
+ * spread y `commit` reasigna—, pero un `this.hsv.h = …` futuro envenenaría a
36
+ * todas las instancias de la página a la vez, y ése es un bug que no se
37
+ * encuentra mirando el componente que lo sufre.
38
+ *
39
+ * El tipo es `Readonly<Hsv>` y no `Hsv`: anotarlo como `Hsv` BORRA el
40
+ * `Readonly` que devuelve `Object.freeze`, y la protección queda sólo en
41
+ * runtime — TS no marcaría `EMPTY_HSV.h = 1` en compilación. Sigue siendo
42
+ * asignable a `this.hsv: Hsv`.
43
+ */
44
+ const EMPTY_HSV = Object.freeze({ h: 0, s: 100, v: 100 });
45
+ /** Los swatches de todos los grupos, en orden de render. */
46
+ const flattenGroups = (groups) => groups.reduce((acc, g) => acc.concat(g.items), []);
4
47
  /**
5
48
  * Color picker with preset swatches. Shows a trigger with the current color
6
- * swatch + hex value, and opens a popover panel with a grid of preset colors.
49
+ * swatch + hex value, and opens a popover panel with a saturation/brightness
50
+ * area, a hue slider, a grid of preset colors and an editable hex field.
7
51
  *
8
- * The hex value is read-only (no manual editing) — a copy button lets the user
9
- * copy the value to clipboard.
52
+ * The hex field previews while typing (`coInput`) and commits on gesture end
53
+ * — blur, Enter or panel close — like every other control in the panel. A
54
+ * pasted CSS color commits immediately; a copy button copies the current value.
10
55
  *
11
- * @event coChange - Emits the selected hex string (e.g. "#0066FF").
56
+ * @event coInput - Live hex while a gesture is in flight — dragging the area or
57
+ * the hue slider, and typing a valid hex in the field (preview only, never a
58
+ * commit).
59
+ * @event coChange - Emits the committed hex string (e.g. "#0066FF"): pointer
60
+ * release, arrow key, swatch click, paste, and the end of a hex-field edit
61
+ * (blur, Enter or panel close).
12
62
  */
13
63
  export class CoColorPicker {
14
64
  constructor() {
@@ -31,13 +81,108 @@ export class CoColorPicker {
31
81
  * or plain hex strings. When set programmatically, accepts an actual array.
32
82
  */
33
83
  this.presets = '';
84
+ /** Idioma de los textos accesibles. Misma prop que co-file-field/co-date-picker. */
85
+ this.locale = 'en';
34
86
  this.isOpen = false;
35
87
  this.copied = false;
88
+ /**
89
+ * El estado AUTORITATIVO del color mientras el picker está vivo: HSV en punto
90
+ * flotante. El hex es una derivación de presentación, no la fuente.
91
+ *
92
+ * ⛔ No redondear: el redondeo a entero rompe el round-trip (#02A270 vuelve
93
+ * como #02A370) y ése es el temblor del cursor al arrastrar. El redondeo va
94
+ * sólo en el borde (el `value` de los range y los aria-valuetext).
95
+ */
96
+ this.hsv = EMPTY_HSV;
97
+ /**
98
+ * El TEXTO del campo hex (sin `#`), que mientras se tipea puede no ser un
99
+ * color: `12` es un hex a medio escribir, no un error. El valor real sigue
100
+ * siendo `value`; esto es sólo lo que se ve en el campo.
101
+ */
102
+ this.hexDraft = '';
103
+ /**
104
+ * Si el usuario está tipeando en el campo hex. Mientras lo esté, el campo NO
105
+ * se re-espeja desde `value`: como el commit es en vivo, tipear `F00` emite
106
+ * `#FF0000` y espejarlo le reescribiría el texto bajo el cursor (react-colorful
107
+ * hace lo mismo, pero mirándole el foco al input; acá es un flag explícito
108
+ * porque el foco dentro de un shadow root no sale por `document.activeElement`
109
+ * y porque un flag es observable desde los tests).
110
+ *
111
+ * Se apaga en el blur y al reabrir el panel: un texto a medias abandonado por
112
+ * una vía que no entrega blur (Escape desmonta el panel entero) no puede
113
+ * dejar el espejo roto para siempre.
114
+ */
115
+ this.hexEditing = false;
116
+ /**
117
+ * Cuál de los dos ejes del área tiene el tab stop. El otro sale del tab order
118
+ * (`tabindex=-1`) y del árbol de accesibilidad (`aria-hidden`), así que el
119
+ * formulario lista UN control por campo y el lector anuncia uno solo — pero
120
+ * los dos siguen operables, porque la flecha del eje oculto le mueve el foco
121
+ * por código. Es @State porque de él dependen atributos pintados.
122
+ */
123
+ this.areaAxis = 's';
124
+ /**
125
+ * Último hex que escribimos en `value`. Es el anti-drift de la capa de estado:
126
+ * si el host nos devuelve el mismo hex que acabamos de emitir, NO se
127
+ * re-convierte a HSV — un redondeo distinto movería el cursor solo.
128
+ * (El otro anti-drift está en color.ts: Hsv es float, nunca entero.)
129
+ *
130
+ * Guardaba también el HSV que produjo ese hex, y nadie lo leía nunca: los
131
+ * cuatro puntos que sellan el caché lo hacen inmediatamente después de
132
+ * asignar `this.hsv`, así que la copia era `this.hsv` por otro nombre —
133
+ * imposible de desincronizar y, por lo mismo, imposible de aprovechar. Un
134
+ * campo muerto dentro de un anti-drift es una invitación a "usarlo" y
135
+ * reintroducir justo el drift que esto evita.
136
+ */
137
+ this.emitted = '';
138
+ /**
139
+ * El último hex realmente COMMITEADO (`coChange`), que es cosa distinta de
140
+ * `emitted`: ése lo sella también cada frame de preview, así que no puede
141
+ * decir a qué color volver cuando un gesto termina sin commitear.
142
+ *
143
+ * Es la línea de base del deshacer: a él vuelve un texto que quedó a medias
144
+ * y —el agujero que esto además tapa— un arrastre abortado, que hoy dejaba
145
+ * `value` en el color previsualizado sin que el host se hubiera enterado
146
+ * nunca por `coChange`.
147
+ */
148
+ this.committed = '';
149
+ /**
150
+ * Índice del swatch enfocado, para la navegación por flechas (roving tabindex).
151
+ * Es @State y no un campo suelto porque el `tabIndex` de cada opción se pinta
152
+ * a partir de él: sin reactividad, las flechas moverían el foco pero el DOM
153
+ * quedaría con el tabbable original y salir/volver con Tab caería en el
154
+ * swatch equivocado.
155
+ */
156
+ this.focusedIndex = 0;
157
+ /**
158
+ * Si hay un arrastre ABIERTO sobre el área (hubo `pointerdown` acá que sí
159
+ * pudo traducir el punto). Sin esto, cualquier `pointerup` que aterrice sobre
160
+ * el área commitea: un arrastre iniciado en otra parte del panel y soltado
161
+ * encima emitía un `coChange` que el usuario nunca pidió — y en suite-v2
162
+ * commit significa formulario sucio.
163
+ */
164
+ this.areaDragging = false;
36
165
  this.handlePopoverOpen = () => {
37
166
  this.isOpen = true;
167
+ // Toda reapertura arranca sin gesto abierto: si el anterior se abortó por
168
+ // una vía que no entrega ningún evento al área (Escape con el botón
169
+ // apretado desmonta el panel), este es el punto por el que sí se pasa.
170
+ this.areaDragging = false;
171
+ // Y sin edición de texto abierta: el panel se desmonta al cerrar, así que un
172
+ // texto a medias que se fue sin blur (Escape) no puede dejar el campo
173
+ // congelado en un draft ya divorciado del color.
174
+ this.resetHexDraft();
175
+ // Al abrir, el foco arranca en el color ya elegido (0 si no hay ninguno).
176
+ const i = this.flatPresets.findIndex((p) => p.value.toUpperCase() === (this.value || '').toUpperCase());
177
+ this.focusedIndex = i >= 0 ? i : 0;
38
178
  };
39
179
  this.handlePopoverClose = () => {
40
180
  this.isOpen = false;
181
+ // El cierre del panel TAMBIÉN cierra el gesto del campo, y no es un detalle:
182
+ // el navegador NO emite `blur` al remover un elemento enfocado, así que
183
+ // tipear un color y salir con Escape (o clickeando afuera) se perdería en
184
+ // silencio. Cubre además el arrastre abortado, que deja un preview colgado.
185
+ this.finishHexEdit();
41
186
  this.restoreTriggerFocus();
42
187
  };
43
188
  this.handleTriggerKeyDown = (e) => {
@@ -52,22 +197,492 @@ export class CoColorPicker {
52
197
  this.isOpen = true;
53
198
  }
54
199
  };
200
+ /**
201
+ * Coordenadas del puntero → saturación/brillo.
202
+ *
203
+ * ⚠️ Un `rect` degenerado NO se convierte en un color: con `rect.width === 0`
204
+ * (área todavía sin layout, o con `display:none`) la división da **Infinity**
205
+ * —no NaN: NaN sólo sale si el numerador es exactamente 0— y el clamp lo
206
+ * lleva a 1, así que un pointerdown escribiría `s=100, v=0`, o sea NEGRO, y
207
+ * lo emitiría como si el usuario lo hubiera elegido. Guard: area.spec.
208
+ */
209
+ this.pointerToHsv = (e) => {
210
+ var _a;
211
+ const rect = (_a = this.areaEl) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
212
+ if (!rect || !(rect.width > 0) || !(rect.height > 0))
213
+ return false;
214
+ const x = Math.min(Math.max((e.clientX - rect.left) / rect.width, 0), 1);
215
+ const y = Math.min(Math.max((e.clientY - rect.top) / rect.height, 0), 1);
216
+ this.previewHsv({ s: x * 100, v: (1 - y) * 100 });
217
+ return true;
218
+ };
219
+ this.handleAreaPointerDown = (e) => {
220
+ var _a, _b;
221
+ // Sólo el botón PRIMARIO pinta: con el secundario, el click derecho abría
222
+ // el menú contextual y de paso cambiaba y commiteaba el color.
223
+ if (this.disabled || e.button !== 0)
224
+ return;
225
+ // Captura sobre el ÁREA (el thumb es pointer-events:none, así que el target
226
+ // ya es ella) para no perder el arrastre al salirse del panel. Llamada
227
+ // opcional: no todo entorno la implementa (jsdom no la tiene) y el arrastre
228
+ // dentro del área funciona igual sin captura.
229
+ (_b = (_a = this.areaEl) === null || _a === void 0 ? void 0 : _a.setPointerCapture) === null || _b === void 0 ? void 0 : _b.call(_a, e.pointerId);
230
+ // El gesto queda abierto SÓLO si el área pudo traducir el punto: con un
231
+ // rect degenerado no hay nada que arrastrar, y por lo tanto nada que
232
+ // commitear al soltar.
233
+ this.areaDragging = this.pointerToHsv(e);
234
+ };
235
+ this.handleAreaPointerMove = (e) => {
236
+ // Sólo dentro de un arrastre abierto en el área y con el botón principal
237
+ // apretado: sin lo primero, un arrastre que empezó en otro lado repinta al
238
+ // pasar por encima; sin lo segundo, lo hace el hover a secas.
239
+ if (this.disabled || !this.areaDragging || e.buttons !== 1)
240
+ return;
241
+ this.pointerToHsv(e);
242
+ };
243
+ /**
244
+ * Un arrastre ABORTADO cierra el gesto sin commitear. Sin esto, el flag queda
245
+ * en `true` para siempre en esa instancia y el próximo `pointerup` suelto
246
+ * commitea — el mismo bug del gesto sin `pointerdown`, por otra puerta.
247
+ */
248
+ this.handleAreaPointerCancel = () => {
249
+ this.areaDragging = false;
250
+ };
251
+ this.handleAreaPointerUp = (e) => {
252
+ // Sólo cierra un gesto ABIERTO en esta área. Un `pointerup` suelto no
253
+ // commitea nada.
254
+ if (!this.areaDragging || e.button !== 0)
255
+ return;
256
+ this.areaDragging = false;
257
+ if (this.disabled)
258
+ return;
259
+ this.commit(hsvToHex(this.hsv));
260
+ };
261
+ /**
262
+ * Teclado del área: la flecha decide el eje, y ese eje pasa a ser el
263
+ * enfocado. El foco programático entra igual en el input con `tabindex=-1`
264
+ * —por eso el par tabindex-1 + aria-hidden no deja ningún eje inalcanzable—.
265
+ * SLDS: flecha = 1, Shift+flecha = 10.
266
+ */
267
+ this.handleAreaKeyDown = (e) => {
268
+ if (this.disabled)
269
+ return;
270
+ const move = CoColorPicker.AREA_KEYS[e.key];
271
+ // Home/End/PageUp/PageDown quedan DELEGADOS al range nativo, sobre su propio
272
+ // eje. ⚠️ Es el único resquicio de redondeo que queda en el camino del
273
+ // estado: el nativo opera sobre el `value` del DOM, que ya viene redondeado
274
+ // por el borde de presentación, así que PageUp/PageDown pierden la fracción
275
+ // al re-entrar por `onInput`. Es preexistente y deliberado —el salto de esas
276
+ // teclas es de 10 o al extremo, donde la fracción no significa nada—, pero
277
+ // queda anotado para que nadie lo lea como un descuido.
278
+ if (!move)
279
+ return;
280
+ e.preventDefault();
281
+ const step = e.shiftKey ? SHIFT_STEP : 1;
282
+ const next = Math.min(100, Math.max(0, this.hsv[move.axis] + move.dir * step));
283
+ this.focusAxis(move.axis);
284
+ this.previewHsv({ [move.axis]: next });
285
+ // Un teclazo es un gesto completo: preview + commit, no un arrastre abierto.
286
+ // Son DOS eventos por tecla (coInput y coChange), no uno.
287
+ this.commit(hsvToHex(this.hsv));
288
+ };
289
+ /**
290
+ * El matiz es un slider 1D suelto: las cuatro flechas son SU eje, así que el
291
+ * range nativo ya resuelve el paso de 1 y acá sólo se intercepta Shift.
292
+ */
293
+ this.handleHueKeyDown = (e) => {
294
+ if (this.disabled || !e.shiftKey)
295
+ return;
296
+ const dir = e.key === 'ArrowRight' || e.key === 'ArrowUp' ? 1
297
+ : e.key === 'ArrowLeft' || e.key === 'ArrowDown' ? -1
298
+ : 0;
299
+ if (!dir)
300
+ return;
301
+ // El range nativo aplicaría ADEMÁS su paso de 1 sobre el mismo evento.
302
+ e.preventDefault();
303
+ const next = Math.min(360, Math.max(0, this.hsv.h + dir * SHIFT_STEP));
304
+ this.previewHsv({ h: next });
305
+ this.commit(hsvToHex(this.hsv));
306
+ };
307
+ this.handleGridKeyDown = (e) => {
308
+ var _a;
309
+ // `presetGroups` re-parsea el JSON de `presets` y remapea en CADA lectura, y
310
+ // todos los consumidores reales pasan presets custom por prop: se resuelve
311
+ // UNA vez por tecla y se pasa por parámetro, no dos veces por getter.
312
+ const groups = this.presetGroups;
313
+ const presets = flattenGroups(groups);
314
+ const n = presets.length;
315
+ if (!n)
316
+ return;
317
+ // Un `focusedIndex` fuera de rango (los presets cambiaron con el panel
318
+ // abierto) se clampea en vez de indexar `undefined`.
319
+ const current = Math.min(Math.max(this.focusedIndex, 0), n - 1);
320
+ let next = current;
321
+ switch (e.key) {
322
+ // Wrap cíclico: regla de SLDS. APG lo trata como opcional.
323
+ case 'ArrowRight':
324
+ next = (current + 1) % n;
325
+ break;
326
+ case 'ArrowLeft':
327
+ next = (current - 1 + n) % n;
328
+ break;
329
+ case 'ArrowDown':
330
+ next = this.verticalNeighbor(groups, current, 1);
331
+ break;
332
+ case 'ArrowUp':
333
+ next = this.verticalNeighbor(groups, current, -1);
334
+ break;
335
+ case 'Home':
336
+ next = 0;
337
+ break;
338
+ case 'End':
339
+ next = n - 1;
340
+ break;
341
+ case 'Enter':
342
+ case ' ':
343
+ e.preventDefault();
344
+ this.handleSwatchClick(presets[current].value);
345
+ return;
346
+ default: return;
347
+ }
348
+ e.preventDefault();
349
+ this.focusedIndex = next;
350
+ // Query, NO `children`: los swatches cuelgan de dos `role=group`, así que
351
+ // el índice plano no coincide con los hijos directos del listbox.
352
+ (_a = this.optionEls()[next]) === null || _a === void 0 ? void 0 : _a.focus();
353
+ };
354
+ /**
355
+ * Tipear PREVISUALIZA (`coInput`), no commitea.
356
+ *
357
+ * El campo es el único control del panel donde el gesto se estira en el
358
+ * tiempo, y tratarlo como commit por caracter tiene un costo que no se ve
359
+ * hasta que se mira de cerca: corregir un typo de `0263EB` a `026` emitiría
360
+ * `coChange('#002266')` — el usuario está BORRANDO y el componente commitea
361
+ * un color nuevo. Con el preview, el campo queda igual que sus tres hermanos
362
+ * (área, matiz, swatches): en vivo mientras dura el gesto, commit al
363
+ * soltarlo. El `#002266` que pinta al pasar por `026` es un frame intermedio
364
+ * de preview, ni más ni menos que cualquier frame de arrastre.
365
+ */
366
+ this.handleHexInput = (e) => {
367
+ var _a, _b;
368
+ if (this.disabled)
369
+ return;
370
+ const el = e.target;
371
+ const raw = this.escapeHex(el.value);
372
+ // El escape se fuerza en el DOM: si el texto escapado no cambió (tipear `zz`
373
+ // sobre `12` sigue dando `12`), el vdom no ve diferencia y no repinta — y el
374
+ // usuario se queda mirando `12zz` en el campo.
375
+ if (el.value !== raw) {
376
+ // Reasignar `value` manda el caret al final: con `1234` y el caret en 2,
377
+ // tipear `z` lo mandaba al 4 y el siguiente caracter salía en otro lugar.
378
+ // La posición se recalcula contando cuántos caracteres SOBREVIVEN al
379
+ // escape por delante del caret.
380
+ const caretIn = (_a = el.selectionStart) !== null && _a !== void 0 ? _a : el.value.length;
381
+ const caretOut = Math.min(this.escapeHex(el.value.slice(0, caretIn)).length, raw.length);
382
+ el.value = raw;
383
+ (_b = el.setSelectionRange) === null || _b === void 0 ? void 0 : _b.call(el, caretOut, caretOut);
384
+ }
385
+ this.hexEditing = true;
386
+ this.hexDraft = raw;
387
+ if (isValidHex(raw))
388
+ this.previewHex(this.expandHex(raw));
389
+ };
390
+ this.handleHexBlur = () => {
391
+ this.finishHexEdit();
392
+ };
393
+ /** Enter cierra el gesto sin salir del campo (y no submitea ningún form). */
394
+ this.handleHexKeyDown = (e) => {
395
+ if (e.key !== 'Enter')
396
+ return;
397
+ e.preventDefault();
398
+ this.finishHexEdit();
399
+ };
400
+ /**
401
+ * Sin interceptar el pegado, el escape convierte `rgb(2, 99, 235)` en
402
+ * `299235` — basura silenciosa que ADEMÁS commitea sola, porque el `input` que
403
+ * sigue al pegado nativo ve 6 dígitos válidos.
404
+ *
405
+ * `parseCssColor` no cubre nombres CSS (ver color.ts): `rebeccapurple` escapa
406
+ * a `EBECCA`, un hex perfectamente válido que nadie eligió. Por eso lo que no
407
+ * es un color se CANCELA en vez de dejarse caer al escape; lo único que pasa
408
+ * de largo es un hex o el principio de uno, para poder pegar `02` y seguir
409
+ * tipeando.
410
+ */
411
+ this.handleHexPaste = (e) => {
412
+ var _a, _b;
413
+ if (this.disabled)
414
+ return;
415
+ const text = ((_b = (_a = e.clipboardData) === null || _a === void 0 ? void 0 : _a.getData('text')) !== null && _b !== void 0 ? _b : '').trim();
416
+ const parsed = parseCssColor(text);
417
+ if (parsed) {
418
+ e.preventDefault();
419
+ // Un pegado entrega un color COMPLETO en un acto atómico, como clickear
420
+ // un swatch: commitea al instante en vez de esperar al fin de gesto, y
421
+ // por lo mismo CIERRA cualquier edición de texto que estuviera abierta
422
+ // (si no, el blur posterior volvería a commitear lo mismo).
423
+ this.hexEditing = false;
424
+ this.hexDraft = this.escapeHex(parsed);
425
+ this.commit(parsed);
426
+ return;
427
+ }
428
+ if (!HEX_FRAGMENT.test(text))
429
+ e.preventDefault();
430
+ };
431
+ /**
432
+ * El cuentagotas entrega un color COMPLETO en un acto atómico, igual que un
433
+ * swatch o un pegado: entra por `commit` —no se duplica ni la asignación ni
434
+ * el emit— y se normaliza con `parseCssColor`, porque la API devuelve el hex
435
+ * en minúscula (`#ff0000`) y el resto del picker trabaja en mayúscula.
436
+ *
437
+ * ⚠️ `finishHexEdit` va PRIMERO y SÍNCRONO, antes del `await`: clickear otro
438
+ * control del panel es el fin del gesto del campo hex, y ese gesto puede
439
+ * durar lo que el usuario tarde en recorrer la pantalla. Sin esto, un texto a
440
+ * medias (`12`) se queda escrito y `hexEditing` colgado durante todo el
441
+ * cuentagotas, y si el usuario CANCELA nadie lo deshace: el preview vivo
442
+ * sobrevive a un gesto que no commiteó nada. Es el mismo cierre que hace el
443
+ * pegado, por la misma razón. Correrlo dos veces es inocuo (el blur real del
444
+ * navegador lo dispara también): la segunda pasada ve `hexEditing` en false y
445
+ * `value === committed`, y sale sin emitir.
446
+ */
447
+ this.handleEyeDropper = async () => {
448
+ this.finishHexEdit();
449
+ // El guard va DESPUÉS del cierre del gesto, y eso es lo único que tiene de
450
+ // interesante. `hasEyeDropper` no es reactivo: la presencia del botón se
451
+ // decide en el render y nunca se re-evalúa, así que existe el camino "API
452
+ // presente al renderizar, ausente al clickear" — el botón sigue en el DOM.
453
+ // Con el guard ADELANTE, ese click no hacía nada Y dejaba la edición del
454
+ // hex abierta: un control visible que se comporta distinto a todos sus
455
+ // hermanos del panel. Acá abajo el camino raro cierra el gesto igual que
456
+ // los demás y sólo se saltea el cuentagotas.
457
+ //
458
+ // Puesto así el guard ya no cambia nada observable —sin él, `new Ctor()`
459
+ // tira un TypeError que el `catch` atrapa y el estado queda idéntico—, y
460
+ // por eso ningún test lo distingue. Se queda por ser explícito sobre una
461
+ // precondición, no por un caso que lo necesite.
462
+ if (!this.hasEyeDropper)
463
+ return;
464
+ try {
465
+ const Ctor = window.EyeDropper;
466
+ const { sRGBHex } = await new Ctor().open();
467
+ const hex = parseCssColor(sRGBHex);
468
+ // Lo que no es un color no se commitea: el picker no inventa negro.
469
+ if (hex)
470
+ this.commit(hex);
471
+ }
472
+ catch (_a) {
473
+ /* El usuario canceló con Escape: no es un error que valga reportar. */
474
+ }
475
+ };
476
+ }
477
+ /**
478
+ * Un valor entrante que YA es el que acabamos de emitir se descarta.
479
+ *
480
+ * Sin esto, un host controlado (el que guarda lo emitido y lo devuelve por la
481
+ * prop) reinyecta el hex derivado, que se re-convierte a HSV con otro
482
+ * redondeo y mueve el cursor solo en pleno arrastre. La comparación es
483
+ * case-insensitive porque el host normaliza el string —guardar en minúsculas
484
+ * es lo habitual— y el mismo color escrito distinto no es un cambio.
485
+ */
486
+ syncFromValue(next) {
487
+ // El campo hex espeja el valor por esta vía ÚNICA, ANTES del guard: todo
488
+ // camino que cambia el color pasa por acá (el arrastre y el commit escriben
489
+ // `value`, y el host también). Si el espejo viviera después del guard, el
490
+ // campo quedaría congelado en el color anterior justo en el caso más común
491
+ // —arrastrar el área—, porque ese camino sella el caché antes de asignar.
492
+ this.syncHexDraft(next);
493
+ if ((next || '').toUpperCase() === (this.emitted || '').toUpperCase())
494
+ return;
495
+ // Un valor que llega de afuera ES la verdad del host, PARSEE O NO: pasa a
496
+ // ser la línea de base a la que vuelve un gesto que termina sin commitear.
497
+ //
498
+ // ⛔ Va ANTES del guard de parseo, y eso es lo único que separa esto de un
499
+ // bug de pérdida de datos: si el host BORRA el color (`value = ''`) o pone
500
+ // algo que no es un hex (`var(--co-brand)`), con la línea abajo `committed`
501
+ // se quedaba en el color VIEJO — y como el cierre del panel deshace todo
502
+ // preview colgado, abrir y cerrar sin tocar nada le devolvía al host el
503
+ // color que acababa de borrar, por `value` y por `coInput`.
504
+ //
505
+ // Y va DESPUÉS del guard de `emitted`, que es igual de deliberado: un host
506
+ // controlado que espeja `coInput` de vuelta a la prop nos devuelve nuestro
507
+ // propio preview, y tomar eso por un commit del host haría irreversible
508
+ // justo lo que este mecanismo existe para revertir.
509
+ this.committed = next;
510
+ // `emitted` se sella acá arriba por la misma razón, y también está medido:
511
+ // gateado por el parseo, un host que PASA por un valor no-hex y vuelve a un
512
+ // color que ya habíamos tenido lo dejaba stale apuntando a ese color, el
513
+ // guard de arriba tomaba el regreso por eco propio, `committed` no se
514
+ // actualizaba y el cierre del panel reemplazaba el color del host por el
515
+ // valor intermedio. Sellar lo que el host escribió —parsee o no— es además
516
+ // lo que el guard significa: "esto ya lo tenemos, no hay nada que
517
+ // re-derivar", que de un valor no parseable es trivialmente cierto.
518
+ this.emitted = next;
519
+ const parsed = hexToHsv(next || '');
520
+ // Un hex inválido no se convierte en un color: se ignora y el estado
521
+ // anterior sobrevive (el picker no tiene por qué inventar negro).
522
+ if (!parsed)
523
+ return;
524
+ this.hsv = parsed;
525
+ }
526
+ /**
527
+ * Siembra del estado. Es OBLIGATORIA acá, no basta el initializer del campo:
528
+ * - los @Watch no corren para el valor inicial de la prop;
529
+ * - el initializer de un miembro DECORADO no sobrevive en el entorno de spec
530
+ * (@stencil/vitest define el accessor encima del campo ya inicializado, así
531
+ * que `this.hsv` llega `undefined` al primer render y el destructuring de
532
+ * `renderArea` tira). Los otros @State del componente lo toleraban porque
533
+ * `undefined` es falsy justo donde se usan.
534
+ * Sin hex válido el estado arranca en negro, que es lo que pinta el área
535
+ * mientras no hay color elegido.
536
+ */
537
+ componentWillLoad() {
538
+ const parsed = hexToHsv(this.value || '');
539
+ this.hsv = parsed !== null && parsed !== void 0 ? parsed : EMPTY_HSV;
540
+ // Mismo motivo que `hsv`: el tab stop del área arranca en la saturación.
541
+ this.areaAxis = 's';
542
+ // El campo hex arranca del VALOR, no del seed del área.
543
+ //
544
+ // Es una siembra DEFENSIVA, y conviene decirlo con precisión porque el
545
+ // comentario anterior mentía: quitarla no pinta `FF0000` en ningún frame
546
+ // —`hexDraft` se queda en su initializer `''`—, y midiendo el shadow DOM
547
+ // cada 5ms desde el keydown del trigger, el input ya nace con el valor
548
+ // correcto porque `coOpen` (y con él `resetHexDraft`) llega ANTES de que el
549
+ // panel sea alcanzable. O sea: la re-siembra del popover le gana la carrera
550
+ // en todo entorno medido, y por eso ningún test la distingue. Se queda
551
+ // igual —sembrar en el load es correcto por construcción y no cuesta nada—,
552
+ // pero como cobertura no vale nada.
553
+ this.resetHexDraft();
554
+ // ⛔ NINGUNO de los dos sellos va detrás de `if (parsed)`, y no es simetría:
555
+ // cada uno abre su propia puerta al mismo bug de pérdida de datos, porque en
556
+ // Stencil el @Watch NO corre para el valor inicial y este es el único lugar
557
+ // donde se pueden sembrar.
558
+ //
559
+ // · `committed` es la línea de base del deshacer. Gateado, un `value`
560
+ // inicial que no parsea (`var(--co-brand)`, un nombre CSS) lo dejaba en
561
+ // `''`, y como el cierre del panel deshace todo preview colgado, abrir y
562
+ // cerrar SIN TOCAR NADA le borraba el valor al host y se lo anunciaba por
563
+ // `coInput`. Es el mismo razonamiento que el del @Watch, con el síntoma
564
+ // invertido: allá resucitaba el color viejo, acá borra el nuevo, porque
565
+ // el initializer es `''` en vez de un hex.
566
+ //
567
+ // · `emitted` es el caché anti-drift, no la línea de base — pero gatearlo
568
+ // abre la MISMA pérdida por composición, y está medido: con `committed`
569
+ // ya arreglado y `emitted` en `''`, un host que BORRA el color escribe
570
+ // justo el `''` que el guard toma por "esto ya lo emitimos nosotros",
571
+ // corta antes de actualizar `committed`, y el cierre del panel le
572
+ // devuelve el token que acababa de borrar. Sembrarlo con el valor inicial
573
+ // además es lo correcto por definición: el guard existe para saltear la
574
+ // re-derivación de un valor que ya tenemos, y al montar `value` ES lo que
575
+ // tenemos (`componentWillLoad` acaba de derivarlo).
576
+ this.committed = this.value;
577
+ this.emitted = this.value;
578
+ }
579
+ /**
580
+ * Movimiento en vivo: actualiza la UI y avisa, sin commitear.
581
+ *
582
+ * ⚠️ El caché se sella ANTES de tocar `this.value`: el setter de una @Prop
583
+ * corre sus @Watch de forma SÍNCRONA, así que con el caché todavía en el
584
+ * color anterior `syncFromValue` vería un color "nuevo", re-parsearía el hex
585
+ * y pisaría este HSV flotante con el redondeado — el temblor, en el mismo
586
+ * frame y sin que el host haya hecho nada. Guard: area.spec.
587
+ */
588
+ previewHsv(next) {
589
+ this.hsv = Object.assign(Object.assign({}, this.hsv), next);
590
+ this.emitPreview(hsvToHex(this.hsv));
591
+ }
592
+ /**
593
+ * Lo mismo, pero entrando por un hex ENTERO en vez de por un eje: es lo que
594
+ * produce el campo de texto, donde el color no llega como "más saturación"
595
+ * sino como un color completo. Comparte el sellado con `previewHsv` para que
596
+ * el orden crítico (sellar → asignar → avisar) exista en UN solo lugar.
597
+ */
598
+ previewHex(hex) {
599
+ const parsed = hexToHsv(hex);
600
+ if (parsed)
601
+ this.hsv = parsed;
602
+ this.emitPreview(hex);
603
+ }
604
+ emitPreview(hex) {
605
+ this.emitted = hex;
606
+ this.value = hex;
607
+ this.coInput.emit(hex);
608
+ }
609
+ /**
610
+ * Commit: lo que los consumidores ya escuchan hoy (soltar el arrastre,
611
+ * clickear un swatch).
612
+ *
613
+ * El HSV se re-deriva SÓLO si el hex viene de afuera —un swatch, un hex
614
+ * tipeado—, y eso se detecta preguntándole al propio estado si ese hex es el
615
+ * que produce. Re-derivar siempre tiene dos daños:
616
+ *
617
+ * 1. 🔴 En un color ACROMÁTICO el hex no lleva matiz: `#000000` es negro y
618
+ * punto, así que `hexToHsv` devuelve h=0 (rojo) y le BORRA al usuario el
619
+ * matiz que acababa de elegir. Con el campo vacío —el estado inicial de
620
+ * tres consumidores de suite-v2— el área se ponía azul al arrastrar el
621
+ * matiz y volvía a roja al soltar.
622
+ * 2. En un color cromático no lo borra pero lo REDONDEA (200 → 199.875):
623
+ * el estado interno pasando por la grilla del hex es justo lo que esta
624
+ * task existe para evitar.
625
+ */
626
+ commit(hex) {
627
+ if (hsvToHex(this.hsv) !== hex) {
628
+ const parsed = hexToHsv(hex);
629
+ if (parsed)
630
+ this.hsv = parsed;
631
+ }
632
+ this.emitted = hex;
633
+ this.committed = hex;
634
+ this.value = hex;
635
+ this.coChange.emit(hex);
636
+ }
637
+ get strings() {
638
+ return getColorPickerStrings(this.locale);
55
639
  }
56
640
  get parsedPresets() {
57
641
  if (Array.isArray(this.presets)) {
58
- return this.presets.map(p => typeof p === 'string' ? { name: p, value: p } : p);
642
+ return this.presets.map(resolvePreset);
59
643
  }
60
644
  if (typeof this.presets === 'string' && this.presets.trim()) {
61
645
  try {
62
646
  const parsed = JSON.parse(this.presets);
63
647
  if (Array.isArray(parsed)) {
64
- return parsed.map((p) => typeof p === 'string' ? { name: p, value: p } : p);
648
+ return parsed.map((p) => resolvePreset(p));
65
649
  }
66
650
  }
67
651
  catch ( /* ignore */_a) { /* ignore */ }
68
652
  }
69
653
  return DEFAULT_PRESETS;
70
654
  }
655
+ /**
656
+ * Los grupos EN EL ORDEN EN QUE SE RENDERIZAN, cada uno con el índice plano
657
+ * de su primer swatch (`from`). La navegación por flechas se indexa contra
658
+ * este aplanado, no contra `parsedPresets`: si el orden del render y el del
659
+ * array divergieran, una flecha movería el foco a otro swatch.
660
+ *
661
+ * La frontera neutros/marca sale de `NEUTRAL_PRESET_KEYS` — la única fuente
662
+ * de la paleta. Nada de `slice(0, 5)`: ese `5` ya estaba duplicado en tres
663
+ * lugares y es lo que la task anterior vino a eliminar.
664
+ */
665
+ get presetGroups() {
666
+ const presets = this.parsedPresets;
667
+ // La partición sale de la MEMBRESÍA de `key` (`splitPaletteGroups`), no de
668
+ // comparar identidad contra `DEFAULT_PRESETS`: el consumidor real manda la
669
+ // misma paleta re-serializada con los nombres traducidos, y por identidad
670
+ // eso caía siempre en "custom" — los rótulos no se anunciaban nunca.
671
+ const split = splitPaletteGroups(presets);
672
+ // Sin partición que signifique algo (hexes sueltos, keys desconocidas, un
673
+ // solo lado) va todo en un grupo, sin rótulo inventado.
674
+ if (!split) {
675
+ return [{ label: undefined, items: presets, from: 0 }];
676
+ }
677
+ return [
678
+ { label: this.strings.groupNeutrals, items: split.neutrals, from: 0 },
679
+ { label: this.strings.groupBrand, items: split.brand, from: split.neutrals.length },
680
+ ];
681
+ }
682
+ /** Los swatches aplanados en orden de render: la lista que recorren las flechas. */
683
+ get flatPresets() {
684
+ return flattenGroups(this.presetGroups);
685
+ }
71
686
  /** Devuelve el foco al trigger al cerrar el panel (Escape, selección),
72
687
  * salvo que el cierre venga de un click-outside que ya movió el foco a
73
688
  * otro elemento — en ese caso no robarlo. */
@@ -79,11 +694,120 @@ export class CoColorPicker {
79
694
  }
80
695
  }
81
696
  handleSwatchClick(hex) {
82
- this.value = hex;
83
- this.coChange.emit(hex);
697
+ // Elegir un preset es un commit como cualquier otro: la asignación y el
698
+ // emit viven en `commit`, no duplicados acá (si no, el swatch dejaría el
699
+ // HSV del color anterior y el área abriría en el color equivocado).
700
+ this.commit(hex);
84
701
  this.isOpen = false;
85
702
  this.restoreTriggerFocus();
86
703
  }
704
+ /** Mueve el tab stop del área (y el foco) al eje pedido. */
705
+ focusAxis(axis) {
706
+ this.areaAxis = axis;
707
+ const el = axis === 's' ? this.satEl : this.valEl;
708
+ if (!el)
709
+ return;
710
+ // El render de Stencil es ASÍNCRONO: enfocar mientras el input todavía
711
+ // tiene `aria-hidden` puede hacer que el lector de pantalla se coma el
712
+ // anuncio (el nodo no está en el árbol en el instante del evento), y un
713
+ // frame después no hay ningún evento nuevo que lo dispare. Se sincroniza a
714
+ // mano y el próximo render converge al mismo valor. Guard: area.spec.
715
+ //
716
+ // El `tabindex` NO hace falta tocarlo: `focus()` entra igual en un
717
+ // `tabindex=-1` —es exactamente lo que hace operable al eje oculto— y el
718
+ // tab order se corrige en el render, dentro del mismo frame.
719
+ el.removeAttribute('aria-hidden');
720
+ el.focus();
721
+ }
722
+ optionEls() {
723
+ var _a, _b;
724
+ // `Array.from`, NO spread: el build de Stencil tipa con `lib: ["dom","es2020"]`
725
+ // SIN `dom.iterable`, así que spreadear un NodeList no compila (y `tsc --noEmit`
726
+ // con este tsconfig no lo detecta — sólo revienta en `stencil build`).
727
+ return Array.from((_b = (_a = this.gridEl) === null || _a === void 0 ? void 0 : _a.querySelectorAll('[role="option"]')) !== null && _b !== void 0 ? _b : []);
728
+ }
729
+ /**
730
+ * Vecino de arriba/abajo EN PANTALLA.
731
+ *
732
+ * La grilla no es una matriz única: son N grillas de 6 columnas apiladas, una
733
+ * por grupo, y la de neutros tiene 5 celdas. Por eso un stride plano de ±6
734
+ * sobre el índice global se corre una columna al cruzar la frontera (Black,
735
+ * columna 0, caía en Olive, columna 1). Fila y columna se calculan DENTRO del
736
+ * grupo; al cruzar al grupo vecino se conserva la columna, que es lo que
737
+ * "fila anterior / siguiente" significa visualmente.
738
+ *
739
+ * En el borde de la grilla el foco NO se mueve: colapsarlo al extremo mandaba
740
+ * cualquier neutro de la primera fila a Black.
741
+ *
742
+ * Asimetría DELIBERADA con las flechas horizontales, que sí wrappean (0↔16):
743
+ * el wrap cíclico en un eje y el tope duro en el otro es lo que hace APG para
744
+ * grillas, y es lo que deja claro dónde termina la paleta.
745
+ */
746
+ verticalNeighbor(groups, current, dir) {
747
+ const gi = groups.findIndex((g) => current >= g.from && current < g.from + g.items.length);
748
+ if (gi < 0)
749
+ return current;
750
+ const g = groups[gi];
751
+ const j = current - g.from;
752
+ const col = j % GRID_COLS;
753
+ const rows = Math.ceil(g.items.length / GRID_COLS);
754
+ const targetRow = Math.floor(j / GRID_COLS) + dir;
755
+ // Hay fila dentro del MISMO grupo. La última puede estar incompleta.
756
+ if (targetRow >= 0 && targetRow < rows) {
757
+ return g.from + Math.min(targetRow * GRID_COLS + col, g.items.length - 1);
758
+ }
759
+ const neighbor = groups[gi + dir];
760
+ if (!neighbor)
761
+ return current;
762
+ // Entrando desde arriba se aterriza en la primera fila; desde abajo, en la última.
763
+ const nRows = Math.ceil(neighbor.items.length / GRID_COLS) || 1;
764
+ const landingRow = dir === 1 ? 0 : nRows - 1;
765
+ return neighbor.from + Math.min(landingRow * GRID_COLS + col, neighbor.items.length - 1);
766
+ }
767
+ /**
768
+ * El área saturación×brillo.
769
+ *
770
+ * Es un `role="group"` con UN `<input type="range">` invisible por eje —el
771
+ * modelo de React Aria—, en vez de un `role="slider"` 2D a mano: así el eje
772
+ * lo maneja un control nativo (teclado, repetición de tecla, anuncio del
773
+ * lector de pantalla) y sólo el arrastre queda de nuestro lado.
774
+ *
775
+ * El matiz viaja al CSS por custom property: el gradiente es CSS puro, sin
776
+ * canvas y sin un hex literal en la hoja de estilos.
777
+ */
778
+ renderArea() {
779
+ const { h: hue, s, v } = this.hsv;
780
+ // El eje enfocado es el único con tab stop y el único anunciado.
781
+ const satFocused = this.areaAxis === 's';
782
+ return (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 }, h("span", { class: "co-color-picker__area-thumb", role: "presentation", style: { left: `${s}%`, top: `${100 - v}%`, background: this.value } }), 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": 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(hsvToHex(this.hsv)), onKeyDown: this.handleAreaKeyDown }), 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": 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(hsvToHex(this.hsv)), onKeyDown: this.handleAreaKeyDown })));
783
+ }
784
+ renderHue() {
785
+ return (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": fillTemplate(this.strings.hueValue, { n: Math.round(this.hsv.h) }), disabled: this.disabled, onInput: (e) => this.previewHsv({ h: +e.target.value }), onChange: () => this.commit(hsvToHex(this.hsv)), onKeyDown: this.handleHueKeyDown }));
786
+ }
787
+ renderSwatches() {
788
+ return (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) => (
789
+ // Agrupación SÓLO para lectores de pantalla: en pantalla los separa el
790
+ // gap, sin rótulos (costaban ~56px y no aportaban — spec §4).
791
+ // `key` por el índice plano de arranque (0 / 5), NO por el rótulo:
792
+ // el rótulo cambia con `locale` y remontaría los grupos al traducir.
793
+ //
794
+ // Sin rótulo el contenedor es PRESENTACIONAL: un `role="group"`
795
+ // anónimo particiona el listbox para el lector de pantalla anunciando
796
+ // una frontera que no significa nada. El div igual tiene que existir
797
+ // —es el que da las 6 columnas—, así que `presentation` lo saca del
798
+ // árbol de accesibilidad y las opciones quedan colgando del listbox.
799
+ 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) => {
800
+ const i = g.from + j;
801
+ const selected = preset.value.toUpperCase() === (this.value || '').toUpperCase();
802
+ return (h("div", { key: preset.value, role: "option", "aria-selected": selected ? 'true' : 'false', "aria-label": preset.name, tabIndex: i === this.focusedIndex ? 0 : -1, class: {
803
+ 'co-color-picker__grid-item': true,
804
+ 'co-color-picker__grid-item--selected': selected,
805
+ // Un swatch claro se pierde contra el panel: se decide por
806
+ // luminancia, no por una lista de hex hardcodeada.
807
+ 'co-color-picker__grid-item--light': isLightColor(preset.value),
808
+ }, style: { background: preset.value }, onFocus: () => (this.focusedIndex = i), onClick: () => this.handleSwatchClick(preset.value) }, selected && (h("co-icon", { name: "check", size: 16, weight: "bold", class: "co-color-picker__grid-check" }))));
809
+ }))))));
810
+ }
87
811
  get statusIcon() {
88
812
  const map = {
89
813
  error: 'warning-circle',
@@ -92,6 +816,142 @@ export class CoColorPicker {
92
816
  };
93
817
  return map[this.status] || null;
94
818
  }
819
+ /**
820
+ * Lo que se puede TIPEAR en el campo: dígitos hex, hasta 6. El 7º caracter y
821
+ * el `#` no entran, y con 8 dígitos (hex con alpha) se queda con los 6 de
822
+ * color — este picker no maneja alpha.
823
+ */
824
+ escapeHex(v) {
825
+ return (v || '').replace(/[^0-9a-f]/gi, '').substring(0, 6).toUpperCase();
826
+ }
827
+ /** `F00` → `#FF0000`: lo emitido es SIEMPRE de 6 dígitos. */
828
+ expandHex(v) {
829
+ const hx = v.replace('#', '');
830
+ const full = hx.length === 3 ? hx[0] + hx[0] + hx[1] + hx[1] + hx[2] + hx[2] : hx;
831
+ return `#${full.toUpperCase()}`;
832
+ }
833
+ /**
834
+ * Siembra el campo desde el valor REAL y cierra cualquier edición abierta.
835
+ *
836
+ * Con `value` vacío queda vacío: el estado interno arranca en EMPTY_HSV (rojo
837
+ * puro) para que el área tenga de dónde partir, pero eso es un seed de
838
+ * DISPLAY del área — espejarlo pondría `FF0000` escrito en un campo que el
839
+ * usuario nunca tocó, anunciando un color que nadie eligió.
840
+ */
841
+ resetHexDraft() {
842
+ // Apagar la edición va PRIMERO y es lo que hace incondicional a la
843
+ // siembra: `syncHexDraft` se abstiene mientras el flag esté prendido, así
844
+ // que sin esto un flag colgado dejaría la re-siembra en no-op.
845
+ //
846
+ // Hoy es defensivo y conviene decirlo: `finishHexEdit` —que corre en todo
847
+ // cierre de panel— ya apaga el flag antes de cualquier otra cosa, así que
848
+ // ningún test lo distingue. Se queda porque es la precondición de la línea
849
+ // de abajo, no por un caso conocido que lo necesite.
850
+ this.hexEditing = false;
851
+ this.syncHexDraft(this.value);
852
+ }
853
+ /**
854
+ * Espeja el valor real en el campo, salvo mientras el usuario lo está
855
+ * tipeando.
856
+ *
857
+ * Sólo espeja lo que YA es un color (o el vacío, que limpia). `escapeHex`
858
+ * sobre cualquier otra cosa fabrica un hex verosímil: un host que pase
859
+ * `rebeccapurple` o `var(--co-color-primary-verde)` vería el campo mostrando
860
+ * `EBECCA` / `ACCAED`. Es exactamente la falla que el pegado cancela unas
861
+ * líneas más abajo, y entraba igual por la puerta de la prop. Los frames de
862
+ * arrastre siempre escriben un hex de 6, así que no se pierde nada legítimo.
863
+ */
864
+ syncHexDraft(hex) {
865
+ if (this.hexEditing)
866
+ return;
867
+ if (hex && !isValidHex(hex))
868
+ return;
869
+ this.hexDraft = this.escapeHex(hex);
870
+ }
871
+ /**
872
+ * Fin del gesto del campo: blur, Enter, o el cierre del panel.
873
+ *
874
+ * Commitea SIEMPRE que haya un color tipeado, sin comparar contra `value`
875
+ * —que a esta altura ya vale el color previsualizado, así que "commitear si
876
+ * cambió" no dispararía nunca—. Es el precedente del `pointerup` del área: el
877
+ * fin de gesto commitea, y si el usuario retipeó el mismo color, el `coChange`
878
+ * redundante es el precio.
879
+ *
880
+ * ⚠️ Consecuencia documentada de esa regla: tipear un hex válido y después
881
+ * clickear un swatch emite DOS `coChange` — el blur commitea el color
882
+ * tipeado, y el swatch el suyo. Es el precio explícito de que el fin de gesto
883
+ * no adivine intenciones, no un bug.
884
+ *
885
+ * Y si no hay nada que commitear, se DESHACE el preview vivo. Eso cubre dos
886
+ * casos con el mismo movimiento: el texto que quedó a medias (`12`), y el
887
+ * arrastre abortado —que emitía `coInput`, escribía `value` y no commiteaba
888
+ * nunca, dejando al picker mostrando un color que el host jamás recibió—.
889
+ */
890
+ finishHexEdit() {
891
+ const editing = this.hexEditing;
892
+ this.hexEditing = false;
893
+ // Un picker deshabilitado no emite ni escribe, ni siquiera para deshacer:
894
+ // si el host lo apagó con un preview colgado, el `value` es asunto suyo.
895
+ if (this.disabled)
896
+ return;
897
+ if (editing && isValidHex(this.hexDraft)) {
898
+ const hex = this.expandHex(this.hexDraft);
899
+ this.commit(hex);
900
+ // El espejo se hace acá a mano porque el @Watch NO dispara: `commit`
901
+ // reasigna a `value` el mismo hex que el preview ya había escrito, y
902
+ // Stencil no corre el watcher cuando el valor no cambió. Sin esto, tipear
903
+ // `F00` deja el campo mostrando `F00` mientras el color real ya es
904
+ // `#FF0000` — el texto y el trigger diciendo cosas distintas.
905
+ this.syncHexDraft(hex);
906
+ return;
907
+ }
908
+ this.revertToCommitted();
909
+ }
910
+ /** Vuelve al último color commiteado y retira el preview que quedó colgado. */
911
+ revertToCommitted() {
912
+ const target = this.committed;
913
+ // Por `syncHexDraft` y no por `escapeHex` a pelo: `committed` puede no ser
914
+ // un hex (el host puede haber puesto `var(--co-brand)`), y escaparlo
915
+ // fabricaría el mismo `ACBAD` verosímil que el guard de allá evita.
916
+ this.syncHexDraft(target);
917
+ // Volver a "sin color" devuelve el área a su vértice vivo. Si el gesto
918
+ // abandonado terminó con `v=0`, reabrir dejaba el campo vacío Y el área en
919
+ // negro, donde mover matiz o saturación no produce color alguno: es
920
+ // exactamente el estado que EMPTY_HSV existe para evitar.
921
+ if (!target)
922
+ this.hsv = EMPTY_HSV;
923
+ if ((this.value || '').toUpperCase() === (target || '').toUpperCase())
924
+ return;
925
+ // SIN sellar: acá el @Watch sí tiene que re-derivar el HSV, para que el área
926
+ // vuelva al color commiteado y no se quede en el que se abandonó.
927
+ this.value = target;
928
+ // El @Watch no sella cuando `target` no es un hex (nunca se commiteó nada y
929
+ // el campo vuelve a vacío), así que se sella acá.
930
+ this.emitted = target;
931
+ // El preview se anunció por `coInput`; retirarlo también. Un host que
932
+ // previsualiza en vivo se quedaría si no con el color que nadie eligió.
933
+ this.coInput.emit(target);
934
+ }
935
+ /**
936
+ * Chrome/Edge 95+ solamente (MDN, 2026-09-02): Firefox, Safari y Chrome
937
+ * Android no la tienen. Se resuelve en el render, no en una prop: si no está,
938
+ * el botón no existe. Un control deshabilitado sin explicar es peor que su
939
+ * ausencia — y una prop obligaría a cada host a repetir la detección.
940
+ *
941
+ * El `typeof window` es por el build de hydrate, donde no hay `window` y el
942
+ * `in` tiraría.
943
+ */
944
+ get hasEyeDropper() {
945
+ return typeof window !== 'undefined' && 'EyeDropper' in window;
946
+ }
947
+ renderHexRow() {
948
+ const hasValue = !!this.value;
949
+ return (h("div", { class: "co-color-picker__hex-row" }, h("span", { class: "co-color-picker__hex-prefix" }, "#"), 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 && (h("button", { type: "button", class: "co-color-picker__eyedropper", title: this.strings.eyedropper, "aria-label": this.strings.eyedropper, disabled: this.disabled, onClick: this.handleEyeDropper }, h("co-icon", { name: "eyedropper", size: 16 }))), 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,
950
+ // La fila ya no está detrás de `hasValue` —hay que poder tipear el
951
+ // primer color—, así que el que se apaga es el botón: sin valor no
952
+ // hay nada que copiar.
953
+ disabled: this.disabled || !hasValue, onClick: () => this.handleCopy() }, h("co-icon", { name: this.copied ? 'check' : 'copy', size: 16 }))));
954
+ }
95
955
  async handleCopy() {
96
956
  if (!this.value)
97
957
  return;
@@ -103,13 +963,14 @@ export class CoColorPicker {
103
963
  catch ( /* ignore */_a) { /* ignore */ }
104
964
  }
105
965
  render() {
106
- const presets = this.parsedPresets;
107
966
  const hasValue = !!this.value;
108
967
  const statusClass = this.status !== 'default' ? `co-color-picker--${this.status}` : '';
109
- return (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 && (h("label", { key: '816392c0b3cebcb2e84ea28ea7e6b7976503b6f9', class: "co-color-picker__label" }, this.label, h(RequiredMark, { key: 'e0e1c97522f4516763fc663878203e2dafb783b3', required: this.required }))), h("co-popover", { key: 'd49ba1f9cd64d2498940247f3ba02897dcc9d2d7', open: this.isOpen, placement: "bottom-start", matchWidth: true, offset: 4, onCoOpen: this.handlePopoverOpen, onCoClose: this.handlePopoverClose }, 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 }, h("span", { key: '2567db35022b5ffdd9921d8bec263c90103fd5f3', class: "co-color-picker__swatch", style: { background: hasValue ? this.value : 'transparent' } }), h("span", { key: '7fecc93b5ecc91acf2c874a26ed1f9d8770d9adf', class: `co-color-picker__value ${!hasValue ? 'co-color-picker__value--empty' : ''}` }, hasValue ? this.value : this.placeholder)), this.isOpen && (h("div", { key: '44d904e4156fac15b302ffe86d68cef72bc7518e', class: "co-color-picker__panel", id: CoColorPicker.PANEL_ID, role: "dialog", "aria-label": this.label || this.placeholder }, h("div", { key: 'a566f189c87792f0af3e493c00eed7240dcd49c9', class: "co-color-picker__grid" }, presets.map((preset) => {
110
- var _a;
111
- return (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) }));
112
- })), hasValue && (h("div", { key: 'bae8ffe387fe30710b654975379e70a4b3724ec9', class: "co-color-picker__hex-row" }, h("span", { key: '671a5a64abc2f824c8d1ef8c2404023d8d51c28d', class: "co-color-picker__hex-prefix" }, "#"), h("span", { key: '3a6742eb528c5a92fe16b2f2e5d8b2ebdf885450', class: "co-color-picker__hex-value" }, this.value.replace(/^#/, '')), 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() }, h("co-icon", { key: 'c99e611beddc2108f3973ecee4f6012423cffd23', name: this.copied ? 'check' : 'copy', size: 16 }))))))), this.helperText && (h("div", { key: '1d6a6e97eab1eafcb9265944693cb0d1121e04ee', class: "co-color-picker__helper" }, this.statusIcon && (h("co-icon", { key: 'bcf943836fddf264cede2f339844f35aa167002f', name: this.statusIcon, size: 14, weight: "fill", class: "co-color-picker__helper-icon" })), h("span", { key: 'a439c4d102d17d0d6c9e55757dcf43ec8b3ade8f', class: "co-color-picker__helper-text" }, this.helperText)))));
968
+ return (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 && (h("label", { key: 'e28d265aefc19f7e86ed36bfbfe6b6ec537d1ca2', class: "co-color-picker__label" }, this.label, h(RequiredMark, { key: '0aff2dde3002e1c9a79f2c3a385b64d33dc3418c', required: this.required }))), h("co-popover", { key: 'edac2d09e0d15c2f09dfff2ea0a2b95f5384d8de', open: this.isOpen, placement: "bottom-start",
969
+ // Sin `matchWidth`: el panel tiene ancho INTRÍNSECO (grilla de 8
970
+ // swatches fijos de 32px). Copiar el ancho del trigger achica los
971
+ // tracks bajo 32px con un campo angosto (media columna de un modal) y
972
+ // los swatches desbordan el card — guard: panel-width.spec.
973
+ offset: 4, onCoOpen: this.handlePopoverOpen, onCoClose: this.handlePopoverClose }, 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 }, h("span", { key: '65e49a6246c71b6366f7907c715c64259c30be46', class: "co-color-picker__swatch", style: { background: hasValue ? this.value : 'transparent' } }), h("span", { key: 'd8e6e852383ec925c4336f9b49a69e73d88e2234', class: `co-color-picker__value ${!hasValue ? 'co-color-picker__value--empty' : ''}` }, hasValue ? this.value : this.placeholder)), this.isOpen && (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 && (h("div", { key: 'ca583c8033afaafa5bdd59ccd63e711eaf02e6df', class: "co-color-picker__helper" }, this.statusIcon && (h("co-icon", { key: 'aca2fd8186658e7d4e13ab67dc7a6e93c2fd8b89', name: this.statusIcon, size: 14, weight: "fill", class: "co-color-picker__helper-icon" })), h("span", { key: 'e8e3cdf72353a1f5fb8b53fe725389386c7d75ea', class: "co-color-picker__helper-text" }, this.helperText)))));
113
974
  }
114
975
  static get is() { return "co-color-picker"; }
115
976
  static get encapsulation() { return "shadow"; }
@@ -348,13 +1209,37 @@ export class CoColorPicker {
348
1209
  "reflect": false,
349
1210
  "attribute": "presets",
350
1211
  "defaultValue": "''"
1212
+ },
1213
+ "locale": {
1214
+ "type": "string",
1215
+ "mutable": false,
1216
+ "complexType": {
1217
+ "original": "string",
1218
+ "resolved": "string",
1219
+ "references": {}
1220
+ },
1221
+ "required": false,
1222
+ "optional": false,
1223
+ "docs": {
1224
+ "tags": [],
1225
+ "text": "Idioma de los textos accesibles. Misma prop que co-file-field/co-date-picker."
1226
+ },
1227
+ "getter": false,
1228
+ "setter": false,
1229
+ "reflect": false,
1230
+ "attribute": "locale",
1231
+ "defaultValue": "'en'"
351
1232
  }
352
1233
  };
353
1234
  }
354
1235
  static get states() {
355
1236
  return {
356
1237
  "isOpen": {},
357
- "copied": {}
1238
+ "copied": {},
1239
+ "hsv": {},
1240
+ "hexDraft": {},
1241
+ "areaAxis": {},
1242
+ "focusedIndex": {}
358
1243
  };
359
1244
  }
360
1245
  static get events() {
@@ -373,9 +1258,30 @@ export class CoColorPicker {
373
1258
  "resolved": "string",
374
1259
  "references": {}
375
1260
  }
1261
+ }, {
1262
+ "method": "coInput",
1263
+ "name": "coInput",
1264
+ "bubbles": true,
1265
+ "cancelable": true,
1266
+ "composed": true,
1267
+ "docs": {
1268
+ "tags": [],
1269
+ "text": "Hex en vivo mientras se arrastra el \u00E1rea o el matiz. El host lo usa para\nprevisualizar si quiere.\n\nLa partici\u00F3n con `coChange` es el contrato nuevo y existe por una raz\u00F3n\nconcreta: un arrastre produce ~60 valores por segundo, y emitirlos todos\ncomo `coChange` ensucia la sesi\u00F3n del formulario en cada frame (un\n\"cambios sin guardar\" por p\u00EDxel movido). `coChange` sigue significando\nexactamente lo que significaba \u2014commit\u2014, as\u00ED que los consumidores actuales\nno cambian una l\u00EDnea."
1270
+ },
1271
+ "complexType": {
1272
+ "original": "string",
1273
+ "resolved": "string",
1274
+ "references": {}
1275
+ }
376
1276
  }];
377
1277
  }
378
1278
  static get elementRef() { return "el"; }
1279
+ static get watchers() {
1280
+ return [{
1281
+ "propName": "value",
1282
+ "methodName": "syncFromValue"
1283
+ }];
1284
+ }
379
1285
  }
380
1286
  /**
381
1287
  * Id del panel de presets, target de `aria-controls` del trigger. Constante
@@ -386,3 +1292,14 @@ export class CoColorPicker {
386
1292
  * on-demand, así que cerrado el IDREF quedaría colgante.
387
1293
  */
388
1294
  CoColorPicker.PANEL_ID = 'co-color-picker-panel';
1295
+ /**
1296
+ * Qué eje mueve cada flecha DENTRO del área, y en qué sentido. Un range
1297
+ * horizontal nativo también responde a ↑/↓ moviendo SU eje, así que sin esta
1298
+ * tabla (y su `preventDefault`) la flecha de arriba subía la saturación.
1299
+ */
1300
+ CoColorPicker.AREA_KEYS = {
1301
+ ArrowRight: { axis: 's', dir: 1 },
1302
+ ArrowLeft: { axis: 's', dir: -1 },
1303
+ ArrowUp: { axis: 'v', dir: 1 },
1304
+ ArrowDown: { axis: 'v', dir: -1 },
1305
+ };