0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-09 00:10:11 -05:00

🐛 Safari compatibility fixes

This commit is contained in:
alonso.torres 2020-11-30 17:59:39 +01:00 committed by Andrey Antukh
parent 9260c59afb
commit 001f90a540
12 changed files with 164 additions and 75 deletions

View file

@ -224,3 +224,8 @@ input[type=number]::-webkit-inner-spin-button,
input[type=number] {
-moz-appearance: textfield;
}
[contenteditable] {
-webkit-user-select: text;
user-select: text;
}

View file

@ -1,5 +1,4 @@
.debug-preview {
max-height: 100vh;
display: flex;
flex-direction: column;
overflow: scroll;

View file

@ -9,9 +9,41 @@
(ns app.config
(:require
[clojure.spec.alpha :as s]
[app.common.spec :as us]
[app.util.object :as obj]
[app.util.dom :as dom]
[cuerdas.core :as str]))
(s/def ::platform #{:windows :linux :macos :other})
(s/def ::browser #{:chrome :mozilla :safari :edge :other})
(defn parse-browser
[]
(let [user-agent (-> (dom/get-user-agent) str/lower)
check-chrome? (fn [] (str/includes? user-agent "chrom"))
check-firefox? (fn [] (str/includes? user-agent "firefox"))
check-edge? (fn [] (str/includes? user-agent "edg"))
check-safari? (fn [] (str/includes? user-agent "safari"))]
(cond
(check-edge?) :edge
(check-chrome?) :chrome
(check-firefox?) :firefox
(check-safari?) :safari
:else :other)))
(defn parse-platform
[]
(let [user-agent (-> (dom/get-user-agent) str/lower)
check-windows? (fn [] (str/includes? user-agent "windows"))
check-linux? (fn [] (str/includes? user-agent "linux"))
check-macos? (fn [] (str/includes? user-agent "mac os"))]
(cond
(check-windows?) :windows
(check-linux?) :linux
(check-macos?) :macos
:else :other)))
(this-as global
(def default-language "en")
(def demo-warning (obj/get global "appDemoWarning" false))
@ -22,7 +54,17 @@
(def public-uri (or (obj/get global "appPublicURI")
(.-origin ^js js/location)))
(def media-uri (str public-uri "/media"))
(def default-theme "default"))
(def default-theme "default")
(def browser (parse-browser))
(def platform (parse-platform)))
(defn ^boolean check-browser? [candidate]
(us/verify ::browser candidate)
(= candidate browser))
(defn ^boolean check-platform? [candidate]
(us/verify ::platform candidate)
(= candidate platform))
(defn resolve-media-path
[path]

View file

@ -1625,45 +1625,53 @@
(deselect-all true))
(rx/empty))))))
(defn c-mod
"Adds the control/command modifier to a shortcuts depending on the
operating system for the user"
[shortcut]
(if (cfg/check-platform? :macos)
(str "command+" shortcut)
(str "ctrl+" shortcut)))
(def shortcuts
{"ctrl+i" #(st/emit! (toggle-layout-flags :assets))
"ctrl+l" #(st/emit! (toggle-layout-flags :sitemap :layers))
"ctrl+shift+r" #(st/emit! (toggle-layout-flags :rules))
"ctrl+a" #(st/emit! (select-all))
"ctrl+p" #(st/emit! (toggle-layout-flags :colorpalette))
"ctrl+'" #(st/emit! (toggle-layout-flags :display-grid))
"ctrl+shift+'" #(st/emit! (toggle-layout-flags :snap-grid))
{(c-mod "i") #(st/emit! (toggle-layout-flags :assets))
(c-mod "l") #(st/emit! (toggle-layout-flags :sitemap :layers))
(c-mod "shift+r") #(st/emit! (toggle-layout-flags :rules))
(c-mod "a") #(st/emit! (select-all))
(c-mod "p") #(st/emit! (toggle-layout-flags :colorpalette))
(c-mod "'") #(st/emit! (toggle-layout-flags :display-grid))
(c-mod "shift+'") #(st/emit! (toggle-layout-flags :snap-grid))
"+" #(st/emit! (increase-zoom nil))
"-" #(st/emit! (decrease-zoom nil))
"ctrl+g" #(st/emit! group-selected)
(c-mod "g") #(st/emit! group-selected)
"shift+g" #(st/emit! ungroup-selected)
"ctrl+m" #(st/emit! mask-group)
(c-mod "m") #(st/emit! mask-group)
"shift+m" #(st/emit! unmask-group)
"ctrl+k" #(st/emit! dwl/add-component)
(c-mod "k") #(st/emit! dwl/add-component)
"shift+0" #(st/emit! reset-zoom)
"shift+1" #(st/emit! zoom-to-fit-all)
"shift+2" #(st/emit! zoom-to-selected-shape)
"ctrl+d" #(st/emit! duplicate-selected)
"ctrl+z" #(st/emit! dwc/undo)
"ctrl+shift+z" #(st/emit! dwc/redo)
"ctrl+y" #(st/emit! dwc/redo)
"ctrl+q" #(st/emit! dwc/reinitialize-undo)
(c-mod "d") #(st/emit! duplicate-selected)
(c-mod "z") #(st/emit! dwc/undo)
(c-mod "shift+z") #(st/emit! dwc/redo)
(c-mod "y") #(st/emit! dwc/redo)
(c-mod "q") #(st/emit! dwc/reinitialize-undo)
"a" #(st/emit! (dwd/select-for-drawing :frame))
"r" #(st/emit! (dwd/select-for-drawing :rect))
"e" #(st/emit! (dwd/select-for-drawing :circle))
"t" #(st/emit! dwtxt/start-edit-if-selected
(dwd/select-for-drawing :text))
"p" #(st/emit! (dwd/select-for-drawing :path))
"ctrl+c" #(st/emit! copy-selected)
"ctrl+v" #(st/emit! paste)
"ctrl+x" #(st/emit! copy-selected delete-selected)
(c-mod "c") #(st/emit! copy-selected)
(c-mod "v") #(st/emit! paste)
(c-mod "x") #(st/emit! copy-selected delete-selected)
"escape" #(st/emit! (esc-pressed))
"del" #(st/emit! delete-selected)
"backspace" #(st/emit! delete-selected)
"ctrl+up" #(st/emit! (vertical-order-selected :up))
"ctrl+down" #(st/emit! (vertical-order-selected :down))
"ctrl+shift+up" #(st/emit! (vertical-order-selected :top))
"ctrl+shift+down" #(st/emit! (vertical-order-selected :bottom))
(c-mod "up") #(st/emit! (vertical-order-selected :up))
(c-mod "down") #(st/emit! (vertical-order-selected :down))
(c-mod "shift+up") #(st/emit! (vertical-order-selected :top))
(c-mod "shift+down") #(st/emit! (vertical-order-selected :bottom))
"shift+up" #(st/emit! (dwt/move-selected :up true))
"shift+down" #(st/emit! (dwt/move-selected :down true))
"shift+right" #(st/emit! (dwt/move-selected :right true))

View file

@ -55,10 +55,14 @@
(defn encode-svg-cursor
[id rotation x y height]
(let [svg-path (str cursor-folder "/" (name id) ".svg")
data (-> svg-path io/resource slurp parse-svg uri/percent-encode)
transform (if rotation (str " transform='rotate(" rotation ")'") "")]
data (-> svg-path io/resource slurp parse-svg)
data (uri/percent-encode data)
data (if rotation
(str/fmt "%3Cg transform='rotate(%s 8,8)'%3E%s%3C/g%3E" rotation data)
data)]
(str "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='20px' "
"height='" height "px' " transform "%3E" data "%3C/svg%3E\") " x " " y ", auto")))
"height='" height "px' %3E" data "%3C/svg%3E\") " x " " y ", auto")))
(defmacro cursor-ref
"Creates a static cursor given its name, rotation and x/y hotspot"

View file

@ -26,7 +26,7 @@
[{:keys [node index shape] :as props}]
(let [embed-resources? (mf/use-ctx muc/embed-ctx)
{:keys [type text children]} node
props #js {:shape shape}
render-node
(fn [index node]
(mf/element text-node {:index index
@ -35,29 +35,31 @@
:shape shape}))]
(if (string? text)
(let [style (sts/generate-text-styles (clj->js node))]
[:span.text-node {:style style} (if (= text "") "\u00A0" text)])
(let [style (sts/generate-text-styles (clj->js node) props)]
[:span {:style style
:className (when (:fill-color-gradient node) "gradient")}
(if (= text "") "\u00A0" text)])
(let [children (map-indexed render-node children)]
(case type
"root"
(let [style (sts/generate-root-styles (clj->js node) #js {:shape shape})]
(let [style (sts/generate-root-styles (clj->js node) props)]
[:div.root.rich-text
{:key index
:style style
:xmlns "http://www.w3.org/1999/xhtml"}
[:*
[:style ".text-node { background: var(--text-color); -webkit-text-fill-color: transparent; -webkit-background-clip: text;"]
[:style ".gradient { background: var(--text-color); -webkit-text-fill-color: transparent; -webkit-background-clip: text;"]
(when embed-resources?
[ste/embed-fontfaces-style {:node node}])]
children])
"paragraph-set"
(let [style (sts/generate-paragraph-set-styles (clj->js node))]
(let [style (sts/generate-paragraph-set-styles (clj->js node) props)]
[:div.paragraph-set {:key index :style style} children])
"paragraph"
(let [style (sts/generate-paragraph-styles (clj->js node))]
(let [style (sts/generate-paragraph-styles (clj->js node) props)]
[:p.paragraph {:key index :style style} children])
nil)))))

View file

@ -35,27 +35,29 @@
(= talign "justify") (obj/set! "justifyContent" "stretch"))))
(defn generate-paragraph-set-styles
[data]
[data props]
;; The position absolute is used so the paragraph is "outside"
;; the normal layout and can grow outside its parent
;; We use this element to measure the size of the text
(let [base #js {:display "inline-block"
:position "absolute"}]
(let [base #js {:display "inline-block"}]
base))
(defn generate-paragraph-styles
[data]
(let [base #js {:fontSize "14px"
[data props]
(let [shape (obj/get props "shape")
grow-type (:grow-type shape)
base #js {:fontSize "14px"
:margin "inherit"
:lineHeight "1.2"}
lh (obj/get data "line-height")
ta (obj/get data "text-align")]
(cond-> base
ta (obj/set! "textAlign" ta)
lh (obj/set! "lineHeight" lh))))
lh (obj/set! "lineHeight" lh)
(= grow-type :auto-width) (obj/set! "whiteSpace" "pre"))))
(defn generate-text-styles
[data]
[data props]
(let [letter-spacing (obj/get data "letter-spacing")
text-decoration (obj/get data "text-decoration")
text-transform (obj/get data "text-transform")
@ -82,7 +84,7 @@
fill-color-ref-file (obj/get data "fill-color-ref-file")
[r g b a] (uc/hex->rgba fill-color fill-opacity)
background (if fill-color-gradient
text-color (if fill-color-gradient
(uc/gradient->css (js->clj fill-color-gradient))
(str/format "rgba(%s, %s, %s, %s)" r g b a))
@ -91,7 +93,8 @@
base #js {:textDecoration text-decoration
:textTransform text-transform
:lineHeight (or line-height "inherit")
"--text-color" background}]
:color text-color
"--text-color" text-color}]
(when (and (string? letter-spacing)
(pos? (alength letter-spacing)))
@ -117,4 +120,5 @@
(obj/set! base "fontStyle" font-style)
(obj/set! base "fontWeight" font-weight))))
base))

View file

@ -156,10 +156,11 @@
(let [res-point (if (#{:top :bottom} position)
{:y y}
{:x x})
width length #_(max 0 (- length (/ (* resize-point-rect-size 2) zoom)))
target-length (max 0 (- length (/ (* resize-point-rect-size 2) zoom)))
width (if (< target-length 6) length target-length)
height (/ resize-side-height zoom)]
[:rect {:x x
:y (- y (/ resize-side-height 2 zoom))
[:rect {:x (+ x (/ (- length width) 2))
:y (- y (/ height 2))
:width width
:height height
:transform (gmt/multiply transform

View file

@ -115,11 +115,13 @@
(resize-observer shape text-node ".paragraph-set")
[:> shape-container {:shape shape}
[:& text/text-shape {:key "text-shape"
:ref text-ref
:shape shape
:selected? selected?
:style {:display (when edition? "none")}}]
;; We keep hidden the shape when we're editing so it keeps track of the size
;; and updates the selrect acordingly
[:g.text-shape {:opacity (when edition? 0)}
[:& text/text-shape {:key "text-shape"
:ref text-ref
:shape shape
:selected? selected?}]]
(when edition?
[:& editor/text-shape-edit {:key "editor"
:shape shape}])

View file

@ -82,7 +82,7 @@
data (obj/get props "element")
type (obj/get data "type")
shape (obj/get props "shape")
style (sts/generate-paragraph-set-styles data)
style (sts/generate-paragraph-set-styles data props)
attrs (-> (obj/get props "attributes")
(obj/set! "style" style)
(obj/set! "className" type))]
@ -95,7 +95,7 @@
childs (obj/get props "children")
data (obj/get props "element")
type (obj/get data "type")
style (sts/generate-paragraph-styles data)
style (sts/generate-paragraph-styles data props)
attrs (-> (obj/get props "attributes")
(obj/set! "style" style)
(obj/set! "className" type))]
@ -106,10 +106,14 @@
[props]
(let [childs (obj/get props "children")
data (obj/get props "leaf")
style (sts/generate-text-styles data)
type (obj/get data "type")
style (sts/generate-text-styles data props)
attrs (-> (obj/get props "attributes")
(obj/set! "style" style)
(obj/set! "className" "text-node"))]
(obj/set! "style" style))
gradient (obj/get data "fill-color-gradient" nil)]
(if gradient
(obj/set! attrs "className" (str type " gradient"))
(obj/set! attrs "className" type))
[:> :span attrs childs]))
(defn- render-element
@ -135,7 +139,7 @@
;; --- Text Shape Edit
(mf/defc text-shape-edit
(mf/defc text-shape-edit-html
{::mf/wrap [mf/memo]
::mf/wrap-props false
::mf/forward-ref true}
@ -161,9 +165,6 @@
on-click-outside
(fn [event]
(dom/prevent-default event)
(dom/stop-propagation event)
(let [sidebar (dom/get-element "settings-bar")
assets (dom/get-element-by-class "assets-bar")
cpicker (dom/get-element-by-class "colorpicker-tooltip")
@ -174,9 +175,13 @@
(and assets (.contains assets target))
(and self (.contains self target))
(and cpicker (.contains cpicker target)))
(if selecting?
(mf/set-ref-val! selecting-ref false)
(on-close)))))
(do
(dom/prevent-default event)
(dom/stop-propagation event)
(if selecting?
(mf/set-ref-val! selecting-ref false)
(on-close))))))
on-mouse-down
(fn [event]
@ -230,13 +235,9 @@
(reset! state (parse-content content))
(reset! content-var content)))
[:foreignObject {:ref self-ref
:transform (gsh/transform-matrix shape)
:x x :y y
:width (if (#{:auto-width} grow-type) 10000 width)
:height (if (#{:auto-height :auto-width} grow-type) 10000 height)}
[:div.text-editor {:ref self-ref}
[:style "span { line-height: inherit; }
.text-node { background: var(--text-color); -webkit-text-fill-color: transparent; -webkit-background-clip: text;"]
.gradient { background: var(--text-color); -webkit-text-fill-color: transparent; -webkit-background-clip: text;"]
[:> rslate/Slate {:editor editor
:value @state
:on-change on-change}
@ -257,3 +258,17 @@
;; WARN: monky patch
(obj/set! slate/Transforms "deselect" (constantly nil)))
:placeholder (when (= :fixed grow-type) "Type some text here...")}]]]))
(mf/defc text-shape-edit
{::mf/wrap [mf/memo]
::mf/wrap-props false
::mf/forward-ref true}
[props ref]
(let [shape (unchecked-get props "shape")
{:keys [x y width height grow-type]} shape]
[:foreignObject {:transform (gsh/transform-matrix shape)
:x x :y y
:width (if (#{:auto-width} grow-type) 10000 width)
:height (if (#{:auto-height :auto-width} grow-type) 10000 height)}
[:& text-shape-edit-html {:shape shape}]]))

View file

@ -116,8 +116,7 @@
(st/emit! dw/start-pan)
(rx/subscribe stream
(fn [delta]
(let [vbox (.. ^js node -viewBox -baseVal)
zoom (gpt/point @refs/selected-zoom)
(let [zoom (gpt/point @refs/selected-zoom)
delta (gpt/divide delta zoom)]
(st/emit! (dw/update-viewport-position
{:x #(- % (:x delta))
@ -352,10 +351,15 @@
on-mouse-move
(fn [event]
(let [event (.getBrowserEvent ^js event)
pt (dom/get-client-position ^js event)
pt (translate-point-to-viewport pt)
delta (gpt/point (.-movementX ^js event)
(.-movementY ^js event))]
raw-pt (dom/get-client-position ^js event)
pt (translate-point-to-viewport raw-pt)
;; We calculate the delta because Safari's MouseEvent.movementX/Y drop
;; events
delta (if @last-position
(gpt/subtract raw-pt @last-position)
(gpt/point 0 0))]
(reset! last-position raw-pt)
(st/emit! (ms/->PointerEvent :delta delta
(kbd/ctrl? event)
(kbd/shift? event)

View file

@ -245,3 +245,6 @@
(defn ^boolean class? [node class-name]
(let [class-list (.-classList ^js node)]
(.contains ^js class-list class-name)))
(defn get-user-agent []
(.-userAgent js/navigator))