0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-24 07:29:08 -05:00

🔧 Minor refactor on text shapes.

This commit is contained in:
Andrey Antukh 2019-07-22 12:40:34 +02:00
parent 2b81832b67
commit 54809d05e2

View file

@ -5,22 +5,22 @@
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz> ;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.main.ui.shapes.text (ns uxbox.main.ui.shapes.text
(:require [cuerdas.core :as str] (:require
[lentes.core :as l] [cuerdas.core :as str]
[goog.events :as events] [goog.events :as events]
[potok.core :as ptk] [lentes.core :as l]
[uxbox.main.store :as st] [rumext.core :as mx]
[uxbox.main.geom :as geom] [rumext.alpha :as mf]
[uxbox.main.refs :as refs] [uxbox.main.data.shapes :as uds]
[uxbox.main.data.shapes :as uds] [uxbox.main.geom :as geom]
[uxbox.main.ui.shapes.common :as common] [uxbox.main.refs :as refs]
[uxbox.main.ui.shapes.attrs :as attrs] [uxbox.main.store :as st]
[uxbox.util.color :as color] [uxbox.main.ui.shapes.attrs :as attrs]
[uxbox.util.data :refer [classnames normalize-props]] [uxbox.main.ui.shapes.common :as common]
[uxbox.util.dom :as dom] [uxbox.util.color :as color]
[uxbox.util.geom.matrix :as gmt] [uxbox.util.data :refer [classnames normalize-props]]
[rumext.core :as mx :include-macros true]) [uxbox.util.dom :as dom]
(:import goog.events.EventType)) [uxbox.util.geom.matrix :as gmt]))
;; --- Events ;; --- Events
@ -39,29 +39,29 @@
(declare text-shape-wrapper) (declare text-shape-wrapper)
(declare text-shape-edit) (declare text-shape-edit)
(mx/defcs text-component (mf/def text-component
{:mixins [mx/static mx/reactive]} :mixins [mf/memo mx/reactive]
[own {:keys [id x1 y1 content group] :as shape}] :render
(let [modifiers (mx/react (refs/selected-modifiers id)) (fn [own {:keys [id x1 y1 content group] :as shape}]
selected (mx/react refs/selected-shapes) (let [modifiers (mx/react (refs/selected-modifiers id))
edition? (= (mx/react refs/selected-edition) id) selected (mx/react refs/selected-shapes)
selected? (and (contains? selected id) edition? (= (mx/react refs/selected-edition) id)
(= (count selected) 1)) selected? (and (contains? selected id)
shape (assoc shape :modifiers modifiers)] (= (count selected) 1))
(letfn [(on-mouse-down [event] shape (assoc shape :modifiers modifiers)]
(handle-mouse-down event shape selected)) (letfn [(on-mouse-down [event]
(on-double-click [event] (handle-mouse-down event shape selected))
;; TODO: handle grouping event propagation (on-double-click [event]
;; TODO: handle actions locking properly ;; TODO: handle grouping event propagation
(dom/stop-propagation event) ;; TODO: handle actions locking properly
(st/emit! (uds/start-edition-mode id)))] (dom/stop-propagation event)
[:g.shape {:class (when selected? "selected") (st/emit! (uds/start-edition-mode id)))]
:ref "main" [:g.shape {:class (when selected? "selected")
:on-double-click on-double-click :on-double-click on-double-click
:on-mouse-down on-mouse-down} :on-mouse-down on-mouse-down}
(if edition? (if edition?
(text-shape-edit shape) (text-shape-edit shape)
(text-shape-wrapper shape))]))) (text-shape-wrapper shape))]))))
;; --- Text Styles Helpers ;; --- Text Styles Helpers
@ -104,97 +104,130 @@
;; --- Text Shape Edit ;; --- Text Shape Edit
(defn- text-shape-edit-did-mount (mf/def text-shape-edit
[own] :mixins [mf/memo]
(let [[shape] (::mx/props own)
dom (mx/ref-node own "container")]
(set! (.-textContent dom) (:content shape ""))
(.focus dom)
own))
(mx/defc text-shape-edit :init
{:did-mount text-shape-edit-did-mount (fn [own props]
:mixins [mx/static]} (assoc own ::container (mf/create-ref)))
[{:keys [id x1 y1 content] :as shape}]
(let [{:keys [width height]} (geom/size shape) :did-mount
style (make-style shape) (fn [own]
props {:x x1 :y y1 :width width :height height}] (let [shape (::mf/props own)
(letfn [(on-input [ev] dom (mx/ref-node (::container own))]
(let [content (dom/event->inner-text ev)] (set! (.-textContent dom) (:content shape ""))
(st/emit! (uds/update-text id content))))] (.focus dom)
[:foreignObject props own))
:render
(fn [own {:keys [id x1 y1 content] :as shape}]
(let [{:keys [width height]} (geom/size shape)
style (make-style shape)
on-input (fn [ev]
(let [content (dom/event->inner-text ev)]
(st/emit! (uds/update-text id content))))]
[:foreignObject {:x x1 :y y1 :width width :height height}
[:div {:style (normalize-props style) [:div {:style (normalize-props style)
:ref "container" :ref (::container own)
:on-input on-input :on-input on-input
:contentEditable true}]]))) :contentEditable true}]])))
;; --- Text Shape Wrapper ;; --- Text Shape Wrapper
;; NOTE: this is a hack for the browser rendering. (mf/def text-shape-wrapper
;; :mixins [mf/memo]
;; Without forcing rerender, when the shape is displaced :key-fn pr-str
;; 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.
(defn text-shape-wrapper-did-mount :init
[own] (fn [own props]
(let [[shape] (::mx/props own) (assoc own ::fobject (mf/create-ref)))
dom (mx/ref-node own "fobject")
html (dom/render-to-html (text-shape-html shape))] ;; NOTE: this is a hack for the browser rendering.
(set! (.-innerHTML dom) html)) ;;
;; 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 (dom/render-to-html (text-shape-html shape))]
(set! (.-innerHTML dom) html))
own) own)
(mx/defc text-shape-wrapper :render
{:did-mount text-shape-wrapper-did-mount (fn [own {:keys [id modifiers] :as shape}]
:key-fn #(pr-str %1)} (let [{:keys [displacement resize]} modifiers
[{:keys [id modifiers] :as shape}] xfmt (cond-> (gmt/matrix)
(let [{:keys [displacement resize]} modifiers displacement (gmt/multiply displacement)
xfmt (cond-> (gmt/matrix) resize (gmt/multiply resize))
displacement (gmt/multiply displacement)
resize (gmt/multiply resize))
{:keys [x1 y1 width height] :as shape} (-> (geom/transform shape xfmt) {:keys [x1 y1 width height] :as shape} (-> (geom/transform shape xfmt)
(geom/size)) (geom/size))
moving? (boolean displacement)] moving? (boolean displacement)]
[:foreignObject {:x x1 [:foreignObject {:x x1
:y y1 :y y1
:class (classnames :move-cursor moving?) :class (classnames :move-cursor moving?)
:id (str id) :id (str id)
:ref "fobject" :ref (::fobject own)
:width width :width width
:height height}])) :height height}])))
;; --- Text Shape Html ;; --- Text Shape Html
(mx/defc text-shape-html (mf/def text-shape-html
[{:keys [content] :as shape}] :mixins [mf/memo]
(let [style (make-style shape)] :render
[:div {:style style} content])) (fn [own {:keys [content] :as shape}]
(let [style (make-style shape)]
[:div {:style style} content])))
;; --- Text Shape Html ;; --- Text Shape Html
(mx/defc text-shape (mf/def text-shape
{:mixins [mx/static] :mixins [mf/memo]
:did-mount text-shape-wrapper-did-mount :key-fn pr-str
:key-fn #(pr-str %1)}
[{: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) :init
(geom/size)) (fn [own props]
moving? (boolean displacement) (assoc own ::fobject (mf/create-ref)))
style (make-style shape)]
[:foreignObject {:x x1 ;; NOTE: this is a hack for the browser rendering.
:y y1 ;;
:class (classnames :move-cursor moving?) ;; Without forcing rerender, when the shape is displaced
:id (str id) ;; and only x and y attrs are updated in dom, the whole content
:ref "fobject" ;; of the foreignObject becomes sometimes partially or
:width width ;; completelly invisible. The complete dom rerender fixes that
:height height} ;; problem.
[:div {:style style}
[:p content]]])) :did-mount
(fn [own]
(let [shape (::mf/props own)
dom (mf/ref-node (::fobject own))
html (dom/render-to-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]]])))