mirror of
https://github.com/penpot/penpot.git
synced 2025-01-23 23:18:48 -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.text :as text]))
|
||||
|
||||
(defn- render-html
|
||||
[component]
|
||||
(.renderToStaticMarkup js/ReactDOMServer component))
|
||||
|
||||
(mf/defc background
|
||||
[]
|
||||
[:rect
|
||||
|
@ -51,15 +47,12 @@
|
|||
:circle [:& circle/circle-shape {:shape shape}])))
|
||||
|
||||
(mf/defc page-svg
|
||||
[{:keys [data width height] :as props}]
|
||||
[{:keys [data] :as props}]
|
||||
(let [shapes-by-id (:shapes-by-id data)
|
||||
shapes (map #(get shapes-by-id %) (:shapes data []))
|
||||
canvas (map #(get shapes-by-id %) (:canvas data []))
|
||||
dim (calculate-dimensions data)]
|
||||
[:svg {
|
||||
;; :width width
|
||||
;; :height height
|
||||
:view-box (str "0 0 " (:width dim) " " (:height dim))
|
||||
[:svg {:view-box (str "0 0 " (:width dim) " " (:height dim))
|
||||
:version "1.1"
|
||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||
:xmlns "http://www.w3.org/2000/svg"}
|
||||
|
@ -70,6 +63,10 @@
|
|||
(for [item shapes]
|
||||
[:& shape-wrapper {:shape item :key (:id item)}])]]))
|
||||
|
||||
;; (defn- render-html
|
||||
;; [component]
|
||||
;; (.renderToStaticMarkup js/ReactDOMServer component))
|
||||
|
||||
;; (defn render
|
||||
;; [{:keys [data] :as page}]
|
||||
;; (try
|
||||
|
|
|
@ -67,27 +67,12 @@
|
|||
|
||||
;; --- 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
|
||||
[{:keys [file] :as props}]
|
||||
[:div.grid-item-th
|
||||
[:& exports/page-svg {:data (:data file)
|
||||
:width "290"
|
||||
:height "150"}]])
|
||||
:width "290"
|
||||
:height "150"}]])
|
||||
|
||||
;; --- Grid Item
|
||||
|
||||
|
|
|
@ -60,17 +60,6 @@
|
|||
:dotted "5,5"
|
||||
: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
|
||||
[{:keys [stroke-style] :or {stroke-style :none} :as attrs}]
|
||||
(case stroke-style
|
||||
|
|
|
@ -18,18 +18,8 @@
|
|||
[uxbox.main.ui.shapes.attrs :as attrs]
|
||||
[uxbox.main.ui.shapes.common :as common]
|
||||
[uxbox.util.color :as color]
|
||||
[uxbox.util.data :refer [classnames normalize-props]]
|
||||
[uxbox.util.dom :as dom]
|
||||
[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
|
||||
[uxbox.util.geom.matrix :as gmt]))
|
||||
|
||||
;; --- Events
|
||||
|
||||
|
@ -44,8 +34,8 @@
|
|||
;; --- Text Wrapper
|
||||
|
||||
(declare text-shape-html)
|
||||
(declare text-shape-wrapper)
|
||||
(declare text-shape-edit)
|
||||
(declare text-shape)
|
||||
|
||||
(mf/defc text-wrapper
|
||||
[{:keys [shape] :as props}]
|
||||
|
@ -65,7 +55,7 @@
|
|||
:on-mouse-down on-mouse-down}
|
||||
(if edition?
|
||||
[:& text-shape-edit {:shape shape}]
|
||||
[:& text-shape-wrapper {:shape shape}])])))
|
||||
[:& text-shape {:shape shape}])])))
|
||||
|
||||
;; --- Text Styles Helpers
|
||||
|
||||
|
@ -79,7 +69,9 @@
|
|||
text-align
|
||||
line-height
|
||||
letter-spacing
|
||||
user-select]
|
||||
user-select
|
||||
width
|
||||
height]
|
||||
:or {fill-color "#000000"
|
||||
fill-opacity 1
|
||||
font-family "sourcesanspro"
|
||||
|
@ -94,17 +86,23 @@
|
|||
(let [color (-> fill-color
|
||||
(color/hex->rgba fill-opacity)
|
||||
(color/rgb->str))]
|
||||
(merge
|
||||
{:fontSize (str font-size "px")
|
||||
:color color
|
||||
:whiteSpace "pre-wrap"
|
||||
:textAlign text-align
|
||||
:fontFamily font-family
|
||||
:fontWeight font-weight
|
||||
:fontStyle font-style}
|
||||
(when user-select {:userSelect "auto"})
|
||||
(when line-height {:lineHeight line-height})
|
||||
(when letter-spacing {:letterSpacing letter-spacing}))))
|
||||
(rumext.util/map->obj
|
||||
(merge
|
||||
{:fontSize (str font-size "px")
|
||||
:color color
|
||||
:width width
|
||||
:height height
|
||||
:whiteSpace "pre-wrap"
|
||||
:textAlign text-align
|
||||
:fontFamily font-family
|
||||
:fontWeight font-weight
|
||||
:fontStyle font-style
|
||||
:margin "0px"
|
||||
:padding "0px"
|
||||
:border "0px"}
|
||||
(when user-select {:userSelect "auto"})
|
||||
(when line-height {:lineHeight line-height})
|
||||
(when letter-spacing {:letterSpacing letter-spacing})))))
|
||||
|
||||
;; --- Text Shape Edit
|
||||
|
||||
|
@ -123,115 +121,34 @@
|
|||
(.focus dom)
|
||||
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
|
||||
(fn [own {:keys [shape] :as props}]
|
||||
(let [{:keys [id x1 y1 content width height]} (geom/size shape)
|
||||
style (make-style shape)
|
||||
on-input (fn [ev]
|
||||
(let [content (dom/event->inner-text ev)]
|
||||
#_(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}]])))
|
||||
(let [{:keys [id x y content width height]} shape]
|
||||
[:foreignObject {:x x :y y :width width :height height}
|
||||
[:textarea {:style (make-style shape)
|
||||
:ref (::container own)}]])))
|
||||
|
||||
;; --- Text Shape Wrapper
|
||||
|
||||
(mf/def text-shape-wrapper
|
||||
:mixins [mf/memo]
|
||||
(mf/defc text-shape
|
||||
[{: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
|
||||
(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 (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)
|
||||
: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
|
||||
:height height}
|
||||
[:div {:style style}
|
||||
[:p content]]])))
|
||||
{:keys [x y width height content]} shape]
|
||||
[:foreignObject {:x x
|
||||
:y y
|
||||
:id (str id)
|
||||
:width width
|
||||
:height height}
|
||||
[:div {:style (make-style shape)} content]]))
|
||||
|
|
Loading…
Add table
Reference in a new issue