mirror of
https://github.com/penpot/penpot.git
synced 2025-05-18 09:16:10 +02:00
159 lines
5 KiB
Clojure
159 lines
5 KiB
Clojure
(ns uxbox.ui.shapes.text
|
|
(:require [sablono.core :refer-macros [html]]
|
|
[cuerdas.core :as str]
|
|
[rum.core :as rum]
|
|
[lentes.core :as l]
|
|
[goog.events :as events]
|
|
[uxbox.rstore :as rs]
|
|
[uxbox.state :as st]
|
|
[uxbox.shapes :as ush]
|
|
[uxbox.data.workspace :as dw]
|
|
[uxbox.ui.core :as uuc]
|
|
[uxbox.ui.mixins :as mx]
|
|
[uxbox.ui.keyboard :as kbd]
|
|
[uxbox.ui.shapes.core :as uusc]
|
|
[uxbox.ui.shapes.icon :as uusi]
|
|
[uxbox.util.dom :as dom])
|
|
(:import goog.events.EventType))
|
|
|
|
(defn on-mouse-down
|
|
[event own {:keys [id group] :as shape} selected]
|
|
(let [selected? (contains? selected id)
|
|
local (:rum/local own)]
|
|
(when-not (:blocked shape)
|
|
(cond
|
|
(:edition @local)
|
|
nil
|
|
|
|
(and group (:locked (ush/resolve-parent shape)))
|
|
nil
|
|
|
|
(and (not selected?) (empty? selected))
|
|
(do
|
|
(dom/stop-propagation event)
|
|
(uuc/acquire-action! :shape/movement)
|
|
(rs/emit! (dw/select-shape id)))
|
|
|
|
(and (not selected?) (not (empty? selected)))
|
|
(do
|
|
(dom/stop-propagation event)
|
|
(if (kbd/shift? event)
|
|
(rs/emit! (dw/select-shape id))
|
|
(rs/emit! (dw/deselect-all)
|
|
(dw/select-shape id))))
|
|
|
|
:else
|
|
(do
|
|
(dom/stop-propagation event)
|
|
(uuc/acquire-action! :shape/movement))))))
|
|
|
|
(defn on-mouse-up
|
|
[event {:keys [id group] :as shape}]
|
|
(cond
|
|
(and group (:locked (ush/resolve-parent shape)))
|
|
nil
|
|
|
|
:else
|
|
(do
|
|
(dom/stop-propagation event)
|
|
(uuc/release-action! :draw/selrect)
|
|
(uuc/release-action! :shape/movement))))
|
|
|
|
(defn- text-component-did-mount
|
|
[own]
|
|
(letfn [(on-double-click [ev]
|
|
(let [container (mx/get-ref-dom own "container")
|
|
local (:rum/local own)]
|
|
(swap! local assoc :edition true)
|
|
(uuc/acquire-action! ::edition)
|
|
(set! (.-contentEditable container) true)
|
|
(.setAttribute container "contenteditable" "true")
|
|
(.focus container)))
|
|
(on-blur [ev]
|
|
(let [container (mx/get-ref-dom own "container")
|
|
local (:rum/local own)]
|
|
(uuc/release-action! ::edition)
|
|
(swap! local assoc :edition false)
|
|
(set! (.-contentEditable container) false)
|
|
(.removeAttribute container "contenteditable")))]
|
|
|
|
(let [dom (mx/get-ref-dom own "main")
|
|
dom2 (mx/get-ref-dom own "container")
|
|
key1 (events/listen dom EventType.DBLCLICK on-double-click)
|
|
key2 (events/listen dom2 EventType.BLUR on-blur)]
|
|
(assoc own ::key1 key1))))
|
|
|
|
(defn- text-component-will-unmount
|
|
[own]
|
|
(let [key1 (::key1 own)
|
|
key2 (::key2 own)]
|
|
(events/unlistenByKey key1)
|
|
(events/unlistenByKey key2)
|
|
(dissoc own ::key1 ::key2)))
|
|
|
|
(defn- text-component-transfer-state
|
|
[old-own own]
|
|
(let [data (select-keys old-own [::key1 ::key2])]
|
|
(merge own data)))
|
|
|
|
(defn- text-component-render
|
|
[own shape]
|
|
(let [{:keys [id x1 y1 content group]} shape
|
|
selected (rum/react uusc/selected-shapes-l)
|
|
selected? (and (contains? selected id) (= (count selected) 1))
|
|
on-mouse-down #(on-mouse-down % own shape selected)
|
|
on-mouse-up #(on-mouse-up % shape)
|
|
local (:rum/local own)]
|
|
(html
|
|
[:g.shape {:class (when selected? "selected")
|
|
;; :on-double-click #(on-double-click own %)
|
|
:ref "main"
|
|
:on-mouse-down on-mouse-down
|
|
:on-mouse-up on-mouse-up}
|
|
(uusc/render-shape (assoc shape :editing? (:edition @local false)) nil)
|
|
(when (and selected? (not (:edition @local false)))
|
|
(uusi/handlers shape))])))
|
|
|
|
(def ^:const text-component
|
|
(mx/component
|
|
{:render text-component-render
|
|
:name "text-componet"
|
|
:did-mount text-component-did-mount
|
|
:will-unmount text-component-will-unmount
|
|
:transfer-state text-component-transfer-state
|
|
:mixins [mx/static rum/reactive (mx/local)]}))
|
|
|
|
(defmethod uusc/render-component :builtin/text
|
|
[own shape]
|
|
(text-component shape))
|
|
|
|
(def ^:const +select-rect-attrs+
|
|
{:stroke-dasharray "5,5"
|
|
:style {:stroke "#333" :fill "transparent"
|
|
:stroke-opacity "0.4"}})
|
|
|
|
(def ^:const +style-attrs+
|
|
[:font-size])
|
|
|
|
(defn- build-style
|
|
[{:keys [font-size]}]
|
|
(merge {} (when font-size {:fontSize (str font-size "px")})))
|
|
|
|
(defmethod uusc/render-shape :builtin/text
|
|
[{:keys [id x1 y1 x2 y2 content drawing? editing?] :as shape}]
|
|
(let [key (str id)
|
|
rfm (ush/transformation shape)
|
|
size (ush/size shape)
|
|
props {:x x1 :y y1
|
|
:transform (str rfm)}
|
|
attrs (merge props size)
|
|
style (build-style shape)]
|
|
|
|
(html
|
|
[:g
|
|
(if (or drawing? editing?)
|
|
[:g
|
|
[:rect (merge attrs +select-rect-attrs+)]])
|
|
[:foreignObject attrs
|
|
[:p {:ref "container" :style style} content]]])))
|
|
|