0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-04-01 09:31:26 -05:00

🐛 Fix problem when resizing texts inside groups

This commit is contained in:
alonso.torres 2022-01-04 14:19:21 +01:00
parent 6334520c66
commit 51ea354bcb
5 changed files with 250 additions and 150 deletions

View file

@ -35,6 +35,7 @@
- Fix problem with booleans [Taiga #2356](https://tree.taiga.io/project/penpot/issue/2356)
- Fix line-height/letter-spacing inputs behaviour [Taiga #2331](https://tree.taiga.io/project/penpot/issue/2331)
- Fix dotted style in strokes [Taiga #2312](https://tree.taiga.io/project/penpot/issue/2312)
- Fix problem when resizing texts inside groups [Taiga #2310](https://tree.taiga.io/project/penpot/issue/2310)
### :arrow_up: Deps updates
### :heart: Community contributions by (Thank you!)

View file

@ -451,9 +451,6 @@
rt-modif (:rotation modifiers)]
(cond-> (gmt/matrix)
(some? displacement)
(gmt/multiply displacement)
(some? resize-1)
(-> (gmt/translate origin-1)
(gmt/multiply resize-transform)
@ -468,6 +465,9 @@
(gmt/multiply resize-transform-inverse)
(gmt/translate (gpt/negate origin-2)))
(some? displacement)
(gmt/multiply displacement)
(some? rt-modif)
(-> (gmt/translate center)
(gmt/multiply (gmt/rotate-matrix rt-modif))

View file

@ -14,11 +14,10 @@
[cuerdas.core :as str]))
(defn generate-root-styles
[shape node]
[_shape node]
(let [valign (:vertical-align node "top")
width (some-> (:width shape) (+ 1))
base #js {:height (or (:height shape) "100%")
:width (or width "100%")
base #js {:height "100%"
:width "100%"
:fontFamily "sourcesanspro"}]
(cond-> base
(= valign "top") (obj/set! "justifyContent" "flex-start")

View file

@ -16,30 +16,54 @@
(defn- text-corrected-transform
"If we apply a scale directly to the texts it will show deformed so we need to create this
correction matrix to \"undo\" the resize but keep the other transformations."
[{:keys [points transform transform-inverse]} current-transform modifiers]
[{:keys [x y width height points transform transform-inverse] :as shape} current-transform modifiers]
(let [corner-pt (first points)
transform (or transform (gmt/matrix))
transform-inverse (or transform-inverse (gmt/matrix))
corner-pt (cond-> corner-pt (some? transform-inverse) (gpt/transform transform-inverse))
current-transform
(if (some? (:resize-vector modifiers))
(gmt/multiply
current-transform
transform
(gmt/scale-matrix (gpt/inverse (:resize-vector modifiers)) (gpt/transform corner-pt transform-inverse))
transform-inverse)
current-transform)
resize-x? (some? (:resize-vector modifiers))
resize-y? (some? (:resize-vector-2 modifiers))
current-transform
(if (some? (:resize-vector-2 modifiers))
(gmt/multiply
current-transform
transform
(gmt/scale-matrix (gpt/inverse (:resize-vector-2 modifiers)) (gpt/transform corner-pt transform-inverse))
transform-inverse)
current-transform)]
current-transform))
flip-x? (neg? (get-in modifiers [:resize-vector :x]))
flip-y? (or (neg? (get-in modifiers [:resize-vector :y]))
(neg? (get-in modifiers [:resize-vector-2 :y])))
result (cond-> (gmt/matrix)
(and (some? transform) (or resize-x? resize-y?))
(gmt/multiply transform)
resize-x?
(gmt/scale (gpt/inverse (:resize-vector modifiers)) corner-pt)
resize-y?
(gmt/scale (gpt/inverse (:resize-vector-2 modifiers)) corner-pt)
flip-x?
(gmt/scale (gpt/point -1 1) corner-pt)
flip-y?
(gmt/scale (gpt/point 1 -1) corner-pt)
(and (some? transform) (or resize-x? resize-y?))
(gmt/multiply transform-inverse))
[width height]
(if (or resize-x? resize-y?)
(let [pc (-> (gpt/point x y)
(gpt/transform transform)
(gpt/transform current-transform))
pw (-> (gpt/point (+ x width) y)
(gpt/transform transform)
(gpt/transform current-transform))
ph (-> (gpt/point x (+ y height))
(gpt/transform transform)
(gpt/transform current-transform))]
[(gpt/distance pc pw) (gpt/distance pc ph)])
[width height])]
[result width height]))
(defn get-nodes
"Retrieve the DOM nodes to apply the matrix transformation"
@ -48,6 +72,7 @@
frame? (= :frame type)
group? (= :group type)
text? (= :text type)
mask? (and group? masked-group?)
;; When the shape is a frame we maybe need to move its thumbnail
@ -68,6 +93,11 @@
group?
[]
text?
[shape-node
(dom/query shape-node "foreignObject")
(dom/query shape-node ".text-shape")]
:else
[shape-node])))
@ -76,11 +106,23 @@
(when-let [nodes (get-nodes shape)]
(let [transform (get transforms id)
modifiers (get-in modifiers [id :modifiers])
transform (case type
:text (text-corrected-transform shape transform modifiers)
transform)]
[text-transform text-width text-height]
(when (= :text type)
(text-corrected-transform shape transform modifiers))]
(doseq [node nodes]
(when (and (some? transform) (some? node))
(cond
(dom/class? node "text-shape")
(when (some? text-transform)
(dom/set-attribute node "transform" (str text-transform)))
(= (dom/get-tag-name node) "foreignObject")
(when (and (some? text-width) (some? text-height))
(dom/set-attribute node "width" text-width)
(dom/set-attribute node "height" text-height))
(and (some? transform) (some? node))
(dom/set-attribute node "transform" (str transform))))))))
(defn remove-transform [shapes]
@ -88,7 +130,13 @@
(when-let [nodes (get-nodes shape)]
(doseq [node nodes]
(when (some? node)
(dom/remove-attribute node "transform"))))))
(cond
(= (dom/get-tag-name node) "foreignObject")
;; The shape width/height will be automaticaly setup when the modifiers are applied
nil
:else
(dom/remove-attribute node "transform")))))))
(defn format-viewbox [vbox]
(str/join " " [(+ (:x vbox 0) (:left-offset vbox 0))

View file

@ -17,21 +17,24 @@
;; --- Deprecated methods
(defn event->inner-text
[e]
(.-innerText (.-target e)))
[^js e]
(when (some? e)
(.-innerText (.-target e))))
(defn event->value
[e]
(.-value (.-target e)))
[^js e]
(when (some? e)
(.-value (.-target e))))
(defn event->target
[e]
(.-target e))
[^js e]
(when (some? e)
(.-target e)))
;; --- New methods
(defn set-html-title
[title]
[^string title]
(set! (.-title globals/document) title))
(defn set-page-style
@ -61,98 +64,117 @@
(dom/getElement id))
(defn get-elements-by-tag
[node tag]
(.getElementsByTagName node tag))
[^js node tag]
(when (some? node)
(.getElementsByTagName node tag)))
(defn stop-propagation
[e]
(when e
(.stopPropagation e)))
[^js event]
(when event
(.stopPropagation event)))
(defn prevent-default
[e]
(when e
(.preventDefault e)))
[^js event]
(when event
(.preventDefault event)))
(defn get-target
"Extract the target from event instance."
[event]
(.-target event))
[^js event]
(when (some? event)
(.-target event)))
(defn get-current-target
"Extract the current target from event instance (different from target
when event triggered in a child of the subscribing element)."
[event]
(.-currentTarget event))
[^js event]
(when (some? event)
(.-currentTarget event)))
(defn get-parent
[dom]
(.-parentElement ^js dom))
[^js node]
(when (some? node)
(.-parentElement ^js node)))
(defn get-value
"Extract the value from dom node."
[node]
(.-value node))
[^js node]
(when (some? node)
(.-value node)))
(defn get-attribute
"Extract the value of one attribute of a dom node."
[node attr-name]
(.getAttribute ^js node attr-name))
[^js node ^string attr-name]
(when (some? node)
(.getAttribute ^js node attr-name)))
(def get-target-val (comp get-value get-target))
(defn click
"Click a node"
[node]
(.click node))
[^js node]
(when (some? node)
(.click node)))
(defn get-files
"Extract the files from dom node."
[node]
(array-seq (.-files node)))
[^js node]
(when (some? node)
(array-seq (.-files node))))
(defn checked?
"Check if the node that represents a radio
or checkbox is checked or not."
[node]
(.-checked node))
[^js node]
(when (some? node)
(.-checked node)))
(defn valid?
"Check if the node that is a form input
has a valid value, against html5 form validation
properties (required, min/max, pattern...)."
[node]
(.-valid (.-validity node)))
[^js node]
(when (some? node)
(when-let [validity (.-validity node)]
(.-valid validity))))
(defn set-validity!
"Manually set the validity status of a node that
is a form input. If the state is an empty string,
the input will be valid. If not, the string will
be set as the error message."
[node status]
(.setCustomValidity node status)
(.reportValidity node))
[^js node status]
(when (some? node)
(.setCustomValidity node status)
(.reportValidity node)))
(defn clean-value!
[node]
(set! (.-value node) ""))
[^js node]
(when (some? node)
(set! (.-value node) "")))
(defn set-value!
[node value]
(set! (.-value ^js node) value))
[^js node value]
(when (some? node)
(set! (.-value ^js node) value)))
(defn select-text!
[node]
(.select ^js node))
[^js node]
(when (some? node)
(.select ^js node)))
(defn ^boolean equals?
[node-a node-b]
(.isEqualNode ^js node-a node-b))
[^js node-a ^js node-b]
(or (and (nil? node-a) (nil? node-b))
(and (some? node-a)
(.isEqualNode ^js node-a node-b))))
(defn get-event-files
"Extract the files from event instance."
[event]
(get-files (get-target event)))
[^js event]
(when (some? event)
(get-files (get-target event))))
(defn create-element
([tag]
@ -161,50 +183,58 @@
(.createElementNS globals/document ns tag)))
(defn set-html!
[el html]
(set! (.-innerHTML el) html))
[^js el html]
(when (some? el)
(set! (.-innerHTML el) html)))
(defn append-child!
[el child]
(.appendChild ^js el child))
[^js el child]
(when (some? el)
(.appendChild ^js el child)))
(defn get-first-child
[el]
(.-firstChild el))
[^js el]
(when (some? el)
(.-firstChild el)))
(defn get-tag-name
[el]
(.-tagName el))
[^js el]
(when (some? el)
(.-tagName el)))
(defn get-outer-html
[el]
(.-outerHTML el))
[^js el]
(when (some? el)
(.-outerHTML el)))
(defn get-inner-text
[el]
(.-innerText el))
[^js el]
(when (some? el)
(.-innerText el)))
(defn query
[el query]
[^js el ^string query]
(when (some? el)
(.querySelector el query)))
(defn get-client-position
[event]
[^js event]
(let [x (.-clientX event)
y (.-clientY event)]
(gpt/point x y)))
(defn get-offset-position
[event]
(let [x (.-offsetX event)
y (.-offsetY event)]
(gpt/point x y)))
[^js event]
(when (some? event)
(let [x (.-offsetX event)
y (.-offsetY event)]
(gpt/point x y))))
(defn get-client-size
[node]
{:width (.-clientWidth ^js node)
:height (.-clientHeight ^js node)})
[^js node]
(when (some? node)
{:width (.-clientWidth ^js node)
:height (.-clientHeight ^js node)}))
(defn get-bounding-rect
[node]
@ -222,12 +252,12 @@
:height (.-innerHeight ^js js/window)})
(defn focus!
[node]
[^js node]
(when (some? node)
(.focus node)))
(defn blur!
[node]
[^js node]
(when (some? node)
(.blur node)))
@ -245,8 +275,9 @@
:hint "seems like the current browser does not support fullscreen api.")))
(defn ^boolean blob?
[v]
(instance? js/Blob v))
[^js v]
(when (some? v)
(instance? js/Blob v)))
(defn create-blob
"Create a blob from content."
@ -265,20 +296,24 @@
{:pre [(blob? b)]}
(js/URL.createObjectURL b))
(defn set-property! [node property value]
(.setAttribute node property value))
(defn set-property! [^js node property value]
(when (some? node)
(.setAttribute node property value)))
(defn set-text! [node text]
(set! (.-textContent node) text))
(defn set-text! [^js node text]
(when (some? node)
(set! (.-textContent node) text)))
(defn set-css-property! [node property value]
(.setProperty (.-style ^js node) property value))
(defn set-css-property! [^js node property value]
(when (some? node)
(.setProperty (.-style ^js node) property value)))
(defn capture-pointer [event]
(-> event get-target (.setPointerCapture (.-pointerId event))))
(defn capture-pointer [^js event]
(when (some? event)
(-> event get-target (.setPointerCapture (.-pointerId event)))))
(defn release-pointer [event]
(when (.-pointerId event)
(defn release-pointer [^js event]
(when (and (some? event) (.-pointerId event))
(-> event get-target (.releasePointerCapture (.-pointerId event)))))
(defn get-root []
@ -295,19 +330,23 @@
(partition 2 params))))
(defn ^boolean class? [node class-name]
(let [class-list (.-classList ^js node)]
(.contains ^js class-list class-name)))
(when (some? node)
(let [class-list (.-classList ^js node)]
(.contains ^js class-list class-name))))
(defn add-class! [node class-name]
(let [class-list (.-classList ^js node)]
(.add ^js class-list class-name)))
(defn add-class! [^js node class-name]
(when (some? node)
(let [class-list (.-classList ^js node)]
(.add ^js class-list class-name))))
(defn remove-class! [node class-name]
(let [class-list (.-classList ^js node)]
(.remove ^js class-list class-name)))
(defn remove-class! [^js node class-name]
(when (some? node)
(let [class-list (.-classList ^js node)]
(.remove ^js class-list class-name))))
(defn child? [node1 node2]
(.contains ^js node2 ^js node1))
(defn child? [^js node1 ^js node2]
(when (some? node1)
(.contains ^js node2 ^js node1)))
(defn get-user-agent []
(.-userAgent globals/navigator))
@ -315,11 +354,13 @@
(defn get-active []
(.-activeElement globals/document))
(defn active? [node]
(= (get-active) node))
(defn active? [^js node]
(when (some? node)
(= (get-active) node)))
(defn get-data [^js node ^string attr]
(.getAttribute node (str "data-" attr)))
(when (some? node)
(.getAttribute node (str "data-" attr))))
(defn mtype->extension [mtype]
;; https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types
@ -336,42 +377,53 @@
nil))
(defn set-attribute [^js node ^string attr value]
(.setAttribute node attr value))
(when (some? node)
(.setAttribute node attr value)))
(defn remove-attribute [^js node ^string attr]
(.removeAttribute node attr))
(when (some? node)
(.removeAttribute node attr)))
(defn get-scroll-pos
[element]
(.-scrollTop ^js element))
[^js element]
(when (some? element)
(.-scrollTop element)))
(defn set-scroll-pos!
[element scroll]
(obj/set! ^js element "scrollTop" scroll))
[^js element scroll]
(when (some? element)
(obj/set! element "scrollTop" scroll)))
(defn scroll-into-view!
([element]
(.scrollIntoView ^js element false))
([element scroll-top]
(.scrollIntoView ^js element scroll-top)))
([^js element]
(when (some? element)
(.scrollIntoView element false)))
([^js element scroll-top]
(when (some? element)
(.scrollIntoView element scroll-top))))
(defn scroll-into-view-if-needed!
([element]
(.scrollIntoViewIfNeeded ^js element false))
([element scroll-top]
(.scrollIntoViewIfNeeded ^js element scroll-top)))
([^js element]
(when (some? element)
(.scrollIntoViewIfNeeded ^js element false)))
([^js element scroll-top]
(when (some? element)
(.scrollIntoViewIfNeeded ^js element scroll-top))))
(defn is-in-viewport?
[element]
(let [rect (.getBoundingClientRect element)
height (or (.-innerHeight js/window)
(.. js/document -documentElement -clientHeight))
width (or (.-innerWidth js/window)
(.. js/document -documentElement -clientWidth))]
(and (>= (.-top rect) 0)
(>= (.-left rect) 0)
(<= (.-bottom rect) height)
(<= (.-right rect) width))))
[^js element]
(when (some? element)
(let [rect (.getBoundingClientRect element)
height (or (.-innerHeight js/window)
(.. js/document -documentElement -clientHeight))
width (or (.-innerWidth js/window)
(.. js/document -documentElement -clientWidth))]
(and (>= (.-top rect) 0)
(>= (.-left rect) 0)
(<= (.-bottom rect) height)
(<= (.-right rect) width)))))
(defn trigger-download-uri
[filename mtype uri]