@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.
- package/custom-elements.json +750 -80
- package/dist/cjs/co-accordion.cjs.entry.js +1 -1
- package/dist/cjs/co-action-bar.cjs.entry.js +1 -1
- package/dist/cjs/co-app-shell.cjs.entry.js +4 -4
- package/dist/cjs/co-audio-player.cjs.entry.js +1 -1
- package/dist/cjs/co-autocomplete.cjs.entry.js +2 -2
- package/dist/cjs/co-avatar-group.cjs.entry.js +1 -1
- package/dist/cjs/co-avatar_2.cjs.entry.js +49 -17
- package/dist/cjs/co-badge.cjs.entry.js +11 -3
- package/dist/cjs/co-bottom-sheet.cjs.entry.js +1 -1
- package/dist/cjs/co-breadcrumb-item.cjs.entry.js +1 -1
- package/dist/cjs/co-breadcrumb.cjs.entry.js +1 -1
- package/dist/cjs/co-button-group.cjs.entry.js +1 -1
- package/dist/cjs/co-button.cjs.entry.js +2 -2
- package/dist/cjs/co-calendar-month_2.cjs.entry.js +55 -20
- package/dist/cjs/co-calendar_3.cjs.entry.js +27 -15
- package/dist/cjs/co-card.cjs.entry.js +1 -1
- package/dist/cjs/co-carousel-item.cjs.entry.js +1 -1
- package/dist/cjs/co-carousel.cjs.entry.js +2 -2
- package/dist/cjs/co-checkbox-group.cjs.entry.js +2 -2
- package/dist/cjs/co-checkbox.cjs.entry.js +6 -6
- package/dist/cjs/co-chip_2.cjs.entry.js +8 -5
- package/dist/cjs/co-color-picker.cjs.entry.js +1048 -27
- package/dist/cjs/co-column-picker.cjs.entry.js +3 -3
- package/dist/cjs/co-combobox.cjs.entry.js +2 -2
- package/dist/cjs/co-command-search.cjs.entry.js +1 -1
- package/dist/cjs/co-data-table-pagination.cjs.entry.js +5 -5
- package/dist/cjs/co-data-table.cjs.entry.js +1 -1
- package/dist/cjs/co-date-picker.cjs.entry.js +3 -3
- package/dist/cjs/co-date-range-picker.cjs.entry.js +3 -3
- package/dist/cjs/co-date-range.cjs.entry.js +2 -2
- package/dist/cjs/co-date-time-picker.cjs.entry.js +101 -130
- package/dist/cjs/co-drive-card.cjs.entry.js +2 -2
- package/dist/cjs/co-drop-zone.cjs.entry.js +2 -2
- package/dist/cjs/co-emoji-picker.cjs.entry.js +4 -4
- package/dist/cjs/co-empty-state.cjs.entry.js +4 -4
- package/dist/cjs/co-event-calendar.cjs.entry.js +4 -4
- package/dist/cjs/co-event-popover.cjs.entry.js +3 -3
- package/dist/cjs/co-fab.cjs.entry.js +3 -3
- package/dist/cjs/co-file-field.cjs.entry.js +102 -106
- package/dist/cjs/co-file-type-tile.cjs.entry.js +3 -3
- package/dist/cjs/co-helper-text.cjs.entry.js +3 -3
- package/dist/cjs/co-icon-button.cjs.entry.js +6 -6
- package/dist/cjs/co-icon.cjs.entry.js +3 -3
- package/dist/cjs/co-input.cjs.entry.js +26 -4
- package/dist/cjs/co-json-field.cjs.entry.js +5 -5
- package/dist/cjs/co-lightbox.cjs.entry.js +204 -21
- package/dist/cjs/co-list-footer.cjs.entry.js +2 -2
- package/dist/cjs/co-list-item.cjs.entry.js +5 -5
- package/dist/cjs/co-loader.cjs.entry.js +1 -1
- package/dist/cjs/co-media-thumb.cjs.entry.js +3 -3
- package/dist/cjs/co-menu-divider.cjs.entry.js +2 -2
- package/dist/cjs/co-menu-item.cjs.entry.js +84 -3
- package/dist/cjs/co-menu.cjs.entry.js +2 -2
- package/dist/cjs/co-modal.cjs.entry.js +6 -4
- package/dist/cjs/co-navbar.cjs.entry.js +4 -4
- package/dist/cjs/co-number-field.cjs.entry.js +272 -9
- package/dist/cjs/co-overlay.cjs.entry.js +6 -4
- package/dist/cjs/co-page-header.cjs.entry.js +2 -2
- package/dist/cjs/co-phone-field.cjs.entry.js +3 -3
- package/dist/cjs/co-popover.cjs.entry.js +58 -21
- package/dist/cjs/co-progress-bar.cjs.entry.js +3 -3
- package/dist/cjs/co-progress-circle.cjs.entry.js +3 -3
- package/dist/cjs/co-provider-logo_2.cjs.entry.js +47 -3
- package/dist/cjs/co-radio-group.cjs.entry.js +1 -1
- package/dist/cjs/co-radio.cjs.entry.js +4 -4
- package/dist/cjs/co-rating.cjs.entry.js +4 -4
- package/dist/cjs/co-ref-field.cjs.entry.js +4 -4
- package/dist/cjs/co-rich-text-editor.cjs.entry.js +11 -8
- package/dist/cjs/co-rich-text-toolbar.cjs.entry.js +7 -3
- package/dist/cjs/co-rich-text-viewer.cjs.entry.js +4 -3
- package/dist/cjs/co-row.cjs.entry.js +3 -3
- package/dist/cjs/co-segmented-bar.cjs.entry.js +1 -1
- package/dist/cjs/co-select.cjs.entry.js +2 -2
- package/dist/cjs/co-separator.cjs.entry.js +2 -2
- package/dist/cjs/co-sidebar-nav.cjs.entry.js +2 -2
- package/dist/cjs/co-sidebar.cjs.entry.js +3 -3
- package/dist/cjs/co-slider.cjs.entry.js +3 -3
- package/dist/cjs/co-switch.cjs.entry.js +6 -6
- package/dist/cjs/co-tab-group.cjs.entry.js +3 -3
- package/dist/cjs/co-tab.cjs.entry.js +3 -3
- package/dist/cjs/co-tags-field.cjs.entry.js +8 -8
- package/dist/cjs/co-textarea.cjs.entry.js +6 -6
- package/dist/cjs/co-time-field.cjs.entry.js +325 -0
- package/dist/cjs/co-toast.cjs.entry.js +2 -2
- package/dist/cjs/co-toggle-button-group.cjs.entry.js +4 -4
- package/dist/cjs/co-toggle-button.cjs.entry.js +4 -4
- package/dist/cjs/co-transfer-list.cjs.entry.js +1 -1
- package/dist/cjs/co-video.cjs.entry.js +32 -7
- package/dist/cjs/cobalt.cjs.js +2 -2
- package/dist/cjs/color-CML2Cfdh.js +142 -0
- package/dist/cjs/{dateI18n-wblvKRq_.js → dateI18n-BK2qHqoC.js} +36 -0
- package/dist/cjs/{fieldChip-BLzo9MEV.js → fieldChip-B6YIGU1V.js} +1 -1
- package/dist/cjs/fileI18n-6sdbKvo6.js +88 -0
- package/dist/cjs/{index-DFZ5YhIT.js → index-BYwrR87Z.js} +28 -10
- package/dist/cjs/{index-DK-2Lzmf.js → index-MDAnKsze.js} +25 -21
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/cjs/{positioning-DCj_AJ2T.js → positioning-CyatXeT_.js} +32 -13
- package/dist/cjs/{requiredMark-C1xcrzSZ.js → requiredMark-D-t-IPN0.js} +1 -1
- package/dist/cjs/{toolbar-config-BQfWTW6P.js → toolbar-config-BSGas-Wl.js} +10 -0
- package/dist/cobalt/cobalt.css +1 -1
- package/dist/cobalt/cobalt.esm.js +1 -1
- package/dist/cobalt/{p-f83b48fd.entry.js → p-011dc80b.entry.js} +1 -1
- package/dist/cobalt/{p-316c62c0.entry.js → p-0678c797.entry.js} +1 -1
- package/dist/cobalt/{p-43bd298d.entry.js → p-08e42e00.entry.js} +1 -1
- package/dist/cobalt/{p-1c68bc41.entry.js → p-10b82207.entry.js} +1 -1
- package/dist/cobalt/{p-a8c64cc3.entry.js → p-15d59169.entry.js} +1 -1
- package/dist/cobalt/{p-07d570a6.entry.js → p-16954cea.entry.js} +1 -1
- package/dist/cobalt/{p-85a61e28.entry.js → p-17244412.entry.js} +1 -1
- package/dist/cobalt/p-1788aab5.entry.js +1 -0
- package/dist/cobalt/p-1a589c8e.entry.js +1 -0
- package/dist/cobalt/{p-da546d08.entry.js → p-1dc55e43.entry.js} +1 -1
- package/dist/cobalt/p-20a39218.entry.js +1 -0
- package/dist/cobalt/{p-4c7e3984.entry.js → p-23ab0cc5.entry.js} +1 -1
- package/dist/cobalt/{p-fabe5fb2.entry.js → p-2636b7eb.entry.js} +1 -1
- package/dist/cobalt/{p-88a0659f.entry.js → p-27a7e549.entry.js} +1 -1
- package/dist/cobalt/{p-18d34b01.entry.js → p-290066ef.entry.js} +1 -1
- package/dist/cobalt/{p-89e38c5e.entry.js → p-2f9cbbd5.entry.js} +1 -1
- package/dist/cobalt/{p-ef5e1167.entry.js → p-325b91b6.entry.js} +1 -1
- package/dist/cobalt/{p-60cb66f5.entry.js → p-37f5036b.entry.js} +1 -1
- package/dist/cobalt/p-3cc3ff93.entry.js +1 -0
- package/dist/cobalt/p-410bee4d.entry.js +1 -0
- package/dist/cobalt/{p-6795a258.entry.js → p-44c4e4a3.entry.js} +1 -1
- package/dist/cobalt/{p-4b083da4.entry.js → p-44ea675f.entry.js} +1 -1
- package/dist/cobalt/{p-2828ecf6.entry.js → p-4592ca00.entry.js} +1 -1
- package/dist/cobalt/p-4908f33f.entry.js +1 -0
- package/dist/cobalt/{p-342e1da4.entry.js → p-4d65e713.entry.js} +1 -1
- package/dist/cobalt/{p-dca4cd5f.entry.js → p-4d897896.entry.js} +1 -1
- package/dist/cobalt/{p-33ea4a90.entry.js → p-50bcc76f.entry.js} +1 -1
- package/dist/cobalt/{p-ac91259e.entry.js → p-5298c030.entry.js} +1 -1
- package/dist/cobalt/p-54c987d7.entry.js +1 -0
- package/dist/cobalt/p-56551580.entry.js +1 -0
- package/dist/cobalt/p-58137c9e.entry.js +1 -0
- package/dist/cobalt/{p-4f754c9a.entry.js → p-58d9b650.entry.js} +1 -1
- package/dist/cobalt/p-59963937.entry.js +1 -0
- package/dist/cobalt/{p-2d329ac8.entry.js → p-623cc195.entry.js} +1 -1
- package/dist/cobalt/p-63825d7f.entry.js +1 -0
- package/dist/cobalt/{p-8e667eb6.entry.js → p-66b11b38.entry.js} +1 -1
- package/dist/cobalt/{p-fb3a095b.entry.js → p-6bf6bc3e.entry.js} +1 -1
- package/dist/cobalt/p-6f700f0d.entry.js +1 -0
- package/dist/cobalt/p-73c6d735.entry.js +1 -0
- package/dist/cobalt/{p-a6357340.entry.js → p-76249983.entry.js} +1 -1
- package/dist/cobalt/{p-bfc2a849.entry.js → p-82266f11.entry.js} +1 -1
- package/dist/cobalt/{p-a9b29cc2.entry.js → p-826ee074.entry.js} +1 -1
- package/dist/cobalt/{p-23b3ff3f.entry.js → p-83a9a05a.entry.js} +1 -1
- package/dist/cobalt/{p-568cfe8d.entry.js → p-83ea631d.entry.js} +1 -1
- package/dist/cobalt/p-85501c6a.entry.js +1 -0
- package/dist/cobalt/{p-dfd25f1d.entry.js → p-88195a63.entry.js} +1 -1
- package/dist/cobalt/p-8fa5dc4a.entry.js +1 -0
- package/dist/cobalt/{p-c8dba82f.entry.js → p-91e73a92.entry.js} +1 -1
- package/dist/cobalt/{p-ac466658.entry.js → p-92b092db.entry.js} +1 -1
- package/dist/cobalt/{p-36197363.entry.js → p-996f4e38.entry.js} +1 -1
- package/dist/cobalt/p-BRbgGqLw.js +1 -0
- package/dist/cobalt/{p-BL0sCfMH.js → p-Bryf3-Js.js} +1 -1
- package/dist/cobalt/p-DFHRS9cJ.js +1 -0
- package/dist/cobalt/{p-CrtiywTB.js → p-DH5lfRNj.js} +1 -1
- package/dist/{components/p-WeuPA9Rw.js → cobalt/p-DOL2zACE.js} +1 -1
- package/dist/cobalt/p-D_zA1Pv4.js +1 -0
- package/dist/cobalt/{p-fef5db54.entry.js → p-a32b20eb.entry.js} +1 -1
- package/dist/cobalt/p-aa9400bf.entry.js +1 -0
- package/dist/cobalt/{p-8eb485c8.entry.js → p-aaca6dab.entry.js} +1 -1
- package/dist/cobalt/{p-e5495539.entry.js → p-aae86f96.entry.js} +1 -1
- package/dist/cobalt/{p-8f38e24d.entry.js → p-ad33c40e.entry.js} +1 -1
- package/dist/cobalt/p-b0c4fc71.entry.js +1 -0
- package/dist/cobalt/{p-da18b5f4.entry.js → p-b1e8d69e.entry.js} +1 -1
- package/dist/cobalt/p-b48917c9.entry.js +1 -0
- package/dist/cobalt/{p-7e53e9c8.entry.js → p-b565104d.entry.js} +1 -1
- package/dist/cobalt/{p-b0319a2d.entry.js → p-b90d41e4.entry.js} +1 -1
- package/dist/cobalt/{p-c5684c79.entry.js → p-bd683db3.entry.js} +1 -1
- package/dist/cobalt/{p-1ddbc48b.entry.js → p-c124e82b.entry.js} +1 -1
- package/dist/cobalt/{p-95efe661.entry.js → p-c2ebf0ec.entry.js} +1 -1
- package/dist/cobalt/{p-76420ac1.entry.js → p-c32c176a.entry.js} +1 -1
- package/dist/cobalt/{p-54ae807d.entry.js → p-c465d619.entry.js} +1 -1
- package/dist/cobalt/{p-ab45d9bd.entry.js → p-c91d4fc6.entry.js} +1 -1
- package/dist/cobalt/{p-ce35c898.entry.js → p-d29bb0fa.entry.js} +1 -1
- package/dist/cobalt/{p-7c5e846a.entry.js → p-db805569.entry.js} +1 -1
- package/dist/cobalt/p-e01f9b9a.entry.js +1 -0
- package/dist/cobalt/p-e3aae282.entry.js +1 -0
- package/dist/cobalt/{p-d15d3a97.entry.js → p-e4264532.entry.js} +1 -1
- package/dist/cobalt/{p-93c68029.entry.js → p-e48f4e45.entry.js} +1 -1
- package/dist/cobalt/{p-3f0eed59.entry.js → p-e49a564c.entry.js} +1 -1
- package/dist/cobalt/p-e8a2f993.entry.js +1 -0
- package/dist/cobalt/p-e8a4e6b0.entry.js +1 -0
- package/dist/cobalt/p-ea20f048.entry.js +1 -0
- package/dist/cobalt/{p-c1e7fb32.entry.js → p-eb063cc0.entry.js} +1 -1
- package/dist/cobalt/p-eb82358d.entry.js +1 -0
- package/dist/cobalt/{p-2114c036.entry.js → p-eb8691f2.entry.js} +1 -1
- package/dist/cobalt/{p-e8878cf9.entry.js → p-ee2023da.entry.js} +1 -1
- package/dist/cobalt/p-ee9a623d.entry.js +1 -0
- package/dist/cobalt/p-ef5ca521.entry.js +1 -0
- package/dist/cobalt/p-f4e1c3c3.entry.js +1 -0
- package/dist/cobalt/{p-e364b8a5.entry.js → p-f57dffca.entry.js} +1 -1
- package/dist/cobalt/p-f6691108.entry.js +1 -0
- package/dist/cobalt/p-f68dd124.entry.js +1 -0
- package/dist/cobalt/p-fMqVDypp.js +1 -0
- package/dist/cobalt/{p-0c463d9a.entry.js → p-fd150cc6.entry.js} +1 -1
- package/dist/cobalt/{p-0e91e5c4.entry.js → p-fe7e8813.entry.js} +1 -1
- package/dist/cobalt/p-gKnOhsd2.js +1 -0
- package/dist/cobalt/p-jYd9gu_c.js +1 -0
- package/dist/collection/collection-manifest.json +1 -0
- package/dist/collection/components/co-app-shell/co-app-shell.css +107 -41
- package/dist/collection/components/co-app-shell/co-app-shell.js +2 -2
- package/dist/collection/components/co-autocomplete/co-autocomplete.js +1 -1
- package/dist/collection/components/co-avatar-group/co-avatar-group.js +1 -1
- package/dist/collection/components/co-badge/co-badge.css +18 -0
- package/dist/collection/components/co-badge/co-badge.js +29 -1
- package/dist/collection/components/co-button/co-button.css +4 -4
- package/dist/collection/components/co-checkbox/co-checkbox.css +12 -3
- package/dist/collection/components/co-checkbox/co-checkbox.js +6 -6
- package/dist/collection/components/co-checkbox-group/co-checkbox-group.css +1 -3
- package/dist/collection/components/co-checkbox-group/co-checkbox-group.js +1 -1
- package/dist/collection/components/co-color-picker/co-color-picker.css +252 -5
- package/dist/collection/components/co-color-picker/co-color-picker.js +932 -15
- package/dist/collection/components/co-color-picker/presets.js +113 -15
- package/dist/collection/components/co-column-picker/co-column-picker.js +2 -2
- package/dist/collection/components/co-combobox/co-combobox.js +1 -1
- package/dist/collection/components/co-command-search/co-command-search.js +1 -1
- package/dist/collection/components/co-data-table/co-data-table.js +1 -1
- package/dist/collection/components/co-data-table-pagination/co-data-table-pagination.js +4 -4
- package/dist/collection/components/co-date-field/co-date-field.js +4 -4
- package/dist/collection/components/co-date-range/co-date-range.js +1 -1
- package/dist/collection/components/co-date-range-picker/co-date-range-picker.js +2 -2
- package/dist/collection/components/co-date-time-picker/co-date-time-picker.css +128 -32
- package/dist/collection/components/co-date-time-picker/co-date-time-picker.js +142 -138
- package/dist/collection/components/co-drawer/co-drawer.css +99 -36
- package/dist/collection/components/co-drawer/co-drawer.js +19 -7
- package/dist/collection/components/co-drive-card/co-drive-card.js +1 -1
- package/dist/collection/components/co-drop-zone/co-drop-zone.js +1 -1
- package/dist/collection/components/co-emoji-picker/co-emoji-picker.js +2 -2
- package/dist/collection/components/co-empty-state/co-empty-state.css +28 -0
- package/dist/collection/components/co-empty-state/co-empty-state.js +2 -2
- package/dist/collection/components/co-event-calendar/co-event-calendar.js +2 -2
- package/dist/collection/components/co-event-popover/co-event-popover.js +1 -1
- package/dist/collection/components/co-fab/co-fab.js +2 -2
- package/dist/collection/components/co-file-field/co-file-field.css +55 -2
- package/dist/collection/components/co-file-field/co-file-field.js +41 -13
- package/dist/collection/components/co-file-field/co-file-field.utils.js +51 -4
- package/dist/collection/components/co-file-type-tile/co-file-type-tile.js +2 -2
- package/dist/collection/components/co-helper-text/co-helper-text.js +2 -2
- package/dist/collection/components/co-icon/co-icon.js +2 -2
- package/dist/collection/components/co-icon-button/co-icon-button.css +40 -2
- package/dist/collection/components/co-icon-button/co-icon-button.js +43 -4
- package/dist/collection/components/co-input/co-input.css +33 -0
- package/dist/collection/components/co-input/co-input.js +25 -2
- package/dist/collection/components/co-json-field/co-json-field.js +3 -3
- package/dist/collection/components/co-lightbox/co-lightbox.css +23 -0
- package/dist/collection/components/co-lightbox/co-lightbox.js +209 -20
- package/dist/collection/components/co-list-footer/co-list-footer.js +1 -1
- package/dist/collection/components/co-list-item/co-list-item.js +4 -4
- package/dist/collection/components/co-media-thumb/co-media-thumb.js +2 -2
- package/dist/collection/components/co-menu/co-menu.js +1 -1
- package/dist/collection/components/co-menu-divider/co-menu-divider.js +1 -1
- package/dist/collection/components/co-menu-item/co-menu-item.js +67 -3
- package/dist/collection/components/co-modal/co-modal.css +106 -37
- package/dist/collection/components/co-modal/co-modal.js +4 -2
- package/dist/collection/components/co-navbar/co-navbar.css +4 -2
- package/dist/collection/components/co-navbar/co-navbar.js +2 -2
- package/dist/collection/components/co-number-field/co-number-field.css +22 -0
- package/dist/collection/components/co-number-field/co-number-field.js +216 -9
- package/dist/collection/components/co-option-list/co-option-list.css +25 -4
- package/dist/collection/components/co-option-list/co-option-list.js +26 -3
- package/dist/collection/components/co-overlay/co-overlay.js +5 -3
- package/dist/collection/components/co-page-header/co-page-header.js +1 -1
- package/dist/collection/components/co-phone-field/co-phone-field.js +1 -1
- package/dist/collection/components/co-popover/co-popover.css +18 -3
- package/dist/collection/components/co-popover/co-popover.js +83 -20
- package/dist/collection/components/co-progress-bar/co-progress-bar.js +2 -2
- package/dist/collection/components/co-progress-circle/co-progress-circle.js +2 -2
- package/dist/collection/components/co-radio/co-radio.js +3 -3
- package/dist/collection/components/co-radio-group/co-radio-group.js +1 -1
- package/dist/collection/components/co-rating/co-rating.js +3 -3
- package/dist/collection/components/co-ref-field/co-ref-field.js +3 -3
- package/dist/collection/components/co-rich-text-editor/co-rich-text-editor.css +14 -1
- package/dist/collection/components/co-rich-text-editor/co-rich-text-editor.js +9 -6
- package/dist/collection/components/co-rich-text-toolbar/co-rich-text-toolbar.js +7 -3
- package/dist/collection/components/co-rich-text-viewer/co-rich-text-viewer.js +3 -2
- package/dist/collection/components/co-row/co-row.js +2 -2
- package/dist/collection/components/co-segmented-bar/co-segmented-bar.js +1 -1
- package/dist/collection/components/co-select/co-select.js +1 -1
- package/dist/collection/components/co-separator/co-separator.js +1 -1
- package/dist/collection/components/co-sidebar/co-sidebar.js +2 -2
- package/dist/collection/components/co-sidebar-nav/co-sidebar-nav.css +2 -2
- package/dist/collection/components/co-sidebar-nav/co-sidebar-nav.js +1 -1
- package/dist/collection/components/co-skeleton/co-skeleton.css +18 -0
- package/dist/collection/components/co-skeleton/co-skeleton.js +83 -1
- package/dist/collection/components/co-slider/co-slider.js +2 -2
- package/dist/collection/components/co-switch/co-switch.css +3 -3
- package/dist/collection/components/co-switch/co-switch.js +3 -3
- package/dist/collection/components/co-tab/co-tab.js +2 -2
- package/dist/collection/components/co-tab-group/co-tab-group.js +2 -2
- package/dist/collection/components/co-tags-field/co-tags-field.js +5 -5
- package/dist/collection/components/co-textarea/co-textarea.js +4 -4
- package/dist/collection/components/co-time-field/co-time-field.css +111 -0
- package/dist/collection/components/co-time-field/co-time-field.js +536 -0
- package/dist/collection/components/co-toast/co-toast.css +13 -7
- package/dist/collection/components/co-toast/co-toast.js +2 -2
- package/dist/collection/components/co-toggle-button/co-toggle-button.css +16 -11
- package/dist/collection/components/co-toggle-button/co-toggle-button.js +2 -2
- package/dist/collection/components/co-toggle-button-group/co-toggle-button-group.css +7 -1
- package/dist/collection/components/co-toggle-button-group/co-toggle-button-group.js +2 -2
- package/dist/collection/components/co-tooltip/co-tooltip.css +18 -1
- package/dist/collection/components/co-tooltip/co-tooltip.js +49 -16
- package/dist/collection/components/co-transfer-list/co-transfer-list.js +1 -1
- package/dist/collection/components/co-video/co-video.js +34 -9
- package/dist/collection/utils/amountText.js +95 -0
- package/dist/collection/utils/color.js +109 -3
- package/dist/collection/utils/colorPickerI18n.js +55 -0
- package/dist/collection/utils/dateI18n.js +36 -0
- package/dist/collection/utils/fileI18n.js +3 -0
- package/dist/collection/utils/positioning.js +37 -4
- package/dist/collection/utils/submenu.js +35 -0
- package/dist/components/co-accordion.js +1 -1
- package/dist/components/co-action-bar.js +1 -1
- package/dist/components/co-app-shell.js +1 -1
- package/dist/components/co-audio-player.js +1 -1
- package/dist/components/co-autocomplete.js +1 -1
- package/dist/components/co-avatar-group.js +1 -1
- package/dist/components/co-avatar.js +1 -1
- package/dist/components/co-badge.js +1 -1
- package/dist/components/co-breadcrumb-item.js +1 -1
- package/dist/components/co-breadcrumb.js +1 -1
- package/dist/components/co-button.js +1 -1
- package/dist/components/co-calendar-month.js +1 -1
- package/dist/components/co-calendar-timegrid.js +1 -1
- package/dist/components/co-calendar.js +1 -1
- package/dist/components/co-carousel.js +1 -1
- package/dist/components/co-checkbox-group.js +1 -1
- package/dist/components/co-checkbox.js +1 -1
- package/dist/components/co-chip.js +1 -1
- package/dist/components/co-color-picker.js +1 -1
- package/dist/components/co-column-picker.js +1 -1
- package/dist/components/co-combobox.js +1 -1
- package/dist/components/co-command-search.js +1 -1
- package/dist/components/co-data-table-pagination.js +1 -1
- package/dist/components/co-data-table.js +1 -1
- package/dist/components/co-date-field.js +1 -1
- package/dist/components/co-date-picker.js +1 -1
- package/dist/components/co-date-range-picker.js +1 -1
- package/dist/components/co-date-range.js +1 -1
- package/dist/components/co-date-time-picker.js +1 -1
- package/dist/components/co-drawer.js +1 -1
- package/dist/components/co-drive-card.js +1 -1
- package/dist/components/co-drop-zone.js +1 -1
- package/dist/components/co-emoji-picker.js +1 -1
- package/dist/components/co-empty-state.js +1 -1
- package/dist/components/co-event-calendar.js +1 -1
- package/dist/components/co-event-popover.js +1 -1
- package/dist/components/co-fab.js +1 -1
- package/dist/components/co-file-field.js +1 -1
- package/dist/components/co-file-type-tile.js +1 -1
- package/dist/components/co-helper-text.js +1 -1
- package/dist/components/co-icon-button.js +1 -1
- package/dist/components/co-icon.js +1 -1
- package/dist/components/co-input.js +1 -1
- package/dist/components/co-json-field.js +1 -1
- package/dist/components/co-lightbox.js +1 -1
- package/dist/components/co-list-footer.js +1 -1
- package/dist/components/co-list-item.js +1 -1
- package/dist/components/co-media-thumb.js +1 -1
- package/dist/components/co-menu-divider.js +1 -1
- package/dist/components/co-menu-item.js +1 -1
- package/dist/components/co-menu.js +1 -1
- package/dist/components/co-modal.js +1 -1
- package/dist/components/co-navbar.js +1 -1
- package/dist/components/co-number-field.js +1 -1
- package/dist/components/co-option-list.js +1 -1
- package/dist/components/co-overlay.js +1 -1
- package/dist/components/co-page-header.js +1 -1
- package/dist/components/co-phone-field.js +1 -1
- package/dist/components/co-popover.js +1 -1
- package/dist/components/co-progress-bar.js +1 -1
- package/dist/components/co-progress-circle.js +1 -1
- package/dist/components/co-radio-group.js +1 -1
- package/dist/components/co-radio.js +1 -1
- package/dist/components/co-rating.js +1 -1
- package/dist/components/co-ref-field.js +1 -1
- package/dist/components/co-rich-text-editor.js +1 -1
- package/dist/components/co-rich-text-toolbar.js +1 -1
- package/dist/components/co-rich-text-viewer.js +1 -1
- package/dist/components/co-row.js +1 -1
- package/dist/components/co-select.js +1 -1
- package/dist/components/co-separator.js +1 -1
- package/dist/components/co-sidebar-nav.js +1 -1
- package/dist/components/co-sidebar.js +1 -1
- package/dist/components/co-skeleton.js +1 -1
- package/dist/components/co-slider.js +1 -1
- package/dist/components/co-switch.js +1 -1
- package/dist/components/co-tab-group.js +1 -1
- package/dist/components/co-tab.js +1 -1
- package/dist/components/co-tags-field.js +1 -1
- package/dist/components/co-textarea.js +1 -1
- package/dist/components/co-time-field.d.ts +11 -0
- package/dist/components/co-time-field.js +1 -0
- package/dist/components/co-toast.js +1 -1
- package/dist/components/co-toggle-button-group.js +1 -1
- package/dist/components/co-toggle-button.js +1 -1
- package/dist/components/co-tooltip.js +1 -1
- package/dist/components/co-transfer-list.js +1 -1
- package/dist/components/co-video.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/p-9ceBPSd1.js +1 -0
- package/dist/components/p-B1QFLcY9.js +1 -0
- package/dist/components/p-B2IsXte7.js +1 -0
- package/dist/components/p-B4NCaKrR.js +1 -0
- package/dist/components/p-BBP5__CY.js +1 -0
- package/dist/components/{p-Dabi98BI.js → p-BGDqldEg.js} +1 -1
- package/dist/components/p-BRbgGqLw.js +1 -0
- package/dist/components/p-Be_kyNRE.js +1 -0
- package/dist/components/{p-BL0sCfMH.js → p-Bryf3-Js.js} +1 -1
- package/dist/components/p-BsTO1uUA.js +1 -0
- package/dist/components/{p-CuZXTvDM.js → p-Bv6U5y3d.js} +1 -1
- package/dist/components/p-BxP8OBw6.js +1 -0
- package/dist/components/{p-P8wvwhM2.js → p-CFFDmGPS.js} +1 -1
- package/dist/components/{p-CA_JAK9s.js → p-CT2enQ6h.js} +1 -1
- package/dist/components/p-CXPRaTuo.js +1 -0
- package/dist/components/{p-D5EdMieb.js → p-Cl3AdEQJ.js} +1 -1
- package/dist/components/p-CnX3L8aF.js +1 -0
- package/dist/components/p-DFHRS9cJ.js +1 -0
- package/dist/components/p-DIo66nBr.js +1 -0
- package/dist/components/{p-Dj1EZ5qD.js → p-DNJAIVfI.js} +1 -1
- package/dist/{cobalt/p-WeuPA9Rw.js → components/p-DOL2zACE.js} +1 -1
- package/dist/components/p-DRP8D9ro.js +1 -0
- package/dist/components/p-DkDTmHCg.js +1 -0
- package/dist/components/{p-Bxk96Zgc.js → p-Du_CgT5E.js} +1 -1
- package/dist/components/{p-BHYtxTzM.js → p-HxVRXXXC.js} +1 -1
- package/dist/components/{p-B0Dc-I_C.js → p-NNxjElcX.js} +1 -1
- package/dist/components/p-gKnOhsd2.js +1 -0
- package/dist/components/p-jYd9gu_c.js +1 -0
- package/dist/components/{p-D4qzGifz.js → p-vby0ITbe.js} +1 -1
- package/dist/components/{p-D6OUW6oW.js → p-x4grh-eZ.js} +1 -1
- package/dist/esm/co-accordion.entry.js +1 -1
- package/dist/esm/co-action-bar.entry.js +1 -1
- package/dist/esm/co-app-shell.entry.js +4 -4
- package/dist/esm/co-audio-player.entry.js +1 -1
- package/dist/esm/co-autocomplete.entry.js +2 -2
- package/dist/esm/co-avatar-group.entry.js +1 -1
- package/dist/esm/co-avatar_2.entry.js +49 -17
- package/dist/esm/co-badge.entry.js +11 -3
- package/dist/esm/co-bottom-sheet.entry.js +1 -1
- package/dist/esm/co-breadcrumb-item.entry.js +1 -1
- package/dist/esm/co-breadcrumb.entry.js +1 -1
- package/dist/esm/co-button-group.entry.js +1 -1
- package/dist/esm/co-button.entry.js +2 -2
- package/dist/esm/co-calendar-month_2.entry.js +37 -2
- package/dist/esm/co-calendar_3.entry.js +27 -15
- package/dist/esm/co-card.entry.js +1 -1
- package/dist/esm/co-carousel-item.entry.js +1 -1
- package/dist/esm/co-carousel.entry.js +2 -2
- package/dist/esm/co-checkbox-group.entry.js +2 -2
- package/dist/esm/co-checkbox.entry.js +6 -6
- package/dist/esm/co-chip_2.entry.js +8 -5
- package/dist/esm/co-color-picker.entry.js +1048 -27
- package/dist/esm/co-column-picker.entry.js +3 -3
- package/dist/esm/co-combobox.entry.js +2 -2
- package/dist/esm/co-command-search.entry.js +1 -1
- package/dist/esm/co-data-table-pagination.entry.js +5 -5
- package/dist/esm/co-data-table.entry.js +1 -1
- package/dist/esm/co-date-picker.entry.js +3 -3
- package/dist/esm/co-date-range-picker.entry.js +3 -3
- package/dist/esm/co-date-range.entry.js +2 -2
- package/dist/esm/co-date-time-picker.entry.js +101 -130
- package/dist/esm/co-drive-card.entry.js +2 -2
- package/dist/esm/co-drop-zone.entry.js +2 -2
- package/dist/esm/co-emoji-picker.entry.js +4 -4
- package/dist/esm/co-empty-state.entry.js +4 -4
- package/dist/esm/co-event-calendar.entry.js +4 -4
- package/dist/esm/co-event-popover.entry.js +3 -3
- package/dist/esm/co-fab.entry.js +3 -3
- package/dist/esm/co-file-field.entry.js +95 -99
- package/dist/esm/co-file-type-tile.entry.js +3 -3
- package/dist/esm/co-helper-text.entry.js +3 -3
- package/dist/esm/co-icon-button.entry.js +6 -6
- package/dist/esm/co-icon.entry.js +3 -3
- package/dist/esm/co-input.entry.js +26 -4
- package/dist/esm/co-json-field.entry.js +5 -5
- package/dist/esm/co-lightbox.entry.js +204 -21
- package/dist/esm/co-list-footer.entry.js +2 -2
- package/dist/esm/co-list-item.entry.js +5 -5
- package/dist/esm/co-loader.entry.js +1 -1
- package/dist/esm/co-media-thumb.entry.js +3 -3
- package/dist/esm/co-menu-divider.entry.js +2 -2
- package/dist/esm/co-menu-item.entry.js +84 -3
- package/dist/esm/co-menu.entry.js +2 -2
- package/dist/esm/co-modal.entry.js +6 -4
- package/dist/esm/co-navbar.entry.js +4 -4
- package/dist/esm/co-number-field.entry.js +272 -9
- package/dist/esm/co-overlay.entry.js +6 -4
- package/dist/esm/co-page-header.entry.js +2 -2
- package/dist/esm/co-phone-field.entry.js +3 -3
- package/dist/esm/co-popover.entry.js +58 -21
- package/dist/esm/co-progress-bar.entry.js +3 -3
- package/dist/esm/co-progress-circle.entry.js +3 -3
- package/dist/esm/co-provider-logo_2.entry.js +47 -3
- package/dist/esm/co-radio-group.entry.js +1 -1
- package/dist/esm/co-radio.entry.js +4 -4
- package/dist/esm/co-rating.entry.js +4 -4
- package/dist/esm/co-ref-field.entry.js +4 -4
- package/dist/esm/co-rich-text-editor.entry.js +11 -8
- package/dist/esm/co-rich-text-toolbar.entry.js +7 -3
- package/dist/esm/co-rich-text-viewer.entry.js +4 -3
- package/dist/esm/co-row.entry.js +3 -3
- package/dist/esm/co-segmented-bar.entry.js +1 -1
- package/dist/esm/co-select.entry.js +2 -2
- package/dist/esm/co-separator.entry.js +2 -2
- package/dist/esm/co-sidebar-nav.entry.js +2 -2
- package/dist/esm/co-sidebar.entry.js +3 -3
- package/dist/esm/co-slider.entry.js +3 -3
- package/dist/esm/co-switch.entry.js +6 -6
- package/dist/esm/co-tab-group.entry.js +3 -3
- package/dist/esm/co-tab.entry.js +3 -3
- package/dist/esm/co-tags-field.entry.js +8 -8
- package/dist/esm/co-textarea.entry.js +6 -6
- package/dist/esm/co-time-field.entry.js +323 -0
- package/dist/esm/co-toast.entry.js +2 -2
- package/dist/esm/co-toggle-button-group.entry.js +4 -4
- package/dist/esm/co-toggle-button.entry.js +4 -4
- package/dist/esm/co-transfer-list.entry.js +1 -1
- package/dist/esm/co-video.entry.js +32 -7
- package/dist/esm/cobalt.js +3 -3
- package/dist/esm/color-BRbgGqLw.js +136 -0
- package/dist/esm/{dateI18n-CnNpoKwg.js → dateI18n-jYd9gu_c.js} +36 -0
- package/dist/esm/{fieldChip-DsAfq1e0.js → fieldChip-uyggU8VV.js} +1 -1
- package/dist/esm/fileI18n-gKnOhsd2.js +84 -0
- package/dist/esm/{index-RuXxdKzC.js → index-68iUQp5j.js} +28 -10
- package/dist/esm/{index-CrtiywTB.js → index-DH5lfRNj.js} +25 -21
- package/dist/esm/loader.js +3 -3
- package/dist/esm/{positioning-BMdapAL8.js → positioning-DFHRS9cJ.js} +32 -13
- package/dist/esm/{requiredMark-DCD-ZA51.js → requiredMark-BCJUuZvC.js} +1 -1
- package/dist/esm/{toolbar-config-WeuPA9Rw.js → toolbar-config-DOL2zACE.js} +10 -0
- package/dist/types/components/co-badge/co-badge.d.ts +7 -0
- package/dist/types/components/co-checkbox/co-checkbox.d.ts +1 -1
- package/dist/types/components/co-color-picker/co-color-picker.d.ts +358 -4
- package/dist/types/components/co-color-picker/presets.d.ts +107 -4
- package/dist/types/components/co-date-time-picker/co-date-time-picker.d.ts +43 -21
- package/dist/types/components/co-drawer/co-drawer.d.ts +4 -3
- package/dist/types/components/co-file-field/co-file-field.d.ts +14 -0
- package/dist/types/components/co-file-field/co-file-field.utils.d.ts +18 -1
- package/dist/types/components/co-icon-button/co-icon-button.d.ts +9 -0
- package/dist/types/components/co-input/co-input.d.ts +4 -0
- package/dist/types/components/co-lightbox/co-lightbox.d.ts +60 -4
- package/dist/types/components/co-menu-item/co-menu-item.d.ts +16 -0
- package/dist/types/components/co-number-field/co-number-field.d.ts +42 -1
- package/dist/types/components/co-option-list/co-option-list.d.ts +3 -0
- package/dist/types/components/co-overlay/co-overlay.d.ts +4 -2
- package/dist/types/components/co-popover/co-popover.d.ts +16 -0
- package/dist/types/components/co-rich-text-toolbar/co-rich-text-toolbar.d.ts +1 -1
- package/dist/types/components/co-skeleton/co-skeleton.d.ts +13 -0
- package/dist/types/components/co-time-field/co-time-field.d.ts +60 -0
- package/dist/types/components/co-tooltip/co-tooltip.d.ts +5 -0
- package/dist/types/components/co-video/co-video.d.ts +4 -0
- package/dist/types/components.d.ts +451 -87
- package/dist/types/utils/amountText.d.ts +34 -0
- package/dist/types/utils/color.d.ts +44 -1
- package/dist/types/utils/colorPickerI18n.d.ts +26 -0
- package/dist/types/utils/dateI18n.d.ts +12 -0
- package/dist/types/utils/fileI18n.d.ts +1 -0
- package/dist/types/utils/positioning.d.ts +10 -0
- package/dist/types/utils/submenu.d.ts +44 -0
- package/package.json +3 -3
- package/dist/cjs/color-YhUkm10t.js +0 -32
- package/dist/cjs/time-LBHtzLHe.js +0 -42
- package/dist/cobalt/p-07904986.entry.js +0 -1
- package/dist/cobalt/p-09799193.entry.js +0 -1
- package/dist/cobalt/p-17ae943c.entry.js +0 -1
- package/dist/cobalt/p-23a103a0.entry.js +0 -1
- package/dist/cobalt/p-2f88d151.entry.js +0 -1
- package/dist/cobalt/p-3495fda1.entry.js +0 -1
- package/dist/cobalt/p-409f28bb.entry.js +0 -1
- package/dist/cobalt/p-682b3313.entry.js +0 -1
- package/dist/cobalt/p-6bf814f9.entry.js +0 -1
- package/dist/cobalt/p-7c88163e.entry.js +0 -1
- package/dist/cobalt/p-7cf4b4ae.entry.js +0 -1
- package/dist/cobalt/p-7ea87b75.entry.js +0 -1
- package/dist/cobalt/p-8183f56f.entry.js +0 -1
- package/dist/cobalt/p-8345b25f.entry.js +0 -1
- package/dist/cobalt/p-8b4b3589.entry.js +0 -1
- package/dist/cobalt/p-983af614.entry.js +0 -1
- package/dist/cobalt/p-BG4WRR22.js +0 -1
- package/dist/cobalt/p-BMdapAL8.js +0 -1
- package/dist/cobalt/p-CF8OB_TM.js +0 -1
- package/dist/cobalt/p-CnNpoKwg.js +0 -1
- package/dist/cobalt/p-T4la7ly_.js +0 -1
- package/dist/cobalt/p-a2d31248.entry.js +0 -1
- package/dist/cobalt/p-a6b5cadd.entry.js +0 -1
- package/dist/cobalt/p-b8581787.entry.js +0 -1
- package/dist/cobalt/p-bcedbd73.entry.js +0 -1
- package/dist/cobalt/p-d40a465f.entry.js +0 -1
- package/dist/cobalt/p-dea43204.entry.js +0 -1
- package/dist/cobalt/p-dfcf667d.entry.js +0 -1
- package/dist/cobalt/p-e6882ddd.entry.js +0 -1
- package/dist/cobalt/p-e84eda2e.entry.js +0 -1
- package/dist/cobalt/p-f25967fb.entry.js +0 -1
- package/dist/cobalt/p-f5f1b463.entry.js +0 -1
- package/dist/cobalt/p-fd39f410.entry.js +0 -1
- package/dist/cobalt/p-mAGnZXRn.js +0 -1
- package/dist/components/p-BMdapAL8.js +0 -1
- package/dist/components/p-BTQEg3UO.js +0 -1
- package/dist/components/p-BZIB4JDs.js +0 -1
- package/dist/components/p-Bbny3WUc.js +0 -1
- package/dist/components/p-C1Kv3zYZ.js +0 -1
- package/dist/components/p-CF8OB_TM.js +0 -1
- package/dist/components/p-CR0izsJC.js +0 -1
- package/dist/components/p-CnNpoKwg.js +0 -1
- package/dist/components/p-DP0bbhfN.js +0 -1
- package/dist/components/p-DbipMAyT.js +0 -1
- package/dist/components/p-DgUBcJIS.js +0 -1
- package/dist/components/p-DolCkNsL.js +0 -1
- package/dist/components/p-gI62K3Be.js +0 -1
- package/dist/components/p-hfGFsvaD.js +0 -1
- package/dist/esm/color-BG4WRR22.js +0 -30
- 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-
|
|
2
|
-
import { R as RequiredMark } from './requiredMark-
|
|
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
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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: '
|
|
11
|
-
{ name: '
|
|
12
|
-
{ name: '
|
|
13
|
-
{ name: '
|
|
14
|
-
{ name: '
|
|
15
|
-
{ name: '
|
|
16
|
-
{ name: '
|
|
17
|
-
{
|
|
18
|
-
{
|
|
19
|
-
{ name: '
|
|
20
|
-
{ name: '
|
|
21
|
-
{ name: '
|
|
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(
|
|
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(
|
|
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) =>
|
|
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
|
-
|
|
98
|
-
|
|
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: '
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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 };
|