mirror of
https://github.com/penpot/penpot.git
synced 2025-05-18 14:46:10 +02:00
♻️ Refactor texts.
This commit is contained in:
parent
07981487bf
commit
51c39d169f
4 changed files with 401 additions and 440 deletions
|
@ -12,8 +12,6 @@
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[cljs.spec.alpha :as s]
|
[cljs.spec.alpha :as s]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
[goog.events :as events]
|
|
||||||
[goog.object :as gobj]
|
|
||||||
[potok.core :as ptk]
|
[potok.core :as ptk]
|
||||||
[uxbox.common.data :as d]
|
[uxbox.common.data :as d]
|
||||||
[uxbox.common.exceptions :as ex]
|
[uxbox.common.exceptions :as ex]
|
||||||
|
|
|
@ -9,23 +9,27 @@
|
||||||
|
|
||||||
(ns uxbox.main.data.workspace.texts
|
(ns uxbox.main.data.workspace.texts
|
||||||
(:require
|
(:require
|
||||||
[beicon.core :as rx]
|
[clojure.walk :as walk]
|
||||||
[cljs.spec.alpha :as s]
|
[cljs.spec.alpha :as s]
|
||||||
[clojure.set :as set]
|
|
||||||
[goog.events :as events]
|
|
||||||
[goog.object :as gobj]
|
[goog.object :as gobj]
|
||||||
[potok.core :as ptk]
|
[potok.core :as ptk]
|
||||||
[uxbox.util.object :as obj]
|
[uxbox.util.object :as obj]
|
||||||
[uxbox.main.fonts :as fonts]
|
[uxbox.main.fonts :as fonts]
|
||||||
|
[uxbox.main.data.workspace.common :as dwc]
|
||||||
|
["slate-react" :as rslate]
|
||||||
["slate" :as slate :refer [Editor Transforms Text]]))
|
["slate" :as slate :refer [Editor Transforms Text]]))
|
||||||
|
|
||||||
|
(defn create-editor
|
||||||
|
[]
|
||||||
|
(rslate/withReact (slate/createEditor)))
|
||||||
|
|
||||||
(defn assign-editor
|
(defn assign-editor
|
||||||
[editor]
|
[id editor]
|
||||||
(ptk/reify ::assign-editor
|
(ptk/reify ::assign-editor
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(-> state
|
(-> state
|
||||||
(assoc-in [:workspace-local :editor] editor)
|
(assoc-in [:workspace-local :editors id] editor)
|
||||||
(update-in [:workspace-local :editor-n] (fnil inc 0))))))
|
(update-in [:workspace-local :editor-n] (fnil inc 0))))))
|
||||||
|
|
||||||
;; --- Helpers
|
;; --- Helpers
|
||||||
|
@ -39,222 +43,128 @@
|
||||||
:focus #js {:path #js [0 0 (dec (alength paragraphs))]
|
:focus #js {:path #js [0 0 (dec (alength paragraphs))]
|
||||||
:offset 1}}))
|
:offset 1}}))
|
||||||
|
|
||||||
(defn set-nodes!
|
(defn- editor-set!
|
||||||
([editor props]
|
([editor props]
|
||||||
(set-nodes! editor props #js {}))
|
(editor-set! editor props #js {}))
|
||||||
([editor props options]
|
([editor props options]
|
||||||
(when (and (nil? (obj/get editor "selection"))
|
|
||||||
(nil? (obj/get options "at")))
|
|
||||||
(obj/set! options "at" (calculate-full-selection editor)))
|
|
||||||
(.setNodes Transforms editor props options)
|
(.setNodes Transforms editor props options)
|
||||||
editor))
|
editor))
|
||||||
|
|
||||||
(defn is-text?
|
(defn- transform-nodes
|
||||||
[v]
|
[pred transform data]
|
||||||
(.isText Text v))
|
(walk/postwalk
|
||||||
|
(fn [item]
|
||||||
|
(if (and (map? item) (pred item))
|
||||||
|
(transform item)
|
||||||
|
item))
|
||||||
|
data))
|
||||||
|
|
||||||
(defn is-paragraph?
|
;; --- Editor Related Helpers
|
||||||
[v]
|
|
||||||
(= (.-type v) "paragraph"))
|
|
||||||
|
|
||||||
;; --- Predicates
|
(defn- ^boolean is-text-node?
|
||||||
|
[node]
|
||||||
|
(cond
|
||||||
|
(object? node) (.isText Text node)
|
||||||
|
(map? node) (string? (:text node))
|
||||||
|
:else (throw (ex-info "unexpected type" {:node node}))))
|
||||||
|
|
||||||
(defn enabled?
|
(defn- ^boolean is-paragraph-node?
|
||||||
[editor universal? pred]
|
[node]
|
||||||
(when editor
|
(cond
|
||||||
(let [result (.nodes Editor editor #js {:match pred :universal universal?})
|
(object? node) (= (.-type node) "paragraph")
|
||||||
match (first (es6-iterator-seq result))]
|
(map? node) (= "paragraph" (:type node))
|
||||||
(array? match))))
|
:else (throw (ex-info "unexpected type" {:node node}))))
|
||||||
|
|
||||||
(defn text-decoration-enabled?
|
(defn- ^boolean is-root-node?
|
||||||
[editor type]
|
[node]
|
||||||
(enabled? editor true
|
(cond
|
||||||
(fn [v]
|
(object? node) (= (.-type node) "root")
|
||||||
(let [val (obj/get v "textDecoration")]
|
(map? node) (= "root" (:type node))
|
||||||
(identical? type val)))))
|
:else (throw (ex-info "unexpected type" {:node node}))))
|
||||||
|
|
||||||
(defn text-transform-enabled?
|
(defn- editor-current-values
|
||||||
[editor type]
|
[editor pred attrs universal?]
|
||||||
(enabled? editor true
|
(let [options #js {:match pred :universal universal?}
|
||||||
(fn [v]
|
_ (when (nil? (obj/get editor "selection"))
|
||||||
(let [val (obj/get v "textTransform")]
|
(obj/set! options "at" (calculate-full-selection editor)))
|
||||||
(identical? type val)))))
|
result (.nodes Editor editor options)
|
||||||
|
match (ffirst (es6-iterator-seq result))]
|
||||||
|
(when (object? match)
|
||||||
|
(let [attrs (clj->js attrs)
|
||||||
|
result (areduce attrs i ret #js {}
|
||||||
|
(let [val (obj/get match (aget attrs i))]
|
||||||
|
(if val
|
||||||
|
(obj/set! ret (aget attrs i) val)
|
||||||
|
ret)))]
|
||||||
|
(js->clj result :keywordize-keys true)))))
|
||||||
|
|
||||||
(defn text-align-enabled?
|
(defn- nodes-seq
|
||||||
[editor type]
|
[match? node]
|
||||||
(enabled? editor false
|
(->> (tree-seq map? :children node)
|
||||||
(fn [v]
|
(filter match?)))
|
||||||
(let [val (obj/get v "textAlign")]
|
|
||||||
(identical? type val)))))
|
|
||||||
|
|
||||||
(defn vertical-align-enabled?
|
(defn- shape-current-values
|
||||||
[editor type]
|
[shape pred attrs]
|
||||||
(enabled? editor false
|
(let [root (:content shape)
|
||||||
(fn [v]
|
nodes (nodes-seq pred root)
|
||||||
(let [val (obj/get v "verticalAlign")]
|
match (first nodes)]
|
||||||
(identical? type val)))))
|
(when match
|
||||||
|
(select-keys match attrs))))
|
||||||
|
|
||||||
;; --- Getters
|
(defn current-text-values
|
||||||
|
[{:keys [editor default attrs shape]}]
|
||||||
|
(if editor
|
||||||
|
(editor-current-values editor is-text-node? attrs true)
|
||||||
|
(shape-current-values shape is-text-node? attrs)))
|
||||||
|
|
||||||
(defn current-value
|
(defn current-paragraph-values
|
||||||
[editor {:keys [universal?
|
[{:keys [editor attrs shape]}]
|
||||||
attr
|
(if editor
|
||||||
pred
|
(editor-current-values editor is-paragraph-node? attrs false)
|
||||||
at]
|
(shape-current-values shape is-paragraph-node? attrs)))
|
||||||
:as opts}]
|
|
||||||
(when editor
|
|
||||||
(let [options #js {:match pred :universal universal?}]
|
|
||||||
(cond
|
|
||||||
(object? at)
|
|
||||||
(obj/set! options "at" at)
|
|
||||||
|
|
||||||
(nil? (obj/get editor "selection"))
|
(defn current-root-values
|
||||||
(obj/set! options "at" (calculate-full-selection editor)))
|
[{:keys [editor attrs shape]}]
|
||||||
|
(if editor
|
||||||
|
(editor-current-values editor is-root-node? attrs false)
|
||||||
|
(shape-current-values shape is-root-node? attrs)))
|
||||||
|
|
||||||
(let [result (.nodes Editor editor options)
|
(defn- merge-attrs
|
||||||
match (ffirst (es6-iterator-seq result))]
|
[node attrs]
|
||||||
(when (object? match)
|
(reduce-kv (fn [node k v]
|
||||||
(obj/get match attr))))))
|
(if (nil? v)
|
||||||
|
(dissoc node k)
|
||||||
|
(assoc node k v)))
|
||||||
|
node
|
||||||
|
attrs))
|
||||||
|
|
||||||
(defn current-line-height
|
(defn- update-attrs
|
||||||
[editor {:keys [at default]}]
|
[{:keys [id editor attrs pred split]}]
|
||||||
(or (current-value editor {:at at
|
(if editor
|
||||||
:pred is-paragraph?
|
(ptk/reify ::update-attrs
|
||||||
:attr "lineHeight"
|
ptk/EffectEvent
|
||||||
:universal? false})
|
(effect [_ state stream]
|
||||||
default))
|
(editor-set! editor (clj->js attrs) #js {:match pred :split split})))
|
||||||
|
|
||||||
(defn current-letter-spacing
|
(ptk/reify ::update-attrs
|
||||||
[editor {:keys [at default]}]
|
dwc/IBatchedChange
|
||||||
(or (current-value editor {:at at
|
ptk/UpdateEvent
|
||||||
:pred is-text?
|
(update [_ state]
|
||||||
:attr "letterSpacing"
|
(let [page-id (get-in state [:workspace-page :id])
|
||||||
:universal? true})
|
merge-attrs #(merge-attrs % attrs)]
|
||||||
default))
|
(update-in state [:workspace-data page-id :objects id]
|
||||||
|
(fn [{:keys [type content] :as shape}]
|
||||||
|
(assert (= :text type) "should be shape type")
|
||||||
|
(update shape :content #(transform-nodes pred merge-attrs %)))))))))
|
||||||
|
|
||||||
|
(defn update-text-attrs
|
||||||
|
[options]
|
||||||
|
(update-attrs (assoc options :pred is-text-node? :split true)))
|
||||||
|
|
||||||
(defn current-font-family
|
(defn update-paragraph-attrs
|
||||||
[editor {:keys [at default]}]
|
[options]
|
||||||
(or (current-value editor {:at at
|
(update-attrs (assoc options :pred is-paragraph-node? :split false)))
|
||||||
:pred is-text?
|
|
||||||
:attr "fontId"
|
|
||||||
:universal? true})
|
|
||||||
default))
|
|
||||||
|
|
||||||
(defn current-font-size
|
(defn update-root-attrs
|
||||||
[editor {:keys [at default]}]
|
[options]
|
||||||
(or (current-value editor {:at at
|
(update-attrs (assoc options :pred is-root-node? :split false)))
|
||||||
:pred is-text?
|
|
||||||
:attr "fontSize"
|
|
||||||
:universal? true})
|
|
||||||
default))
|
|
||||||
|
|
||||||
|
|
||||||
(defn current-font-variant
|
|
||||||
[editor {:keys [at default]}]
|
|
||||||
(or (current-value editor {:at at
|
|
||||||
:pred is-text?
|
|
||||||
:attr "fontVariantId"
|
|
||||||
:universal? true})
|
|
||||||
default))
|
|
||||||
|
|
||||||
|
|
||||||
(defn current-fill
|
|
||||||
[editor {:keys [at default]}]
|
|
||||||
(or (current-value editor {:at at
|
|
||||||
:pred is-text?
|
|
||||||
:attr "fill"
|
|
||||||
:universal? true})
|
|
||||||
default))
|
|
||||||
|
|
||||||
|
|
||||||
(defn current-opacity
|
|
||||||
[editor {:keys [at default]}]
|
|
||||||
(or (current-value editor {:at at
|
|
||||||
:pred is-text?
|
|
||||||
:attr "opacity"
|
|
||||||
:universal? true})
|
|
||||||
default))
|
|
||||||
|
|
||||||
|
|
||||||
;; --- Setters
|
|
||||||
|
|
||||||
(defn set-text-decoration!
|
|
||||||
[editor type]
|
|
||||||
(set-nodes! editor
|
|
||||||
#js {:textDecoration type}
|
|
||||||
#js {:match is-text?
|
|
||||||
:split true}))
|
|
||||||
|
|
||||||
(defn set-text-align!
|
|
||||||
[editor type]
|
|
||||||
(set-nodes! editor
|
|
||||||
#js {:textAlign type}
|
|
||||||
#js {:match is-paragraph?}))
|
|
||||||
|
|
||||||
(defn set-text-transform!
|
|
||||||
[editor type]
|
|
||||||
(set-nodes! editor
|
|
||||||
#js {:textTransform type}
|
|
||||||
#js {:match is-text?
|
|
||||||
:split true}))
|
|
||||||
|
|
||||||
(defn set-vertical-align!
|
|
||||||
[editor type]
|
|
||||||
(set-nodes! editor
|
|
||||||
#js {:verticalAlign type}
|
|
||||||
#js {:match (fn [item]
|
|
||||||
(= "text-box" (obj/get item "type")))}))
|
|
||||||
|
|
||||||
(defn set-line-height!
|
|
||||||
[editor val at]
|
|
||||||
(set-nodes! editor
|
|
||||||
#js {:lineHeight val}
|
|
||||||
#js {:at at
|
|
||||||
:match is-paragraph?}))
|
|
||||||
|
|
||||||
(defn set-letter-spacing!
|
|
||||||
[editor val at]
|
|
||||||
(set-nodes! editor
|
|
||||||
#js {:letterSpacing val}
|
|
||||||
#js {:at at
|
|
||||||
:match is-text?
|
|
||||||
:split true}))
|
|
||||||
|
|
||||||
(defn set-font!
|
|
||||||
[editor id family]
|
|
||||||
(set-nodes! editor
|
|
||||||
#js {:fontId id
|
|
||||||
:fontFamily family}
|
|
||||||
#js {:match is-text?
|
|
||||||
:split true}))
|
|
||||||
|
|
||||||
(defn set-font-size!
|
|
||||||
[editor val]
|
|
||||||
(set-nodes! editor
|
|
||||||
#js {:fontSize val}
|
|
||||||
#js {:match is-text?
|
|
||||||
:split true}))
|
|
||||||
|
|
||||||
(defn set-font-variant!
|
|
||||||
[editor id weight style]
|
|
||||||
(set-nodes! editor
|
|
||||||
#js {:fontVariantId id
|
|
||||||
:fontWeight weight
|
|
||||||
:fontStyle style}
|
|
||||||
#js {:match is-text?
|
|
||||||
:split true}))
|
|
||||||
|
|
||||||
(defn set-fill!
|
|
||||||
[editor val]
|
|
||||||
(set-nodes! editor
|
|
||||||
#js {:fill val}
|
|
||||||
#js {:match is-text?
|
|
||||||
:split true}))
|
|
||||||
|
|
||||||
(defn set-opacity!
|
|
||||||
[editor val]
|
|
||||||
(set-nodes! editor
|
|
||||||
#js {:opacity val}
|
|
||||||
#js {:match is-text?
|
|
||||||
:split true}))
|
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
(when selected?
|
(when selected?
|
||||||
(st/emit! (dw/start-edition-mode (:id shape)))))]
|
(st/emit! (dw/start-edition-mode (:id shape)))))]
|
||||||
|
|
||||||
[:g.shape {:on-double-click on-double-click
|
[:g.shape {:on-double-click on-double-click
|
||||||
:on-mouse-down on-mouse-down
|
:on-mouse-down on-mouse-down
|
||||||
:on-context-menu on-context-menu}
|
:on-context-menu on-context-menu}
|
||||||
|
@ -71,11 +72,11 @@
|
||||||
[:& text-shape {:shape shape
|
[:& text-shape {:shape shape
|
||||||
:selected? selected?}])]))
|
:selected? selected?}])]))
|
||||||
|
|
||||||
;; --- Text Rendering
|
;; --- Text Editor Rendering
|
||||||
|
|
||||||
(defn- generate-text-box-styles
|
(defn- generate-root-styles
|
||||||
[data]
|
[data]
|
||||||
(let [valign (obj/get data "verticalAlign")
|
(let [valign (obj/get data "vertical-align")
|
||||||
base #js {:height "100%"
|
base #js {:height "100%"
|
||||||
:width "100%"
|
:width "100%"
|
||||||
:display "flex"}]
|
:display "flex"}]
|
||||||
|
@ -84,75 +85,31 @@
|
||||||
(= valign "center") (obj/set! "alignItems" "center")
|
(= valign "center") (obj/set! "alignItems" "center")
|
||||||
(= valign "bottom") (obj/set! "alignItems" "flex-end"))))
|
(= valign "bottom") (obj/set! "alignItems" "flex-end"))))
|
||||||
|
|
||||||
(mf/defc rt-text-box
|
|
||||||
{::mf/wrap-props false
|
|
||||||
::mf/wrap [mf/memo]}
|
|
||||||
[props]
|
|
||||||
(let [attrs (obj/get props "attributes")
|
|
||||||
childs (obj/get props "children")
|
|
||||||
data (obj/get props "element")
|
|
||||||
type (obj/get data "type")
|
|
||||||
style (generate-text-box-styles data)
|
|
||||||
attrs (obj/set! attrs "style" style)
|
|
||||||
attrs (obj/set! attrs "className" type)]
|
|
||||||
[:> :div attrs childs]))
|
|
||||||
|
|
||||||
(defn- generate-text-styles
|
|
||||||
[data]
|
|
||||||
(let [valign (obj/get data "verticalAlign")
|
|
||||||
base #js {:display "inline-block"
|
|
||||||
:width "100%"}]
|
|
||||||
base))
|
|
||||||
|
|
||||||
(mf/defc rt-text
|
|
||||||
{::mf/wrap-props false
|
|
||||||
::mf/wrap [mf/memo]}
|
|
||||||
[props]
|
|
||||||
(let [attrs (obj/get props "attributes")
|
|
||||||
childs (obj/get props "children")
|
|
||||||
data (obj/get props "element")
|
|
||||||
type (obj/get data "type")
|
|
||||||
style (generate-text-styles data)
|
|
||||||
attrs (obj/set! attrs "style" style)
|
|
||||||
attrs (obj/set! attrs "className" type)]
|
|
||||||
[:> :div attrs childs]))
|
|
||||||
|
|
||||||
(defn- generate-paragraph-styles
|
(defn- generate-paragraph-styles
|
||||||
[data]
|
[data]
|
||||||
(let [base #js {:fontSize "14px"
|
(let [base #js {:fontSize "14px"
|
||||||
:margin "inherit"
|
:margin "inherit"
|
||||||
:lineHeight "1.2"}
|
:lineHeight "1.2"}
|
||||||
lh (obj/get data "lineHeight")
|
lh (obj/get data "line-height")
|
||||||
ta (obj/get data "textAlign")]
|
ta (obj/get data "text-align")]
|
||||||
(cond-> base
|
(cond-> base
|
||||||
ta (obj/set! "textAlign" ta)
|
ta (obj/set! "textAlign" ta)
|
||||||
lh (obj/set! "lineHeight" lh))))
|
lh (obj/set! "lineHeight" lh))))
|
||||||
|
|
||||||
(mf/defc rt-pharagraph
|
(defn- generate-text-styles
|
||||||
{::mf/wrap-props false
|
|
||||||
::mf/wrap [mf/memo]}
|
|
||||||
[props]
|
|
||||||
(let [attrs (obj/get props "attributes")
|
|
||||||
childs (obj/get props "children")
|
|
||||||
data (obj/get props "element")
|
|
||||||
style (generate-paragraph-styles data)
|
|
||||||
attrs (obj/set! attrs "style" style)]
|
|
||||||
[:> :p attrs childs]))
|
|
||||||
|
|
||||||
(defn- generate-leaf-styles
|
|
||||||
[data]
|
[data]
|
||||||
(let [letter-spacing (obj/get data "letterSpacing")
|
(let [letter-spacing (obj/get data "letter-spacing")
|
||||||
text-decoration (obj/get data "textDecoration")
|
text-decoration (obj/get data "text-decoration")
|
||||||
text-transform (obj/get data "textTransform")
|
text-transform (obj/get data "text-transform")
|
||||||
|
|
||||||
font-id (obj/get data "fontId")
|
font-id (obj/get data "font-id")
|
||||||
font-variant-id (obj/get data "fontVariantId")
|
font-variant-id (obj/get data "font-variant-id")
|
||||||
|
|
||||||
font-family (obj/get data "fontFamily")
|
font-family (obj/get data "font-family")
|
||||||
font-size (obj/get data "fontSize")
|
font-size (obj/get data "font-size")
|
||||||
fill (obj/get data "fill")
|
fill (obj/get data "fill")
|
||||||
opacity (obj/get data "opacity")
|
opacity (obj/get data "opacity")
|
||||||
fontsdb (mf/deref fonts/fontsdb)
|
fontsdb (deref fonts/fontsdb)
|
||||||
|
|
||||||
base #js {:textDecoration text-decoration
|
base #js {:textDecoration text-decoration
|
||||||
:color fill
|
:color fill
|
||||||
|
@ -185,14 +142,50 @@
|
||||||
|
|
||||||
base))
|
base))
|
||||||
|
|
||||||
(mf/defc rt-leaf
|
|
||||||
|
(mf/defc editor-root-node
|
||||||
{::mf/wrap-props false
|
{::mf/wrap-props false
|
||||||
::mf/wrap [mf/memo]}
|
::mf/wrap [mf/memo]}
|
||||||
[props]
|
[props]
|
||||||
|
(let [attrs (obj/get props "attributes")
|
||||||
|
childs (obj/get props "children")
|
||||||
|
data (obj/get props "element")
|
||||||
|
type (obj/get data "type")
|
||||||
|
style (generate-root-styles data)
|
||||||
|
attrs (obj/set! attrs "style" style)
|
||||||
|
attrs (obj/set! attrs "className" type)]
|
||||||
|
[:> :div attrs childs]))
|
||||||
|
|
||||||
|
(mf/defc editor-paragraph-set-node
|
||||||
|
{::mf/wrap-props false}
|
||||||
|
[props]
|
||||||
|
(let [attrs (obj/get props "attributes")
|
||||||
|
childs (obj/get props "children")
|
||||||
|
data (obj/get props "element")
|
||||||
|
type (obj/get data "type")
|
||||||
|
style #js {:display "inline-block"
|
||||||
|
:width "100%"}
|
||||||
|
attrs (obj/set! attrs "style" style)
|
||||||
|
attrs (obj/set! attrs "className" type)]
|
||||||
|
[:> :div attrs childs]))
|
||||||
|
|
||||||
|
(mf/defc editor-paragraph-node
|
||||||
|
{::mf/wrap-props false}
|
||||||
|
[props]
|
||||||
|
(let [attrs (obj/get props "attributes")
|
||||||
|
childs (obj/get props "children")
|
||||||
|
data (obj/get props "element")
|
||||||
|
style (generate-paragraph-styles data)
|
||||||
|
attrs (obj/set! attrs "style" style)]
|
||||||
|
[:> :p attrs childs]))
|
||||||
|
|
||||||
|
(mf/defc editor-text-node
|
||||||
|
{::mf/wrap-props false}
|
||||||
|
[props]
|
||||||
(let [attrs (obj/get props "attributes")
|
(let [attrs (obj/get props "attributes")
|
||||||
childs (obj/get props "children")
|
childs (obj/get props "children")
|
||||||
data (obj/get props "leaf")
|
data (obj/get props "leaf")
|
||||||
style (generate-leaf-styles data)
|
style (generate-text-styles data)
|
||||||
attrs (obj/set! attrs "style" style)]
|
attrs (obj/set! attrs "style" style)]
|
||||||
[:> :span attrs childs]))
|
[:> :span attrs childs]))
|
||||||
|
|
||||||
|
@ -201,48 +194,44 @@
|
||||||
(mf/html
|
(mf/html
|
||||||
(let [element (obj/get props "element")]
|
(let [element (obj/get props "element")]
|
||||||
(case (obj/get element "type")
|
(case (obj/get element "type")
|
||||||
"text-box" [:> rt-text-box props]
|
"root" [:> editor-root-node props]
|
||||||
"text" [:> rt-text props]
|
"paragraph-set" [:> editor-paragraph-set-node props]
|
||||||
"paragraph" [:> rt-pharagraph props]
|
"paragraph" [:> editor-paragraph-node props]
|
||||||
nil))))
|
nil))))
|
||||||
|
|
||||||
(defn- render-leaf
|
(defn- render-text
|
||||||
[props]
|
[props]
|
||||||
(mf/html
|
(mf/html
|
||||||
[:> rt-leaf props]))
|
[:> editor-text-node props]))
|
||||||
|
|
||||||
;; --- Text Shape Edit
|
;; --- Text Shape Edit
|
||||||
|
|
||||||
(defn- initial-text
|
(defn- initial-text
|
||||||
([] (initial-text ""))
|
[text]
|
||||||
([text]
|
(clj->js
|
||||||
#js [#js {:type "text-box"
|
[{:type "root"
|
||||||
:children #js [#js {:type "text"
|
:children [{:type "paragraph-set"
|
||||||
:children #js [#js {:type "paragraph"
|
:children [{:type "paragraph"
|
||||||
:children #js [#js {:text text}]}]}]}]))
|
:children [{:text (or text "")}]}]}]}]))
|
||||||
(defn- parse-content
|
(defn- parse-content
|
||||||
[content]
|
[content]
|
||||||
(cond
|
(cond
|
||||||
(string? content) (initial-text content)
|
(string? content) (initial-text content)
|
||||||
(vector? content) (clj->js content)
|
(map? content) (clj->js [content])
|
||||||
(object? content) content
|
:else (initial-text "")))
|
||||||
:else (initial-text)))
|
|
||||||
|
|
||||||
(mf/defc text-shape-edit
|
(mf/defc text-shape-edit
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [shape] :as props}]
|
[{:keys [shape] :as props}]
|
||||||
(let [{:keys [id x y width height content]} shape
|
(let [{:keys [id x y width height content]} shape
|
||||||
|
|
||||||
state (mf/use-state #(parse-content content))
|
state (mf/use-state #(parse-content content))
|
||||||
value (mf/use-var @state)
|
editor (mf/use-memo #(dwt/create-editor))
|
||||||
|
|
||||||
editor (mf/use-memo #(rslate/withReact (slate/createEditor)))
|
|
||||||
self-ref (mf/use-ref)
|
self-ref (mf/use-ref)
|
||||||
|
|
||||||
on-close
|
on-close
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! dw/clear-edition-mode
|
(st/emit! dw/clear-edition-mode))
|
||||||
dw/deselect-all))
|
|
||||||
|
|
||||||
on-click
|
on-click
|
||||||
(fn [event]
|
(fn [event]
|
||||||
|
@ -264,22 +253,21 @@
|
||||||
|
|
||||||
on-mount
|
on-mount
|
||||||
(fn []
|
(fn []
|
||||||
(let [
|
(let [lkey1 (events/listen js/document EventType.CLICK on-click)
|
||||||
lkey1 (events/listen js/document EventType.CLICK on-click)
|
|
||||||
lkey2 (events/listen js/document EventType.KEYUP on-keyup)]
|
lkey2 (events/listen js/document EventType.KEYUP on-keyup)]
|
||||||
(st/emit! (dwt/assign-editor editor))
|
(st/emit! (dwt/assign-editor id editor))
|
||||||
#(let [content (js->clj @value)]
|
#(do
|
||||||
(st/emit! (dwt/assign-editor nil)
|
(st/emit! (dwt/assign-editor id nil))
|
||||||
(dw/update-shape id {:content content}))
|
|
||||||
(events/unlistenByKey lkey1)
|
(events/unlistenByKey lkey1)
|
||||||
(events/unlistenByKey lkey2))))
|
(events/unlistenByKey lkey2))))
|
||||||
|
|
||||||
on-change
|
on-change
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
(fn [val]
|
(fn [val]
|
||||||
(st/emit! (dwt/assign-editor editor))
|
(let [content (js->clj val :keywordize-keys true)
|
||||||
(reset! state val)
|
content (first content)]
|
||||||
(reset! value val)))]
|
(st/emit! (dw/update-shape id {:content content}))
|
||||||
|
(reset! state val))))]
|
||||||
|
|
||||||
(mf/use-effect on-mount)
|
(mf/use-effect on-mount)
|
||||||
|
|
||||||
|
@ -293,7 +281,7 @@
|
||||||
:spell-check "false"
|
:spell-check "false"
|
||||||
:class "rich-text"
|
:class "rich-text"
|
||||||
:render-element render-element
|
:render-element render-element
|
||||||
:render-leaf render-leaf
|
:render-leaf render-text
|
||||||
:on-blur (fn [event]
|
:on-blur (fn [event]
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
|
@ -303,43 +291,45 @@
|
||||||
|
|
||||||
;; --- Text Shape Wrapper
|
;; --- Text Shape Wrapper
|
||||||
|
|
||||||
|
(defn- render-text-node
|
||||||
|
([node] (render-text-node 0 node))
|
||||||
|
([index {:keys [type text children] :as node}]
|
||||||
|
(mf/html
|
||||||
|
(if (string? text)
|
||||||
|
(let [style (generate-text-styles (clj->js node))]
|
||||||
|
[:span {:style style :key index} text])
|
||||||
|
(let [children (map-indexed render-text-node children)]
|
||||||
|
(case type
|
||||||
|
"root"
|
||||||
|
(let [style (generate-root-styles (clj->js node))]
|
||||||
|
[:div.root.rich-text {:key index :style style} children])
|
||||||
|
|
||||||
|
"paragraph-set"
|
||||||
|
(let [style #js {:display "inline-block"
|
||||||
|
:width "100%"}]
|
||||||
|
[:div.paragraphs {:key index :style style} children])
|
||||||
|
|
||||||
|
"paragraph"
|
||||||
|
(let [style (generate-paragraph-styles (clj->js node))]
|
||||||
|
[:p {:key index :style style} children])
|
||||||
|
|
||||||
|
nil))))))
|
||||||
|
|
||||||
|
(mf/defc text-content
|
||||||
|
{::mf/wrap-props false
|
||||||
|
::mf/wrap [mf/memo]}
|
||||||
|
[props]
|
||||||
|
(let [root (obj/get props "content")]
|
||||||
|
(render-text-node root)))
|
||||||
|
|
||||||
(mf/defc text-shape
|
(mf/defc text-shape
|
||||||
[{:keys [shape selected?] :as props}]
|
[{:keys [shape selected?] :as props}]
|
||||||
(let [{:keys [id x y width height content]} shape
|
(let [{:keys [id x y width height rotation content]} shape]
|
||||||
content (parse-content content)
|
|
||||||
editor (mf/use-memo #(rslate/withReact (slate/createEditor)))
|
|
||||||
|
|
||||||
on-mount
|
|
||||||
(fn []
|
|
||||||
(when selected?
|
|
||||||
(st/emit! (dwt/assign-editor editor))
|
|
||||||
#(st/emit! (dwt/assign-editor nil))))
|
|
||||||
|
|
||||||
on-change
|
|
||||||
(mf/use-callback
|
|
||||||
(fn [val]
|
|
||||||
(let [content (js->clj val)]
|
|
||||||
(st/emit! (dw/update-shape id {:content content})))))
|
|
||||||
|
|
||||||
render-element (mf/use-callback render-element)
|
|
||||||
render-leaf (mf/use-callback render-leaf)]
|
|
||||||
|
|
||||||
(mf/use-effect (mf/deps id selected?) on-mount)
|
|
||||||
|
|
||||||
[:foreignObject {:x x
|
[:foreignObject {:x x
|
||||||
:y y
|
:y y
|
||||||
:transform (geom/transform-matrix shape)
|
:transform (geom/transform-matrix shape)
|
||||||
:id (str id)
|
:id (str id)
|
||||||
:width width
|
:width width
|
||||||
:height height}
|
:height height}
|
||||||
|
[:& text-content {:content (:content shape)}]]))
|
||||||
|
|
||||||
[:> rslate/Slate {:editor editor
|
|
||||||
:value content
|
|
||||||
:on-change on-change}
|
|
||||||
|
|
||||||
[:> rslate/Editable {:auto-focus "false"
|
|
||||||
:read-only "true"
|
|
||||||
:class "rich-text"
|
|
||||||
:render-element render-element
|
|
||||||
:render-leaf render-leaf
|
|
||||||
:placeholder "Type some text here..."}]]]))
|
|
||||||
|
|
|
@ -48,37 +48,64 @@
|
||||||
(mf/defc font-options
|
(mf/defc font-options
|
||||||
[{:keys [editor shape] :as props}]
|
[{:keys [editor shape] :as props}]
|
||||||
(let [selection (mf/use-ref)
|
(let [selection (mf/use-ref)
|
||||||
font-id (dwt/current-font-family editor {:default "sourcesanspro"})
|
|
||||||
font-size (dwt/current-font-size editor {:default "14"})
|
{:keys [font-id
|
||||||
font-var (dwt/current-font-variant editor {:default "regular"})
|
font-size
|
||||||
|
font-variant-id]
|
||||||
|
:or {font-id "sourcesanspro"
|
||||||
|
font-size "14"
|
||||||
|
font-variant-id "regular"}}
|
||||||
|
(dwt/current-text-values
|
||||||
|
{:editor editor
|
||||||
|
:shape shape
|
||||||
|
:attrs [:font-id
|
||||||
|
:font-size
|
||||||
|
:font-variant-id]})
|
||||||
|
|
||||||
fonts (mf/deref fonts/fontsdb)
|
fonts (mf/deref fonts/fontsdb)
|
||||||
font (get fonts font-id)
|
font (get fonts font-id)
|
||||||
|
|
||||||
|
change-font
|
||||||
|
(fn [id]
|
||||||
|
(st/emit! (dwt/update-text-attrs
|
||||||
|
{:id (:id shape)
|
||||||
|
:editor editor
|
||||||
|
:attrs {:font-id id
|
||||||
|
:font-family (:family (get fonts id))
|
||||||
|
:font-variant-id nil
|
||||||
|
:font-weight nil
|
||||||
|
:font-style nil}})))
|
||||||
|
|
||||||
on-font-family-change
|
on-font-family-change
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [id (-> (dom/get-target event)
|
(let [id (-> (dom/get-target event)
|
||||||
(dom/get-value))
|
(dom/get-value))
|
||||||
font (get fonts id)]
|
font (get fonts id)]
|
||||||
(fonts/ensure-loaded! id
|
(fonts/ensure-loaded! id (partial change-font id))))
|
||||||
#(do
|
|
||||||
(dwt/set-font! editor id (:family font))
|
|
||||||
(when (not= id font-id)
|
|
||||||
(dwt/set-font-variant! editor nil nil nil))))))
|
|
||||||
|
|
||||||
on-font-size-change
|
on-font-size-change
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [val (-> (dom/get-target event)
|
(let [val (-> (dom/get-target event)
|
||||||
(dom/get-value))]
|
(dom/get-value))]
|
||||||
(dwt/set-font-size! editor val)))
|
(st/emit! (dwt/update-text-attrs
|
||||||
|
{:id (:id shape)
|
||||||
|
:editor editor
|
||||||
|
:attrs {:font-size val}}))))
|
||||||
|
|
||||||
on-font-variant-change
|
on-font-variant-change
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [id (-> (dom/get-target event)
|
(let [id (-> (dom/get-target event)
|
||||||
(dom/get-value))
|
(dom/get-value))
|
||||||
variant (d/seek #(= id (:id %)) (:variants font))]
|
variant (d/seek #(= id (:id %)) (:variants font))]
|
||||||
(dwt/set-font! editor (:id font) (:family font))
|
|
||||||
(dwt/set-font-variant! editor id (:weight variant) (:style variant))))
|
(st/emit! (dwt/update-text-attrs
|
||||||
|
{:id (:id shape)
|
||||||
|
:editor editor
|
||||||
|
:attrs {:font-id (:id font)
|
||||||
|
:font-family (:family font)
|
||||||
|
:font-variant-id id
|
||||||
|
:font-weight (:weight variant)
|
||||||
|
:font-style (:style variant)}}))))
|
||||||
]
|
]
|
||||||
|
|
||||||
[:*
|
[:*
|
||||||
|
@ -109,7 +136,7 @@
|
||||||
:on-change on-font-size-change
|
:on-change on-font-size-change
|
||||||
}]]
|
}]]
|
||||||
|
|
||||||
[:select.input-select {:value font-var
|
[:select.input-select {:value font-variant-id
|
||||||
:on-change on-font-variant-change}
|
:on-change on-font-variant-change}
|
||||||
(for [variant (:variants font)]
|
(for [variant (:variants font)]
|
||||||
[:option {:value (:id variant)
|
[:option {:value (:id variant)
|
||||||
|
@ -118,48 +145,63 @@
|
||||||
|
|
||||||
|
|
||||||
(mf/defc text-align-options
|
(mf/defc text-align-options
|
||||||
[{:keys [editor locale] :as props}]
|
[{:keys [editor shape locale] :as props}]
|
||||||
(let [on-text-align-change
|
(let [{:keys [text-align]
|
||||||
(fn [event type]
|
:or {text-align "left"}}
|
||||||
(dwt/set-text-align! editor type))]
|
(dwt/current-paragraph-values
|
||||||
;; --- Align
|
{:editor editor
|
||||||
|
:shape shape
|
||||||
|
:attrs [:text-align]})
|
||||||
|
|
||||||
|
on-change
|
||||||
|
(fn [event type]
|
||||||
|
(st/emit! (dwt/update-paragraph-attrs
|
||||||
|
{:id (:id shape)
|
||||||
|
:editor editor
|
||||||
|
:attrs {:text-align type}})))]
|
||||||
|
|
||||||
|
;; --- Align
|
||||||
[:div.row-flex.align-icons
|
[:div.row-flex.align-icons
|
||||||
[:span.tooltip.tooltip-bottom
|
[:span.tooltip.tooltip-bottom
|
||||||
{:alt (t locale "workspace.options.font-options.align-left")
|
{:alt (t locale "workspace.options.font-options.align-left")
|
||||||
:class (dom/classnames
|
:class (dom/classnames :current (= "left" text-align))
|
||||||
:current (dwt/text-align-enabled? editor "left"))
|
:on-click #(on-change % "left")}
|
||||||
:on-click #(on-text-align-change % "left")}
|
|
||||||
i/text-align-left]
|
i/text-align-left]
|
||||||
[:span.tooltip.tooltip-bottom
|
[:span.tooltip.tooltip-bottom
|
||||||
{:alt (t locale "workspace.options.font-options.align-center")
|
{:alt (t locale "workspace.options.font-options.align-center")
|
||||||
:class (dom/classnames
|
:class (dom/classnames :current (= "center" text-align))
|
||||||
:current (dwt/text-align-enabled? editor "center"))
|
:on-click #(on-change % "center")}
|
||||||
:on-click #(on-text-align-change % "center")}
|
|
||||||
i/text-align-center]
|
i/text-align-center]
|
||||||
[:span.tooltip.tooltip-bottom
|
[:span.tooltip.tooltip-bottom
|
||||||
{:alt (t locale "workspace.options.font-options.align-right")
|
{:alt (t locale "workspace.options.font-options.align-right")
|
||||||
:class (dom/classnames
|
:class (dom/classnames :current (= "right" text-align))
|
||||||
:current (dwt/text-align-enabled? editor "right"))
|
:on-click #(on-change % "right")}
|
||||||
:on-click #(on-text-align-change % "right")}
|
|
||||||
i/text-align-right]
|
i/text-align-right]
|
||||||
[:span.tooltip.tooltip-bottom
|
[:span.tooltip.tooltip-bottom
|
||||||
{:alt (t locale "workspace.options.font-options.align-justify")
|
{:alt (t locale "workspace.options.font-options.align-justify")
|
||||||
:class (dom/classnames
|
:class (dom/classnames :current (= "justify" text-align))
|
||||||
:current (dwt/text-align-enabled? editor "justify"))
|
:on-click #(on-change % "justify")}
|
||||||
:on-click #(on-text-align-change % "justify")}
|
|
||||||
i/text-align-justify]]))
|
i/text-align-justify]]))
|
||||||
|
|
||||||
|
|
||||||
(mf/defc text-fill-options
|
(mf/defc text-fill-options
|
||||||
[{:keys [editor] :as props}]
|
[{:keys [editor shape] :as props}]
|
||||||
(let [color (dwt/current-fill editor {:default "#000000"})
|
(let [{:keys [fill opacity]
|
||||||
opacity (dwt/current-opacity editor {:default 1})
|
:or {fill "#000000"
|
||||||
|
opacity 1}}
|
||||||
|
(dwt/current-text-values
|
||||||
|
{:editor editor
|
||||||
|
:shape shape
|
||||||
|
:attrs [:fill :opacity]})
|
||||||
|
|
||||||
opacity (math/round (* opacity 100))
|
opacity (math/round (* opacity 100))
|
||||||
|
|
||||||
on-color-change
|
on-color-change
|
||||||
(fn [color]
|
(fn [color]
|
||||||
(dwt/set-fill! editor color))
|
(st/emit! (dwt/update-text-attrs
|
||||||
|
{:id (:id shape)
|
||||||
|
:editor editor
|
||||||
|
:attrs {:fill color}})))
|
||||||
|
|
||||||
on-color-input-change
|
on-color-input-change
|
||||||
(fn [event]
|
(fn [event]
|
||||||
|
@ -175,7 +217,10 @@
|
||||||
(when (str/numeric? value)
|
(when (str/numeric? value)
|
||||||
(let [value (-> (d/parse-integer value 1)
|
(let [value (-> (d/parse-integer value 1)
|
||||||
(/ 100))]
|
(/ 100))]
|
||||||
(dwt/set-opacity! editor value)))))
|
(st/emit! (dwt/update-text-attrs
|
||||||
|
{:id (:id shape)
|
||||||
|
:editor editor
|
||||||
|
:attrs {:opacity value}}))))))
|
||||||
|
|
||||||
show-color-picker
|
show-color-picker
|
||||||
(fn [event]
|
(fn [event]
|
||||||
|
@ -184,22 +229,22 @@
|
||||||
props {:x x :y y
|
props {:x x :y y
|
||||||
:on-change on-color-change
|
:on-change on-color-change
|
||||||
:default "#ffffff"
|
:default "#ffffff"
|
||||||
:value color
|
:value fill
|
||||||
:transparent? true}]
|
:transparent? true}]
|
||||||
(modal/show! colorpicker-modal props)))]
|
(modal/show! colorpicker-modal props)))]
|
||||||
|
|
||||||
[:div.row-flex.color-data
|
[:div.row-flex.color-data
|
||||||
[:span.color-th
|
[:span.color-th
|
||||||
{:style {:background-color color}
|
{:style {:background-color fill}
|
||||||
:on-click show-color-picker
|
:on-click show-color-picker
|
||||||
}]
|
}]
|
||||||
|
|
||||||
[:div.color-info
|
[:div.color-info
|
||||||
[:input {:default-value color
|
[:input {:default-value fill
|
||||||
:pattern "^#(?:[0-9a-fA-F]{3}){1,2}$"
|
:pattern "^#(?:[0-9a-fA-F]{3}){1,2}$"
|
||||||
:ref (fn [el]
|
:ref (fn [el]
|
||||||
(when el
|
(when el
|
||||||
(set! (.-value el) color)))
|
(set! (.-value el) fill)))
|
||||||
:on-change on-color-input-change
|
:on-change on-color-input-change
|
||||||
}]]
|
}]]
|
||||||
|
|
||||||
|
@ -222,12 +267,25 @@
|
||||||
}]]))
|
}]]))
|
||||||
|
|
||||||
(mf/defc spacing-options
|
(mf/defc spacing-options
|
||||||
[{:keys [editor locale] :as props}]
|
[{:keys [editor shape locale] :as props}]
|
||||||
(let [selection (mf/use-ref)
|
(let [{:keys [letter-spacing
|
||||||
lh (dwt/current-line-height editor {:default "1.2"
|
line-height]
|
||||||
:at (mf/ref-val selection)})
|
:or {line-height "1.2"
|
||||||
ls (dwt/current-letter-spacing editor {:default "0"
|
letter-spacing "0"}}
|
||||||
:at (mf/ref-val selection)})]
|
(dwt/current-text-values
|
||||||
|
{:editor editor
|
||||||
|
:shape shape
|
||||||
|
:attrs [:line-height
|
||||||
|
:letter-spacing]})
|
||||||
|
|
||||||
|
on-change
|
||||||
|
(fn [event attr]
|
||||||
|
(let [val (-> (dom/get-target event)
|
||||||
|
(dom/get-value))]
|
||||||
|
(st/emit! (dwt/update-text-attrs
|
||||||
|
{:id (:id shape)
|
||||||
|
:editor editor
|
||||||
|
:attrs {attr val}}))))]
|
||||||
[:div.row-flex
|
[:div.row-flex
|
||||||
[:div.input-icon
|
[:div.input-icon
|
||||||
[:span.icon-before.tooltip.tooltip-bottom
|
[:span.icon-before.tooltip.tooltip-bottom
|
||||||
|
@ -238,12 +296,9 @@
|
||||||
:step "0.1"
|
:step "0.1"
|
||||||
:min "0"
|
:min "0"
|
||||||
:max "200"
|
:max "200"
|
||||||
:value lh
|
:value line-height
|
||||||
:on-change (fn [event]
|
:on-change #(on-change % :line-height)}]]
|
||||||
(let [val (-> (dom/get-target event)
|
|
||||||
(dom/get-value))
|
|
||||||
sel (mf/ref-val selection)]
|
|
||||||
(dwt/set-line-height! editor val sel)))}]]
|
|
||||||
[:div.input-icon
|
[:div.input-icon
|
||||||
[:span.icon-before.tooltip.tooltip-bottom
|
[:span.icon-before.tooltip.tooltip-bottom
|
||||||
{:alt (t locale "workspace.options.font-options.letter-spacing")}
|
{:alt (t locale "workspace.options.font-options.letter-spacing")}
|
||||||
|
@ -253,12 +308,8 @@
|
||||||
:step "0.1"
|
:step "0.1"
|
||||||
:min "0"
|
:min "0"
|
||||||
:max "200"
|
:max "200"
|
||||||
:value ls
|
:value letter-spacing
|
||||||
:on-change (fn [event]
|
:on-change #(on-change % :letter-spacing)}]]]))
|
||||||
(let [val (-> (dom/get-target event)
|
|
||||||
(dom/get-value))
|
|
||||||
sel (mf/ref-val selection)]
|
|
||||||
(dwt/set-letter-spacing! editor val sel)))}]]]))
|
|
||||||
|
|
||||||
;; (mf/defc box-sizing-options
|
;; (mf/defc box-sizing-options
|
||||||
;; [{:keys [editor] :as props}]
|
;; [{:keys [editor] :as props}]
|
||||||
|
@ -274,126 +325,138 @@
|
||||||
;; i/auto-fix]])
|
;; i/auto-fix]])
|
||||||
|
|
||||||
(mf/defc vertical-align-options
|
(mf/defc vertical-align-options
|
||||||
[{:keys [editor locale] :as props}]
|
[{:keys [editor locale shape] :as props}]
|
||||||
(let [on-vertical-align-change
|
(let [{:keys [vertical-align]
|
||||||
|
:or {vertical-align "top"}}
|
||||||
|
(dwt/current-root-values
|
||||||
|
{:editor editor
|
||||||
|
:shape shape
|
||||||
|
:attrs [:vertical-align]})
|
||||||
|
|
||||||
|
on-change
|
||||||
(fn [event type]
|
(fn [event type]
|
||||||
(dwt/set-vertical-align! editor type))]
|
(st/emit! (dwt/update-root-attrs
|
||||||
|
{:id (:id shape)
|
||||||
|
:editor editor
|
||||||
|
:attrs {:vertical-align type}})))]
|
||||||
|
|
||||||
[:div.row-flex
|
[:div.row-flex
|
||||||
[:span.element-set-subtitle (t locale "workspace.options.font-options.vertical-align")]
|
[:span.element-set-subtitle (t locale "workspace.options.font-options.vertical-align")]
|
||||||
[:div.align-icons
|
[:div.align-icons
|
||||||
[:span.tooltip.tooltip-bottom
|
[:span.tooltip.tooltip-bottom
|
||||||
{:alt (t locale "workspace.options.font-options.align-top")
|
{:alt (t locale "workspace.options.font-options.align-top")
|
||||||
:class (dom/classnames
|
:class (dom/classnames :current (= "top" vertical-align))
|
||||||
:current (dwt/vertical-align-enabled? editor "top"))
|
:on-click #(on-change % "top")}
|
||||||
:on-click #(on-vertical-align-change % "top")}
|
|
||||||
i/align-top]
|
i/align-top]
|
||||||
[:span.tooltip.tooltip-bottom
|
[:span.tooltip.tooltip-bottom
|
||||||
{:alt (t locale "workspace.options.font-options.align-middle")
|
{:alt (t locale "workspace.options.font-options.align-middle")
|
||||||
:class (dom/classnames
|
:class (dom/classnames :current (= "center" vertical-align))
|
||||||
:current (dwt/vertical-align-enabled? editor "center"))
|
:on-click #(on-change % "center")}
|
||||||
:on-click #(on-vertical-align-change % "center")}
|
|
||||||
i/align-middle]
|
i/align-middle]
|
||||||
[:span.tooltip.tooltip-bottom
|
[:span.tooltip.tooltip-bottom
|
||||||
{:alt (t locale "workspace.options.font-options.align-bottom")
|
{:alt (t locale "workspace.options.font-options.align-bottom")
|
||||||
:class (dom/classnames
|
:class (dom/classnames :current (= "bottom" vertical-align))
|
||||||
:current (dwt/vertical-align-enabled? editor "bottom"))
|
:on-click #(on-change % "bottom")}
|
||||||
:on-click #(on-vertical-align-change % "bottom")}
|
|
||||||
i/align-bottom]]]))
|
i/align-bottom]]]))
|
||||||
|
|
||||||
(mf/defc text-decoration-options
|
(mf/defc text-decoration-options
|
||||||
[{:keys [editor locale] :as props}]
|
[{:keys [editor locale shape] :as props}]
|
||||||
(let [on-decoration-change
|
(let [{:keys [text-decoration]
|
||||||
|
:or {text-decoration "none"}}
|
||||||
|
(dwt/current-text-values
|
||||||
|
{:editor editor
|
||||||
|
:shape shape
|
||||||
|
:attrs [:text-decoration]})
|
||||||
|
|
||||||
|
on-change
|
||||||
(fn [event type]
|
(fn [event type]
|
||||||
(dom/prevent-default event)
|
(st/emit! (dwt/update-text-attrs
|
||||||
(dom/stop-propagation event)
|
{:id (:id shape)
|
||||||
(if (dwt/text-decoration-enabled? editor type)
|
:editor editor
|
||||||
(dwt/set-text-decoration! editor "none")
|
:attrs {:text-decoration type}})))]
|
||||||
(dwt/set-text-decoration! editor type)))]
|
|
||||||
[:div.row-flex
|
[:div.row-flex
|
||||||
[:span.element-set-subtitle (t locale "workspace.options.font-options.decoration")]
|
[:span.element-set-subtitle (t locale "workspace.options.font-options.decoration")]
|
||||||
[:div.align-icons
|
[:div.align-icons
|
||||||
[:span.tooltip.tooltip-bottom
|
[:span.tooltip.tooltip-bottom
|
||||||
{:alt (t locale "workspace.options.font-options.none")
|
{:alt (t locale "workspace.options.font-options.none")
|
||||||
:on-click #(on-decoration-change % "none")}
|
:class (dom/classnames :current (= "none" text-decoration))
|
||||||
|
:on-click #(on-change % "none")}
|
||||||
i/minus]
|
i/minus]
|
||||||
|
|
||||||
[:span.tooltip.tooltip-bottom
|
[:span.tooltip.tooltip-bottom
|
||||||
{:alt (t locale "workspace.options.font-options.underline")
|
{:alt (t locale "workspace.options.font-options.underline")
|
||||||
:class (dom/classnames
|
:class (dom/classnames :current (= "underline" text-decoration))
|
||||||
:current (dwt/text-decoration-enabled? editor "underline"))
|
:on-click #(on-change % "underline")}
|
||||||
:on-click #(on-decoration-change % "underline")}
|
|
||||||
i/underline]
|
i/underline]
|
||||||
|
|
||||||
[:span.tooltip.tooltip-bottom
|
[:span.tooltip.tooltip-bottom
|
||||||
{:alt (t locale "workspace.options.font-options.strikethrough")
|
{:alt (t locale "workspace.options.font-options.strikethrough")
|
||||||
:class (dom/classnames
|
:class (dom/classnames :current (= "line-through" text-decoration))
|
||||||
:current (dwt/text-decoration-enabled? editor "line-through"))
|
:on-click #(on-change % "line-through")}
|
||||||
:on-click #(on-decoration-change % "line-through")}
|
|
||||||
i/strikethrough]]]))
|
i/strikethrough]]]))
|
||||||
|
|
||||||
|
|
||||||
(mf/defc text-transform-options
|
(mf/defc text-transform-options
|
||||||
[{:keys [editor locale] :as props}]
|
[{:keys [editor locale shape] :as props}]
|
||||||
(let [on-text-transform-change
|
(let [{:keys [text-transform]
|
||||||
|
:or {text-transform "none"}}
|
||||||
|
(dwt/current-text-values
|
||||||
|
{:editor editor
|
||||||
|
:shape shape
|
||||||
|
:attrs [:text-transform]})
|
||||||
|
|
||||||
|
on-change
|
||||||
(fn [event type]
|
(fn [event type]
|
||||||
(dom/prevent-default event)
|
(st/emit! (dwt/update-text-attrs
|
||||||
(dom/stop-propagation event)
|
{:id (:id shape)
|
||||||
(if (dwt/text-transform-enabled? editor type)
|
:editor editor
|
||||||
(dwt/set-text-transform! editor "none")
|
:attrs {:text-transform type}})))]
|
||||||
(dwt/set-text-transform! editor type)))]
|
|
||||||
[:div.row-flex
|
[:div.row-flex
|
||||||
[:span.element-set-subtitle (t locale "workspace.options.font-options.text-case")]
|
[:span.element-set-subtitle (t locale "workspace.options.font-options.text-case")]
|
||||||
[:div.align-icons
|
[:div.align-icons
|
||||||
[:span.tooltip.tooltip-bottom
|
[:span.tooltip.tooltip-bottom
|
||||||
{:alt (t locale "workspace.options.font-options.none")
|
{:alt (t locale "workspace.options.font-options.none")
|
||||||
:class (dom/classnames
|
:class (dom/classnames :current (= "none" text-transform))
|
||||||
:current (dwt/text-transform-enabled? editor "none"))
|
:on-click #(on-change % "none")}
|
||||||
:on-click #(on-text-transform-change % "none")}
|
|
||||||
|
|
||||||
i/minus]
|
i/minus]
|
||||||
[:span.tooltip.tooltip-bottom
|
[:span.tooltip.tooltip-bottom
|
||||||
{:alt (t locale "workspace.options.font-options.uppercase")
|
{:alt (t locale "workspace.options.font-options.uppercase")
|
||||||
:class (dom/classnames
|
:class (dom/classnames :current (= "uppercase" text-transform))
|
||||||
:current (dwt/text-transform-enabled? editor "uppercase"))
|
:on-click #(on-change % "uppercase")}
|
||||||
:on-click #(on-text-transform-change % "uppercase")}
|
|
||||||
|
|
||||||
i/uppercase]
|
i/uppercase]
|
||||||
[:span.tooltip.tooltip-bottom
|
[:span.tooltip.tooltip-bottom
|
||||||
{:alt (t locale "workspace.options.font-options.lowercase")
|
{:alt (t locale "workspace.options.font-options.lowercase")
|
||||||
:class (dom/classnames
|
:class (dom/classnames :current (= "lowercase" text-transform))
|
||||||
:current (dwt/text-transform-enabled? editor "lowercase"))
|
:on-click #(on-change % "lowercase")}
|
||||||
:on-click #(on-text-transform-change % "lowercase")}
|
|
||||||
|
|
||||||
i/lowercase]
|
i/lowercase]
|
||||||
[:span.tooltip.tooltip-bottom
|
[:span.tooltip.tooltip-bottom
|
||||||
{:alt (t locale "workspace.options.font-options.titlecase")
|
{:alt (t locale "workspace.options.font-options.titlecase")
|
||||||
:class (dom/classnames
|
:class (dom/classnames :current (= "capitalize" text-transform))
|
||||||
:current (dwt/text-transform-enabled? editor "capitalize"))
|
:on-click #(on-change % "capitalize")}
|
||||||
:on-click #(on-text-transform-change % "capitalize")}
|
|
||||||
i/titlecase]]]))
|
i/titlecase]]]))
|
||||||
|
|
||||||
(mf/defc text-menu
|
(mf/defc text-menu
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [shape] :as props}]
|
[{:keys [shape] :as props}]
|
||||||
(let [id (:id shape)
|
(let [id (:id shape)
|
||||||
editor (:editor (mf/deref refs/workspace-local))
|
local (mf/deref refs/workspace-local)
|
||||||
locale (i18n/use-locale)]
|
editor (get-in local [:editors (:id shape)])
|
||||||
|
locale (mf/deref i18n/locale)]
|
||||||
[:*
|
[:*
|
||||||
[:div.element-set
|
[:div.element-set
|
||||||
[:div.element-set-title (t locale "workspace.options.fill")]
|
[:div.element-set-title (t locale "workspace.options.fill")]
|
||||||
[:div.element-set-content
|
[:div.element-set-content
|
||||||
[:& text-fill-options {:editor editor}]]]
|
[:& text-fill-options {:editor editor :shape shape}]]]
|
||||||
|
|
||||||
|
|
||||||
[:div.element-set
|
[:div.element-set
|
||||||
[:div.element-set-title (t locale "workspace.options.font-options")]
|
[:div.element-set-title (t locale "workspace.options.font-options")]
|
||||||
[:div.element-set-content
|
[:div.element-set-content
|
||||||
[:& font-options {:editor editor :locale locale}]
|
[:& font-options {:editor editor :locale locale :shape shape}]
|
||||||
[:& text-align-options {:editor editor :locale locale}]
|
[:& text-align-options {:editor editor :locale locale :shape shape}]
|
||||||
[:& spacing-options {:editor editor :locale locale}]
|
[:& spacing-options {:editor editor :locale locale :shape shape}]
|
||||||
[:& vertical-align-options {:editor editor :locale locale}]
|
[:& vertical-align-options {:editor editor :locale locale :shape shape}]
|
||||||
[:& text-decoration-options {:editor editor :locale locale}]
|
[:& text-decoration-options {:editor editor :locale locale :shape shape}]
|
||||||
[:& text-transform-options {:editor editor :locale locale}]]]]))
|
[:& text-transform-options {:editor editor :locale locale :shape shape}]]]]))
|
||||||
|
|
||||||
(mf/defc options
|
(mf/defc options
|
||||||
[{:keys [shape] :as props}]
|
[{:keys [shape] :as props}]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue