@prolibu-suite/cobalt-core 0.9.5 → 0.10.0

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