0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-23 23:18:48 -05:00

🐛 Fixes problems with the picker for Safari and Firefox

This commit is contained in:
alonso.torres 2020-12-02 15:37:11 +01:00 committed by Andrey Antukh
parent ba529b9fd6
commit 264811c5ee
7 changed files with 158 additions and 127 deletions

View file

@ -0,0 +1,33 @@
/*
* Safari and Edge polyfill for createImageBitmap
* https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap
*
* Support source image types Blob and ImageData.
*
* From: https://dev.to/nektro/createimagebitmap-polyfill-for-safari-and-edge-228
* Updated by Yoan Tournade <yoan@ytotech.com>
*/
if (!('createImageBitmap' in window)) {
window.createImageBitmap = async function (data) {
return new Promise((resolve,reject) => {
let dataURL;
if (data instanceof Blob) {
dataURL = URL.createObjectURL(data);
} else if (data instanceof ImageData) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = data.width;
canvas.height = data.height;
ctx.putImageData(data,0,0);
dataURL = canvas.toDataURL();
} else {
throw new Error('createImageBitmap does not handle the provided image source type');
}
const img = document.createElement('img');
img.addEventListener('load',function () {
resolve(this);
});
img.src = dataURL;
});
};
}

View file

@ -1621,8 +1621,7 @@
(let [edition-id (get-in state [:workspace-local :edition])
path-edit-mode (get-in state [:workspace-local :edit-path edition-id :edit-mode])]
(if-not (= :draw path-edit-mode)
(rx/of :interrupt
(deselect-all true))
(rx/of :interrupt (deselect-all true))
(rx/empty))))))
(defn c-mod

View file

@ -64,7 +64,7 @@
(dom/stop-propagation event)
(st/emit! (modal/hide))
(on-accept props))))
key (events/listen (dom/get-root) EventType.KEYDOWN on-keydown)]
key (events/listen js/document EventType.KEYDOWN on-keydown)]
#(events/unlistenByKey key))))
[:div.modal-overlay

View file

@ -76,7 +76,7 @@
(mf/deps allow-click-outside)
(fn []
(let [keys [(events/listen js/window EventType.POPSTATE on-pop-state)
(events/listen (dom/get-root) EventType.KEYDOWN handle-keydown)
(events/listen js/document EventType.KEYDOWN handle-keydown)
(events/listen (dom/get-root) EventType.CLICK handle-click-outside)]]
#(doseq [key keys]
(events/unlistenByKey key)))))

View file

@ -54,106 +54,124 @@
[:& shape-wrapper {:shape item
:key (:id item)}]))]]))
(defn draw-picker-canvas [svg-node canvas-node]
(let [canvas-context (.getContext canvas-node "2d")
xml (.serializeToString (js/XMLSerializer.) svg-node)
img-src (str "data:image/svg+xml;base64,"
(-> xml js/encodeURIComponent js/unescape js/btoa))
img (js/Image.)
on-error (fn [err] (.error js/console "ERROR" err))
on-load (fn [] (.drawImage canvas-context img 0 0))]
(.addEventListener img "error" on-error)
(.addEventListener img "load" on-load)
(obj/set! img "src" img-src)))
(mf/defc pixel-overlay
{::mf/wrap-props false}
[props]
(let [vport (unchecked-get props "vport")
vbox (unchecked-get props "vbox")
(let [vport (unchecked-get props "vport")
vbox (unchecked-get props "vbox")
viewport-ref (unchecked-get props "viewport-ref")
options (unchecked-get props "options")
svg-ref (mf/use-ref nil)
canvas-ref (mf/use-ref nil)
fetch-pending (mf/deref (mdf/pending-ref))
options (unchecked-get props "options")
svg-ref (mf/use-ref nil)
canvas-ref (mf/use-ref nil)
img-ref (mf/use-ref nil)
update-canvas-stream (rx/subject)
update-str (rx/subject)
handle-keydown
(fn [event]
(when (and (kbd/esc? event))
(do (dom/stop-propagation event)
(dom/prevent-default event)
(st/emit! (dwc/stop-picker))
(modal/disallow-click-outside!))))
(mf/use-callback
(fn [event]
(when (and (kbd/esc? event))
(do (dom/stop-propagation event)
(dom/prevent-default event)
(st/emit! (dwc/stop-picker))
(modal/disallow-click-outside!)))))
on-mouse-move-picker
(fn [event]
(when-let [zoom-view-node (.getElementById js/document "picker-detail")]
(let [{brx :left bry :top} (dom/get-bounding-rect (mf/ref-val viewport-ref))
x (- (.-clientX event) brx)
y (- (.-clientY event) bry)
handle-mouse-move-picker
(mf/use-callback
(mf/deps viewport-ref)
(fn [event]
(when-let [zoom-view-node (.getElementById js/document "picker-detail")]
(let [viewport-node (mf/ref-val viewport-ref)
canvas-node (mf/ref-val canvas-ref)
zoom-context (.getContext zoom-view-node "2d")
canvas-node (mf/ref-val canvas-ref)
canvas-context (.getContext canvas-node "2d")
pixel-data (.getImageData canvas-context x y 1 1)
rgba (.-data pixel-data)
r (obj/get rgba 0)
g (obj/get rgba 1)
b (obj/get rgba 2)
a (obj/get rgba 3)
{brx :left bry :top} (dom/get-bounding-rect viewport-node)
x (- (.-clientX event) brx)
y (- (.-clientY event) bry)
area-data (.getImageData canvas-context (- x 25) (- y 20) 50 40)]
zoom-context (.getContext zoom-view-node "2d")
canvas-context (.getContext canvas-node "2d")
pixel-data (.getImageData canvas-context x y 1 1)
rgba (.-data pixel-data)
r (obj/get rgba 0)
g (obj/get rgba 1)
b (obj/get rgba 2)
a (obj/get rgba 3)
area-data (.getImageData canvas-context (- x 25) (- y 20) 50 40)]
(-> (js/createImageBitmap area-data)
(p/then
(fn [image]
;; Draw area
(obj/set! zoom-context "imageSmoothingEnabled" false)
(.drawImage zoom-context image 0 0 200 160))))
(st/emit! (dwc/pick-color [r g b a]))))))
(-> (js/createImageBitmap area-data)
(p/then (fn [image]
;; Draw area
(obj/set! zoom-context "imageSmoothingEnabled" false)
(.drawImage zoom-context image 0 0 200 160))))
(st/emit! (dwc/pick-color [r g b a])))))
handle-mouse-down-picker
(mf/use-callback
(fn [event]
(dom/prevent-default event)
(dom/stop-propagation event)
(st/emit! (dwc/pick-color-select true (kbd/shift? event)))))
on-mouse-down-picker
(fn [event]
(dom/prevent-default event)
(dom/stop-propagation event)
(st/emit! (dwc/pick-color-select true (kbd/shift? event))))
handle-mouse-up-picker
(mf/use-callback
(fn [event]
(dom/prevent-default event)
(dom/stop-propagation event)
(st/emit! (dwc/stop-picker))
(modal/disallow-click-outside!)))
on-mouse-up-picker
(fn [event]
(dom/prevent-default event)
(dom/stop-propagation event)
(st/emit! (dwc/stop-picker))
(modal/disallow-click-outside!))]
handle-image-load
(mf/use-callback
(mf/deps img-ref)
(fn []
(let [canvas-node (mf/ref-val canvas-ref)
img-node (mf/ref-val img-ref)
canvas-context (.getContext canvas-node "2d")]
(.drawImage canvas-context img-node 0 0))))
handle-draw-picker-canvas
(mf/use-callback
(mf/deps img-ref)
(fn []
(let [img-node (mf/ref-val img-ref)
svg-node (mf/ref-val svg-ref)
xml (-> (js/XMLSerializer.)
(.serializeToString svg-node)
js/encodeURIComponent
js/unescape
js/btoa)
img-src (str "data:image/svg+xml;base64," xml)]
(obj/set! img-node "src" img-src))))
handle-svg-change
(mf/use-callback
(fn []
(rx/push! update-str :update)))]
(mf/use-effect
(fn []
(let [listener (events/listen (dom/get-root) EventType.KEYDOWN handle-keydown)]
(let [listener (events/listen js/document EventType.KEYDOWN handle-keydown)]
#(events/unlistenByKey listener))))
(mf/use-effect
(fn []
(let [sub (->> update-canvas-stream
(let [sub (->> update-str
(rx/debounce 10)
(rx/subs #(draw-picker-canvas (mf/ref-val svg-ref)
(mf/ref-val canvas-ref))))]
(rx/subs handle-draw-picker-canvas))]
#(rx/dispose! sub))))
(mf/use-effect
(mf/deps svg-ref canvas-ref)
(mf/deps svg-ref)
(fn []
(when (and svg-ref canvas-ref)
(let [config (clj->js {:attributes true
:childList true
:subtree true
:characterData true})
on-svg-change (fn [mutation-list] (rx/push! update-canvas-stream :update))
observer (js/MutationObserver. on-svg-change)]
(.observe observer (mf/ref-val svg-ref) config)
(when svg-ref
(let [config #js {:attributes true
:childList true
:subtree true
:characterData true}
svg-node (mf/ref-val svg-ref)
observer (js/MutationObserver. handle-svg-change)]
(.observe observer svg-node config)
(handle-svg-change)
;; Disconnect on unmount
#(.disconnect observer)))))
@ -167,21 +185,31 @@
:width "100%"
:height "100%"
:cursor cur/picker}
:on-mouse-down on-mouse-down-picker
:on-mouse-up on-mouse-up-picker
:on-mouse-move on-mouse-move-picker}]
[:canvas {:ref canvas-ref
:width (:width vport 0)
:height (:height vport 0)
:style {:display "none"}}]
:on-mouse-down handle-mouse-down-picker
:on-mouse-up handle-mouse-up-picker
:on-mouse-move handle-mouse-move-picker}
[:div {:style {:display "none"}}
[:img {:ref img-ref
:on-load handle-image-load
:style {:position "absolute"
:width "100%"
:height "100%"}}]
[:canvas {:ref canvas-ref
:width (:width vport 0)
:height (:height vport 0)
:style {:position "absolute"
:width "100%"
:height "100%"}}]
[:& (mf/provider muc/embed-ctx) {:value true}
[:svg.viewport
{:ref svg-ref
:preserveAspectRatio "xMidYMid meet"
:width (:width vport 0)
:height (:height vport 0)
:view-box (format-viewbox vbox)
:style {:display "none"
:background-color (get options :background "#E8E9EA")}}
[:& overlay-frames]]]]))
[:& (mf/provider muc/embed-ctx) {:value true}
[:svg.viewport
{:ref svg-ref
:preserveAspectRatio "xMidYMid meet"
:width (:width vport 0)
:height (:height vport 0)
:view-box (format-viewbox vbox)
:style {:position "absolute"
:width "100%"
:height "100%"
:background-color (get options :background "#E8E9EA")}}
[:& overlay-frames]]]]]]))

View file

@ -1,29 +0,0 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0.
;;
;; Copyright (c) 2020 UXBOX Labs SL
(ns app.main.ui.workspace.colorpicker.pixel-picker
(:require
[rumext.alpha :as mf]
[okulary.core :as l]
[cuerdas.core :as str]
[app.common.geom.point :as gpt]
[app.common.math :as math]
[app.common.uuid :refer [uuid]]
[app.util.dom :as dom]
[app.util.color :as uc]
[app.util.object :as obj]
[app.main.store :as st]
[app.main.refs :as refs]
[app.main.data.workspace.libraries :as dwl]
[app.main.data.colors :as dc]
[app.main.data.modal :as modal]
[app.main.ui.icons :as i]
[app.util.i18n :as i18n :refer [t]]))

View file

@ -490,8 +490,8 @@
(let [node (mf/ref-val viewport-ref)
prnt (dom/get-parent node)
keys [(events/listen (dom/get-root) EventType.KEYDOWN on-key-down)
(events/listen (dom/get-root) EventType.KEYUP on-key-up)
keys [(events/listen js/document EventType.KEYDOWN on-key-down)
(events/listen js/document EventType.KEYUP on-key-up)
(events/listen node EventType.MOUSEMOVE on-mouse-move)
;; bind with passive=false to allow the event to be cancelled
;; https://stackoverflow.com/a/57582286/3219895