mirror of
https://github.com/penpot/penpot.git
synced 2025-02-03 04:49:03 -05:00
♻️ Refactor text shape.
This commit is contained in:
parent
020625392a
commit
b0da06bad4
4 changed files with 56 additions and 168 deletions
|
@ -18,10 +18,6 @@
|
||||||
[uxbox.main.ui.shapes.rect :as rect]
|
[uxbox.main.ui.shapes.rect :as rect]
|
||||||
[uxbox.main.ui.shapes.text :as text]))
|
[uxbox.main.ui.shapes.text :as text]))
|
||||||
|
|
||||||
(defn- render-html
|
|
||||||
[component]
|
|
||||||
(.renderToStaticMarkup js/ReactDOMServer component))
|
|
||||||
|
|
||||||
(mf/defc background
|
(mf/defc background
|
||||||
[]
|
[]
|
||||||
[:rect
|
[:rect
|
||||||
|
@ -51,15 +47,12 @@
|
||||||
:circle [:& circle/circle-shape {:shape shape}])))
|
:circle [:& circle/circle-shape {:shape shape}])))
|
||||||
|
|
||||||
(mf/defc page-svg
|
(mf/defc page-svg
|
||||||
[{:keys [data width height] :as props}]
|
[{:keys [data] :as props}]
|
||||||
(let [shapes-by-id (:shapes-by-id data)
|
(let [shapes-by-id (:shapes-by-id data)
|
||||||
shapes (map #(get shapes-by-id %) (:shapes data []))
|
shapes (map #(get shapes-by-id %) (:shapes data []))
|
||||||
canvas (map #(get shapes-by-id %) (:canvas data []))
|
canvas (map #(get shapes-by-id %) (:canvas data []))
|
||||||
dim (calculate-dimensions data)]
|
dim (calculate-dimensions data)]
|
||||||
[:svg {
|
[:svg {:view-box (str "0 0 " (:width dim) " " (:height dim))
|
||||||
;; :width width
|
|
||||||
;; :height height
|
|
||||||
:view-box (str "0 0 " (:width dim) " " (:height dim))
|
|
||||||
:version "1.1"
|
:version "1.1"
|
||||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||||
:xmlns "http://www.w3.org/2000/svg"}
|
:xmlns "http://www.w3.org/2000/svg"}
|
||||||
|
@ -70,6 +63,10 @@
|
||||||
(for [item shapes]
|
(for [item shapes]
|
||||||
[:& shape-wrapper {:shape item :key (:id item)}])]]))
|
[:& shape-wrapper {:shape item :key (:id item)}])]]))
|
||||||
|
|
||||||
|
;; (defn- render-html
|
||||||
|
;; [component]
|
||||||
|
;; (.renderToStaticMarkup js/ReactDOMServer component))
|
||||||
|
|
||||||
;; (defn render
|
;; (defn render
|
||||||
;; [{:keys [data] :as page}]
|
;; [{:keys [data] :as page}]
|
||||||
;; (try
|
;; (try
|
||||||
|
|
|
@ -67,21 +67,6 @@
|
||||||
|
|
||||||
;; --- Grid Item Thumbnail
|
;; --- Grid Item Thumbnail
|
||||||
|
|
||||||
;; (mf/defc grid-item-thumbnail
|
|
||||||
;; [{:keys [file] :as props}]
|
|
||||||
;; (let [url (mf/use-memo
|
|
||||||
;; {:fn #(let [content (exports/render file)
|
|
||||||
;; blob (js/Blob. #js [content] #js {:type "image/svg+xml"})]
|
|
||||||
;; (js/URL.createObjectURL blob))
|
|
||||||
;; :deps (mf/deps (:id file))})]
|
|
||||||
;; (mf/use-effect
|
|
||||||
;; {:fn (fn []
|
|
||||||
;; #(js/URL.revokeObjectURL url))
|
|
||||||
;; :deps (mf/deps (:id file))})
|
|
||||||
;; [:div.grid-item-th
|
|
||||||
;; [:img.img-th {:src url}]]))
|
|
||||||
|
|
||||||
|
|
||||||
(mf/defc grid-item-thumbnail
|
(mf/defc grid-item-thumbnail
|
||||||
[{:keys [file] :as props}]
|
[{:keys [file] :as props}]
|
||||||
[:div.grid-item-th
|
[:div.grid-item-th
|
||||||
|
|
|
@ -60,17 +60,6 @@
|
||||||
:dotted "5,5"
|
:dotted "5,5"
|
||||||
:dashed "10,10"))
|
:dashed "10,10"))
|
||||||
|
|
||||||
;; (defn- rename-attr
|
|
||||||
;; [[key value :as pair]]
|
|
||||||
;; (case key
|
|
||||||
;; :stroke-color [:stroke value]
|
|
||||||
;; :fill-color [:fill value]
|
|
||||||
;; pair))
|
|
||||||
|
|
||||||
;; (defn- rename-attrs
|
|
||||||
;; [attrs]
|
|
||||||
;; (into {} (map rename-attr) attrs))
|
|
||||||
|
|
||||||
(defn- transform-stroke-attrs
|
(defn- transform-stroke-attrs
|
||||||
[{:keys [stroke-style] :or {stroke-style :none} :as attrs}]
|
[{:keys [stroke-style] :or {stroke-style :none} :as attrs}]
|
||||||
(case stroke-style
|
(case stroke-style
|
||||||
|
|
|
@ -18,18 +18,8 @@
|
||||||
[uxbox.main.ui.shapes.attrs :as attrs]
|
[uxbox.main.ui.shapes.attrs :as attrs]
|
||||||
[uxbox.main.ui.shapes.common :as common]
|
[uxbox.main.ui.shapes.common :as common]
|
||||||
[uxbox.util.color :as color]
|
[uxbox.util.color :as color]
|
||||||
[uxbox.util.data :refer [classnames normalize-props]]
|
|
||||||
[uxbox.util.dom :as dom]
|
[uxbox.util.dom :as dom]
|
||||||
[uxbox.util.geom.matrix :as gmt]
|
[uxbox.util.geom.matrix :as gmt]))
|
||||||
[cljsjs.react.dom.server]))
|
|
||||||
|
|
||||||
(defn- render-html
|
|
||||||
[component]
|
|
||||||
(.renderToStaticMarkup js/ReactDOMServer component))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;; TODO: this code need a good refactor
|
|
||||||
|
|
||||||
;; --- Events
|
;; --- Events
|
||||||
|
|
||||||
|
@ -44,8 +34,8 @@
|
||||||
;; --- Text Wrapper
|
;; --- Text Wrapper
|
||||||
|
|
||||||
(declare text-shape-html)
|
(declare text-shape-html)
|
||||||
(declare text-shape-wrapper)
|
|
||||||
(declare text-shape-edit)
|
(declare text-shape-edit)
|
||||||
|
(declare text-shape)
|
||||||
|
|
||||||
(mf/defc text-wrapper
|
(mf/defc text-wrapper
|
||||||
[{:keys [shape] :as props}]
|
[{:keys [shape] :as props}]
|
||||||
|
@ -65,7 +55,7 @@
|
||||||
:on-mouse-down on-mouse-down}
|
:on-mouse-down on-mouse-down}
|
||||||
(if edition?
|
(if edition?
|
||||||
[:& text-shape-edit {:shape shape}]
|
[:& text-shape-edit {:shape shape}]
|
||||||
[:& text-shape-wrapper {:shape shape}])])))
|
[:& text-shape {:shape shape}])])))
|
||||||
|
|
||||||
;; --- Text Styles Helpers
|
;; --- Text Styles Helpers
|
||||||
|
|
||||||
|
@ -79,7 +69,9 @@
|
||||||
text-align
|
text-align
|
||||||
line-height
|
line-height
|
||||||
letter-spacing
|
letter-spacing
|
||||||
user-select]
|
user-select
|
||||||
|
width
|
||||||
|
height]
|
||||||
:or {fill-color "#000000"
|
:or {fill-color "#000000"
|
||||||
fill-opacity 1
|
fill-opacity 1
|
||||||
font-family "sourcesanspro"
|
font-family "sourcesanspro"
|
||||||
|
@ -94,17 +86,23 @@
|
||||||
(let [color (-> fill-color
|
(let [color (-> fill-color
|
||||||
(color/hex->rgba fill-opacity)
|
(color/hex->rgba fill-opacity)
|
||||||
(color/rgb->str))]
|
(color/rgb->str))]
|
||||||
|
(rumext.util/map->obj
|
||||||
(merge
|
(merge
|
||||||
{:fontSize (str font-size "px")
|
{:fontSize (str font-size "px")
|
||||||
:color color
|
:color color
|
||||||
|
:width width
|
||||||
|
:height height
|
||||||
:whiteSpace "pre-wrap"
|
:whiteSpace "pre-wrap"
|
||||||
:textAlign text-align
|
:textAlign text-align
|
||||||
:fontFamily font-family
|
:fontFamily font-family
|
||||||
:fontWeight font-weight
|
:fontWeight font-weight
|
||||||
:fontStyle font-style}
|
:fontStyle font-style
|
||||||
|
:margin "0px"
|
||||||
|
:padding "0px"
|
||||||
|
:border "0px"}
|
||||||
(when user-select {:userSelect "auto"})
|
(when user-select {:userSelect "auto"})
|
||||||
(when line-height {:lineHeight line-height})
|
(when line-height {:lineHeight line-height})
|
||||||
(when letter-spacing {:letterSpacing letter-spacing}))))
|
(when letter-spacing {:letterSpacing letter-spacing})))))
|
||||||
|
|
||||||
;; --- Text Shape Edit
|
;; --- Text Shape Edit
|
||||||
|
|
||||||
|
@ -123,115 +121,34 @@
|
||||||
(.focus dom)
|
(.focus dom)
|
||||||
own))
|
own))
|
||||||
|
|
||||||
|
:will-unmount
|
||||||
|
(fn [own]
|
||||||
|
(let [dom (mf/ref-val (::container own))
|
||||||
|
shape (get-in own [::mf/props :shape])
|
||||||
|
content (dom/get-value dom)]
|
||||||
|
(st/emit! (udw/update-shape (:id shape) {:content content}))
|
||||||
|
own))
|
||||||
|
|
||||||
:render
|
:render
|
||||||
(fn [own {:keys [shape] :as props}]
|
(fn [own {:keys [shape] :as props}]
|
||||||
(let [{:keys [id x1 y1 content width height]} (geom/size shape)
|
(let [{:keys [id x y content width height]} shape]
|
||||||
style (make-style shape)
|
[:foreignObject {:x x :y y :width width :height height}
|
||||||
on-input (fn [ev]
|
[:textarea {:style (make-style shape)
|
||||||
(let [content (dom/event->inner-text ev)]
|
:ref (::container own)}]])))
|
||||||
#_(st/emit! (udw/update-shape-attrs id {:content content}))))]
|
|
||||||
[:foreignObject {:x x1 :y y1 :width width :height height}
|
|
||||||
[:div {:style (normalize-props style)
|
|
||||||
:ref (::container own)
|
|
||||||
:on-input on-input
|
|
||||||
:contentEditable true}]])))
|
|
||||||
|
|
||||||
;; --- Text Shape Wrapper
|
;; --- Text Shape Wrapper
|
||||||
|
|
||||||
(mf/def text-shape-wrapper
|
(mf/defc text-shape
|
||||||
:mixins [mf/memo]
|
[{:keys [shape] :as props}]
|
||||||
|
(let [{:keys [id rotation modifier-mtx]} shape
|
||||||
|
shape (cond
|
||||||
|
(gmt/matrix? modifier-mtx) (geom/transform shape modifier-mtx)
|
||||||
|
:else shape)
|
||||||
|
|
||||||
:init
|
{:keys [x y width height content]} shape]
|
||||||
(fn [own props]
|
[:foreignObject {:x x
|
||||||
(assoc own ::fobject (mf/create-ref)))
|
:y y
|
||||||
|
|
||||||
;; NOTE: this is a hack for the browser rendering.
|
|
||||||
;;
|
|
||||||
;; Without forcing rerender, when the shape is displaced
|
|
||||||
;; and only x and y attrs are updated in dom, the whole content
|
|
||||||
;; of the foreignObject becomes sometimes partially or
|
|
||||||
;; completelly invisible. The complete dom rerender fixes that
|
|
||||||
;; problem.
|
|
||||||
|
|
||||||
:did-mount
|
|
||||||
(fn [own]
|
|
||||||
(let [shape (get-in own [::mf/props :shape])
|
|
||||||
dom (mf/ref-node (::fobject own))
|
|
||||||
html (render-html (text-shape-html shape))]
|
|
||||||
(set! (.-innerHTML dom) html))
|
|
||||||
own)
|
|
||||||
|
|
||||||
:render
|
|
||||||
(fn [own {:keys [shape] :as props}]
|
|
||||||
(let [{:keys [id modifiers]} shape
|
|
||||||
{:keys [displacement resize]} modifiers
|
|
||||||
xfmt (cond-> (gmt/matrix)
|
|
||||||
displacement (gmt/multiply displacement)
|
|
||||||
resize (gmt/multiply resize))
|
|
||||||
|
|
||||||
{:keys [x1 y1 width height] :as shape} (-> (geom/transform shape xfmt)
|
|
||||||
(geom/size))
|
|
||||||
moving? (boolean displacement)]
|
|
||||||
[:foreignObject {:x x1
|
|
||||||
:y y1
|
|
||||||
:class (classnames :move-cursor moving?)
|
|
||||||
:id (str id)
|
:id (str id)
|
||||||
:ref (::fobject own)
|
|
||||||
:width width
|
|
||||||
:height height}])))
|
|
||||||
|
|
||||||
;; --- Text Shape Html
|
|
||||||
|
|
||||||
(mf/def text-shape-html
|
|
||||||
:mixins [mf/memo]
|
|
||||||
:render
|
|
||||||
(fn [own {:keys [content] :as shape}]
|
|
||||||
(let [style (make-style shape)]
|
|
||||||
[:div {:style style} content])))
|
|
||||||
|
|
||||||
;; --- Text Shape Html
|
|
||||||
|
|
||||||
(mf/def text-shape
|
|
||||||
:mixins [mf/memo]
|
|
||||||
:key-fn pr-str
|
|
||||||
|
|
||||||
:init
|
|
||||||
(fn [own props]
|
|
||||||
(assoc own ::fobject (mf/create-ref)))
|
|
||||||
|
|
||||||
;; NOTE: this is a hack for the browser rendering.
|
|
||||||
;;
|
|
||||||
;; Without forcing rerender, when the shape is displaced
|
|
||||||
;; and only x and y attrs are updated in dom, the whole content
|
|
||||||
;; of the foreignObject becomes sometimes partially or
|
|
||||||
;; completelly invisible. The complete dom rerender fixes that
|
|
||||||
;; problem.
|
|
||||||
|
|
||||||
:did-mount
|
|
||||||
(fn [own]
|
|
||||||
(let [shape (::mf/props own)
|
|
||||||
dom (mf/ref-node (::fobject own))
|
|
||||||
html (render-html (text-shape-html shape))]
|
|
||||||
(set! (.-innerHTML dom) html))
|
|
||||||
own)
|
|
||||||
|
|
||||||
:render
|
|
||||||
(fn [own {:keys [id content modifiers] :as shape}]
|
|
||||||
(let [{:keys [displacement resize]} modifiers
|
|
||||||
xfmt (cond-> (gmt/matrix)
|
|
||||||
displacement (gmt/multiply displacement)
|
|
||||||
resize (gmt/multiply resize))
|
|
||||||
|
|
||||||
{:keys [x1 y1 width height] :as shape} (-> (geom/transform shape xfmt)
|
|
||||||
(geom/size))
|
|
||||||
moving? (boolean displacement)
|
|
||||||
style (make-style shape)]
|
|
||||||
[:foreignObject {:x x1
|
|
||||||
:y y1
|
|
||||||
:class (classnames :move-cursor moving?)
|
|
||||||
:id (str id)
|
|
||||||
:ref (::fobject own)
|
|
||||||
:width width
|
:width width
|
||||||
:height height}
|
:height height}
|
||||||
[:div {:style style}
|
[:div {:style (make-style shape)} content]]))
|
||||||
[:p content]]])))
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue