From abdd4d68d5d9897fda42da8a789de7eed4f907d5 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 18 Sep 2020 13:55:57 +0200 Subject: [PATCH] :sparkles: Allows auto-width and auto-height for text layouts --- frontend/resources/locales.json | 6 +- frontend/src/app/main/data/workspace.cljs | 1 + .../src/app/main/data/workspace/drawing.cljs | 12 ++- frontend/src/app/main/ui/shapes/text.cljs | 17 +++-- .../src/app/main/ui/workspace/drawarea.cljs | 2 +- .../app/main/ui/workspace/shapes/text.cljs | 60 +++++++++++---- .../workspace/sidebar/options/multiple.cljs | 3 +- .../ui/workspace/sidebar/options/text.cljs | 73 ++++++++++++------- .../app/main/ui/workspace/snap_points.cljs | 11 ++- frontend/src/app/util/dom.cljs | 4 +- 10 files changed, 130 insertions(+), 59 deletions(-) diff --git a/frontend/resources/locales.json b/frontend/resources/locales.json index 59c53d8df..ce9d50b81 100644 --- a/frontend/resources/locales.json +++ b/frontend/resources/locales.json @@ -2678,5 +2678,9 @@ "ru" : "Кликни чтобы закончить фигуру", "es" : "Pulsar para cerrar la ruta" } - } + }, + + "workspace.options.text-options.grow-fixed": "Fixed", + "workspace.options.text-options.grow-auto-width": "Auto width", + "workspace.options.text-options.grow-auto-height": "Auto height" } diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 66b322ca1..fc578148c 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1374,6 +1374,7 @@ (defn change-canvas-color [color] + (s/assert string? color) (ptk/reify ::change-canvas-color ptk/WatchEvent (watch [_ state stream] diff --git a/frontend/src/app/main/data/workspace/drawing.cljs b/frontend/src/app/main/data/workspace/drawing.cljs index a18dd5ff7..c0878ff9a 100644 --- a/frontend/src/app/main/data/workspace/drawing.cljs +++ b/frontend/src/app/main/data/workspace/drawing.cljs @@ -273,10 +273,10 @@ (rx/of dw/clear-drawing) (when (::initialized? shape) (let [shape-click-width (case (:type shape) - :text 150 + :text 3 20) shape-click-height (case (:type shape) - :text 40 + :text 16 20) shape (if (::click-draw? shape) (-> shape @@ -285,10 +285,14 @@ (assoc-in [:modifiers :resize-origin] (gpt/point (:x shape) (:y shape)))) shape) + + shape (cond-> shape + (= (:type shape) :text) (assoc :grow-type + (if (::click-draw? shape) :auto-width :fixed))) + shape (-> shape geom/transform-shape - (dissoc ::initialized? - ::click-draw?))] + (dissoc ::initialized? ::click-draw?))] ;; Add & select the created shape to the workspace (rx/of dw/deselect-all (dw/add-shape shape))))))))) diff --git a/frontend/src/app/main/ui/shapes/text.cljs b/frontend/src/app/main/ui/shapes/text.cljs index 10cc83814..d78db4bb0 100644 --- a/frontend/src/app/main/ui/shapes/text.cljs +++ b/frontend/src/app/main/ui/shapes/text.cljs @@ -22,14 +22,19 @@ (defn- generate-root-styles [data] - (let [valign (obj/get data "vertical-align") + (let [valign (obj/get data "vertical-align" "top") + talign (obj/get data "text-align" "flex-start") base #js {:height "100%" :width "100%" :display "flex"}] (cond-> base (= valign "top") (obj/set! "alignItems" "flex-start") (= valign "center") (obj/set! "alignItems" "center") - (= valign "bottom") (obj/set! "alignItems" "flex-end")))) + (= valign "bottom") (obj/set! "alignItems" "flex-end") + (= talign "left") (obj/set! "justifyContent" "flex-start") + (= talign "center") (obj/set! "justifyContent" "center") + (= talign "right") (obj/set! "justifyContent" "flex-end") + (= talign "justify") (obj/set! "justifyContent" "stretch")))) (defn- generate-paragraph-styles [data] @@ -47,6 +52,7 @@ (let [letter-spacing (obj/get data "letter-spacing") text-decoration (obj/get data "text-decoration") text-transform (obj/get data "text-transform") + line-height (obj/get data "line-height") font-id (obj/get data "font-id") font-variant-id (obj/get data "font-variant-id") @@ -61,7 +67,7 @@ :color fill :opacity opacity :textTransform text-transform - :lineHeight "inherit"}] + :lineHeight (or line-height "inherit")}] (when (and (string? letter-spacing) (pos? (alength letter-spacing))) @@ -128,7 +134,7 @@ (if (string? text) (let [style (generate-text-styles (clj->js node))] - [:span {:style style :key index} text]) + [:span {:style style :key index} (if (= text "") "\u00A0" text)]) (let [children (map-indexed (fn [index node] (mf/element text-node {:index index :node node :key index})) children)] @@ -145,8 +151,7 @@ children]) "paragraph-set" - (let [style #js {:display "inline-block" - :width "100%"}] + (let [style #js {:display "inline-block"}] [:div.paragraphs {:key index :style style} children]) "paragraph" diff --git a/frontend/src/app/main/ui/workspace/drawarea.cljs b/frontend/src/app/main/ui/workspace/drawarea.cljs index 3037db9b4..33143af7f 100644 --- a/frontend/src/app/main/ui/workspace/drawarea.cljs +++ b/frontend/src/app/main/ui/workspace/drawarea.cljs @@ -29,7 +29,7 @@ (mf/defc generic-draw-area [{:keys [shape zoom]}] - (let [{:keys [x y width height] :as kk} (:selrect (gsh/transform-shape shape))] + (let [{:keys [x y width height]} (:selrect (gsh/transform-shape shape))] (when (and x y (not (d/nan? x)) (not (d/nan? y))) diff --git a/frontend/src/app/main/ui/workspace/shapes/text.cljs b/frontend/src/app/main/ui/workspace/shapes/text.cljs index 2186fd01a..9b5e5dd42 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text.cljs @@ -28,6 +28,7 @@ [app.util.dom :as dom] [app.common.geom.shapes :as geom] [app.util.object :as obj] + [app.util.timers :as timers] ["slate" :as slate] ["slate-react" :as rslate]) (:import @@ -81,15 +82,21 @@ ;; --- Text Editor Rendering (defn- generate-root-styles - [data] - (let [valign (obj/get data "vertical-align") + [data props] + (let [valign (obj/get data "vertical-align" "top") + talign (obj/get data "text-align") + shape (obj/get props "shape") base #js {:height "100%" - :width "100%" + :width (:width shape) :display "flex"}] (cond-> base (= valign "top") (obj/set! "alignItems" "flex-start") (= valign "center") (obj/set! "alignItems" "center") - (= valign "bottom") (obj/set! "alignItems" "flex-end")))) + (= valign "bottom") (obj/set! "alignItems" "flex-end") + (= talign "left") (obj/set! "justifyContent" "flex-start") + (= talign "center") (obj/set! "justifyContent" "center") + (= talign "right") (obj/set! "justifyContent" "flex-end") + (= talign "justify") (obj/set! "justifyContent" "stretch")))) (defn- generate-paragraph-styles [data] @@ -107,6 +114,7 @@ (let [letter-spacing (obj/get data "letter-spacing") text-decoration (obj/get data "text-decoration") text-transform (obj/get data "text-transform") + line-height (obj/get data "line-height") font-id (obj/get data "font-id") font-variant-id (obj/get data "font-variant-id") @@ -121,7 +129,7 @@ :color fill :opacity opacity :textTransform text-transform - :lineHeight "inherit"}] + :lineHeight (or line-height "inherit")}] (when (and (string? letter-spacing) (pos? (alength letter-spacing))) @@ -157,7 +165,7 @@ childs (obj/get props "children") data (obj/get props "element") type (obj/get data "type") - style (generate-root-styles data) + style (generate-root-styles data props) attrs (obj/set! attrs "style" style) attrs (obj/set! attrs "className" type)] [:> :div attrs childs])) @@ -169,8 +177,13 @@ childs (obj/get props "children") data (obj/get props "element") type (obj/get data "type") + shape (obj/get props "shape") + + ;; The position absolute is used so the paragraph is "outside" + ;; the normal layout and can grow outside its parent + ;; We use this element to measure the size of the text style #js {:display "inline-block" - :width "100%"} + :position "absolute"} attrs (obj/set! attrs "style" style) attrs (obj/set! attrs "className" type)] [:> :div attrs childs])) @@ -196,9 +209,10 @@ [:> :span attrs childs])) (defn- render-element - [props] + [shape props] (mf/html - (let [element (obj/get props "element")] + (let [element (obj/get props "element") + props (obj/merge! props #js {:shape shape})] (case (obj/get element "type") "root" [:> editor-root-node props] "paragraph-set" [:> editor-paragraph-set-node props] @@ -229,12 +243,13 @@ (mf/defc text-shape-edit {::mf/wrap [mf/memo]} [{:keys [shape] :as props}] - (let [{:keys [id x y width height content]} shape + (let [{:keys [id x y width height content grow-type]} shape state (mf/use-state #(parse-content content)) editor (mf/use-memo #(dwt/create-editor)) self-ref (mf/use-ref) selecting-ref (mf/use-ref) + measure-ref (mf/use-ref) on-close (fn [] @@ -297,8 +312,25 @@ (mf/use-effect on-mount) - [:foreignObject {:transform (geom/transform-matrix shape) - :x x :y y :width width :height height :ref self-ref} + (mf/use-effect + (mf/deps @state) + (fn [] + (timers/schedule + #(if (#{:auto-width :auto-height} grow-type) + (let [self-node (mf/ref-val self-ref) + paragraph-node (dom/query self-node ".paragraph-set")] + (when paragraph-node + (let [{:keys [width height]} (dom/get-bounding-rect paragraph-node)] + (st/emit! (dw/update-shape id (if (= grow-type :auto-width) + {:width width :height height} + {:height height})))))))))) + + [:foreignObject {:ref self-ref + :transform (geom/transform-matrix shape) + :x x :y y + :width (if (= :auto-width grow-type) 10000 width) + :height height} + [:style "span { line-height: inherit; }"] [:> rslate/Slate {:editor editor :value @state :on-change on-change} @@ -308,7 +340,7 @@ :on-focus on-focus :class "rich-text" :style {:cursor cur/text} - :render-element render-element + :render-element #(render-element shape %) :render-leaf render-text :on-mouse-up on-mouse-up :on-mouse-down on-mouse-down @@ -317,4 +349,4 @@ (dom/stop-propagation event) ;; WARN: monky patch (obj/set! slate/Transforms "deselect" (constantly nil))) - :placeholder "Type some text here..."}]]])) + :placeholder (when (= :fixed grow-type) "Type some text here...")}]]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/multiple.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/multiple.cljs index fd2df9729..b09b4d2f7 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/multiple.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/multiple.cljs @@ -149,5 +149,6 @@ :spacing-values spacing-values :valign-values valign-values :decoration-values decoration-values - :transform-values transform-values}])])) + :transform-values transform-values + :shapes shapes}])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/text.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/text.cljs index 5d825ca0c..9d8b0a3de 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/text.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/text.cljs @@ -15,6 +15,7 @@ [app.main.ui.icons :as i] [app.common.data :as d] [app.main.data.workspace :as dw] + [app.main.data.workspace.common :as dwc] [app.main.data.workspace.texts :as dwt] [app.main.store :as st] [app.main.refs :as refs] @@ -152,10 +153,15 @@ on-change (fn [event new-align] - (run! #(st/emit! (dwt/update-paragraph-attrs - {:id % - :editor editor - :attrs {:text-align new-align}})) + (run! #(st/emit! + (dwt/update-root-attrs + {:id % + :editor editor + :attrs {:text-align new-align}}) + (dwt/update-paragraph-attrs + {:id % + :editor editor + :attrs {:text-align new-align}})) ids))] ;; --- Align @@ -226,35 +232,29 @@ :placeholder (t locale "settings.multiple") :on-change #(on-change % :letter-spacing)}]]])) -;; (mf/defc box-sizing-options -;; [{:keys [editor] :as props}] -;; [:div.align-icons -;; [:span.tooltip.tooltip-bottom -;; {:alt "Auto height"} -;; i/auto-height] -;; [:span.tooltip.tooltip-bottom -;; {:alt "Auto width"} -;; i/auto-width] -;; [:span.tooltip.tooltip-bottom -;; {:alt "Fixed size"} -;; i/auto-fix]]) - -(mf/defc vertical-align-options - [{:keys [editor ids values locale] :as props}] +(mf/defc additional-options + [{:keys [shapes editor ids values locale] :as props}] (let [{:keys [vertical-align]} values + to-single-value (fn [coll] (if (> (count coll) 1) nil (first coll))) + + grow-type (->> shapes (map :grow-type) (into #{}) to-single-value) + vertical-align (or vertical-align "top") + on-change-grow + (fn [event grow-type] + (st/emit! (dwc/update-shapes ids #(assoc % :grow-type grow-type)))) + on-change (fn [event new-align] (run! #(st/emit! (dwt/update-root-attrs - {:id % - :editor editor - :attrs {:vertical-align new-align}})) + {:id % + :editor editor + :attrs {:vertical-align new-align}})) ids))] [:div.row-flex - [:span.element-set-subtitle (t locale "workspace.options.text-options.vertical-align")] [:div.align-icons [:span.tooltip.tooltip-bottom {:alt (t locale "workspace.options.text-options.align-top") @@ -270,7 +270,24 @@ {:alt (t locale "workspace.options.text-options.align-bottom") :class (dom/classnames :current (= "bottom" vertical-align)) :on-click #(on-change % "bottom")} - i/align-bottom]]])) + i/align-bottom]] + + [:div.align-icons + [:span.tooltip.tooltip-bottom + {:alt (t locale "workspace.options.text-options.grow-fixed") + :class (dom/classnames :current (= :fixed grow-type)) + :on-click #(on-change-grow % :fixed)} + i/auto-fix] + [:span.tooltip.tooltip-bottom + {:alt (t locale "workspace.options.text-options.grow-auto-width") + :class (dom/classnames :current (= :auto-width grow-type)) + :on-click #(on-change-grow % :auto-width)} + i/auto-width] + [:span.tooltip.tooltip-bottom + {:alt (t locale "workspace.options.text-options.grow-auto-height") + :class (dom/classnames :current (= :auto-height grow-type)) + :on-click #(on-change-grow % :auto-height)} + i/auto-height]]])) (mf/defc text-decoration-options [{:keys [editor ids values locale] :as props}] @@ -353,7 +370,8 @@ spacing-values valign-values decoration-values - transform-values] :as props}] + transform-values + shapes] :as props}] (let [locale (mf/deref i18n/locale) label (case type :multiple (t locale "workspace.options.text-options.title-selection") @@ -365,7 +383,7 @@ [:& font-options {:editor editor :ids ids :values font-values :locale locale}] [:& text-align-options {:editor editor :ids ids :values align-values :locale locale}] [:& spacing-options {:editor editor :ids ids :values spacing-values :locale locale}] - [:& vertical-align-options {:editor editor :ids ids :values valign-values :locale locale}] + [:& additional-options {:shapes shapes :editor editor :ids ids :values valign-values :locale locale}] [:& text-decoration-options {:editor editor :ids ids :values decoration-values :locale locale}] [:& text-transform-options {:editor editor :ids ids :values transform-values :locale locale}]]])) @@ -432,4 +450,5 @@ :spacing-values spacing-values :valign-values valign-values :decoration-values decoration-values - :transform-values transform-values}]])) + :transform-values transform-values + :shapes [shape]}]])) diff --git a/frontend/src/app/main/ui/workspace/snap_points.cljs b/frontend/src/app/main/ui/workspace/snap_points.cljs index b8e1747cd..429491aa4 100644 --- a/frontend/src/app/main/ui/workspace/snap_points.cljs +++ b/frontend/src/app/main/ui/workspace/snap_points.cljs @@ -9,6 +9,7 @@ (ns app.main.ui.workspace.snap-points (:require + [app.common.math :as mth] [app.common.data :as d] [app.common.geom.point :as gpt] [app.main.refs :as refs] @@ -22,6 +23,8 @@ (mf/defc snap-point [{:keys [point zoom]}] (let [{:keys [x y]} point + x (mth/round x) + y (mth/round y) cross-width (/ 3 zoom)] [:g [:line {:x1 (- x cross-width) @@ -37,10 +40,10 @@ (mf/defc snap-line [{:keys [snap point zoom]}] - [:line {:x1 (:x snap) - :y1 (:y snap) - :x2 (:x point) - :y2 (:y point) + [:line {:x1 (mth/round (:x snap)) + :y1 (mth/round (:y snap)) + :x2 (mth/round (:x point)) + :y2 (mth/round (:y point)) :style {:stroke line-color :stroke-width (str (/ 1 zoom))} :opacity 0.4}]) diff --git a/frontend/src/app/util/dom.cljs b/frontend/src/app/util/dom.cljs index ca4611c1f..dbc05d854 100644 --- a/frontend/src/app/util/dom.cljs +++ b/frontend/src/app/util/dom.cljs @@ -167,7 +167,9 @@ {:left (.-left ^js rect) :top (.-top ^js rect) :right (.-right ^js rect) - :bottom (.-bottom ^js rect)})) + :bottom (.-bottom ^js rect) + :width (.-width ^js rect) + :height (.-height ^js rect)})) (defn get-window-size []