mirror of
https://github.com/penpot/penpot.git
synced 2025-02-10 00:58:26 -05:00
✨ Allows auto-width and auto-height for text layouts
This commit is contained in:
parent
9c61c52dc5
commit
abdd4d68d5
10 changed files with 130 additions and 59 deletions
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -1374,6 +1374,7 @@
|
|||
|
||||
(defn change-canvas-color
|
||||
[color]
|
||||
(s/assert string? color)
|
||||
(ptk/reify ::change-canvas-color
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
|
|
|
@ -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)))))))))
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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...")}]]]))
|
||||
|
|
|
@ -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}])]))
|
||||
|
||||
|
|
|
@ -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]}]]))
|
||||
|
|
|
@ -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}])
|
||||
|
||||
|
|
|
@ -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
|
||||
[]
|
||||
|
|
Loading…
Add table
Reference in a new issue