✨ Change iconography to reflect orientation
5
frontend/resources/images/icons/text-align-bottom.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<g transform="rotate(90 8 8)">
|
||||
<path d="m14 8h-5.333m5.333-4h-12m12 8h-9.333"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 216 B |
5
frontend/resources/images/icons/text-align-middle.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<g transform="rotate(90 8 8)">
|
||||
<path d="m5.333 8h5.334m-8.667-4h12m-10 8h8"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 214 B |
5
frontend/resources/images/icons/text-align-top.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<g transform="rotate(90 8 8)">
|
||||
<path d="m7.333 8h-5.333m12-4h-12m9.333 8h-9.333"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 219 B |
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<g transform="rotate(90 8 8)">
|
||||
<path d="M13.334 12H6m9.334-8H6m4.667 4H6m-4 6V2m0 12h1.334M2 14H.667M2 2h1.334M2 2H.667"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 259 B |
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M5.667 10.667l.863-1.918m0 0l1.537-3.416 1.536 3.416m-3.073 0h3.073m0 0l.864 1.918M2 14V2m0 12h1.334M2 14H.667M2 2h1.334M2 2H.667"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 261 B |
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<g transform="rotate(90 8 8)">
|
||||
<path d="M6 14l2-2 2 2M3.333 6.667h9.334M3.333 9.333h9.334M10 2L8 4 6 2"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 242 B |
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<g transform="rotate(90 8 8)">
|
||||
<path d="M14 8H2m12-4H2m12 8H2"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 201 B |
5
frontend/resources/images/icons/text-left.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<g transform="rotate(90 8 8)">
|
||||
<path d="M10 3L8 5 6 3m6.667 10H3.333m9.334-2.667H3.333"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 226 B |
5
frontend/resources/images/icons/text-right.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<g transform="rotate(90 8 8)">
|
||||
<path d="M6 13l2-2 2 2M3.333 3h9.334M3.333 5.667h9.334"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 225 B |
@ -270,11 +270,16 @@
|
||||
(def ^:icon-id swatches "swatches")
|
||||
(def ^:icon-id switch "switch")
|
||||
(def ^:icon-id text "text")
|
||||
(def ^:icon-id text-align-bottom "text-align-bottom")
|
||||
(def ^:icon-id text-align-center "text-align-center")
|
||||
(def ^:icon-id text-align-left "text-align-left")
|
||||
(def ^:icon-id text-align-middle "text-align-middle")
|
||||
(def ^:icon-id text-align-right "text-align-right")
|
||||
(def ^:icon-id text-align-top "text-align-top")
|
||||
(def ^:icon-id text-auto-height "text-auto-height")
|
||||
(def ^:icon-id text-auto-height-vertical "text-auto-height-vertical")
|
||||
(def ^:icon-id text-auto-width "text-auto-width")
|
||||
(def ^:icon-id text-auto-width-vertical "text-auto-width-vertical")
|
||||
(def ^:icon-id text-bottom "text-bottom")
|
||||
(def ^:icon-id text-combine-upright-all "text-combine-upright-all")
|
||||
(def ^:icon-id text-combine-upright-digits "text-combine-upright-digits")
|
||||
@ -283,7 +288,10 @@
|
||||
(def ^:icon-id text-font-family "text-font-family")
|
||||
(def ^:icon-id text-font-size "text-font-size")
|
||||
(def ^:icon-id text-font-weight "text-font-weight")
|
||||
(def ^:icon-id text-horizontal-center "text-horizontal-center")
|
||||
(def ^:icon-id text-justify "text-justify")
|
||||
(def ^:icon-id text-justify-vertical "text-justify-vertical")
|
||||
(def ^:icon-id text-left "text-left")
|
||||
(def ^:icon-id text-letterspacing "text-letterspacing")
|
||||
(def ^:icon-id text-lineheight "text-lineheight")
|
||||
(def ^:icon-id text-lowercase "text-lowercase")
|
||||
@ -294,6 +302,7 @@
|
||||
(def ^:icon-id text-orientation-upright "text-orientation-upright")
|
||||
(def ^:icon-id text-palette "text-palette")
|
||||
(def ^:icon-id text-paragraph "text-paragraph")
|
||||
(def ^:icon-id text-right "text-right")
|
||||
(def ^:icon-id text-rtl "text-rtl")
|
||||
(def ^:icon-id text-stroked "text-stroked")
|
||||
(def ^:icon-id text-top "text-top")
|
||||
|
||||
@ -40,6 +40,7 @@
|
||||
[app.util.object :as obj]
|
||||
[app.util.text.content :as content]
|
||||
[app.util.text.ui :as txu]
|
||||
[app.util.text.writing-mode :as wm]
|
||||
[app.util.timers :as ts]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]
|
||||
@ -56,24 +57,32 @@
|
||||
|
||||
(mf/defc text-align-options*
|
||||
[{:keys [values on-change on-blur]}]
|
||||
(let [options
|
||||
(mf/with-memo []
|
||||
(let [vertical? (and (wm/vertical-layout-active?)
|
||||
(tjl/vertical-japanese-layout? values))
|
||||
options
|
||||
(mf/with-memo [vertical?]
|
||||
[{:value "left"
|
||||
:id "text-align-left"
|
||||
:label (tr "workspace.options.text-options.text-align-left")
|
||||
:icon i/text-align-left}
|
||||
:label (if vertical?
|
||||
(tr "workspace.options.text-options.align-top")
|
||||
(tr "workspace.options.text-options.text-align-left"))
|
||||
:icon (if vertical? i/text-align-top i/text-align-left)}
|
||||
{:value "center"
|
||||
:id "text-align-center"
|
||||
:label (tr "workspace.options.text-options.text-align-center")
|
||||
:icon i/text-align-center}
|
||||
:label (if vertical?
|
||||
(tr "workspace.options.text-options.align-middle")
|
||||
(tr "workspace.options.text-options.text-align-center"))
|
||||
:icon (if vertical? i/text-align-middle i/text-align-center)}
|
||||
{:value "right"
|
||||
:id "text-align-right"
|
||||
:label (tr "workspace.options.text-options.text-align-right")
|
||||
:icon i/text-align-right}
|
||||
:label (if vertical?
|
||||
(tr "workspace.options.text-options.align-bottom")
|
||||
(tr "workspace.options.text-options.text-align-right"))
|
||||
:icon (if vertical? i/text-align-bottom i/text-align-right)}
|
||||
{:value "justify"
|
||||
:id "text-align-justify"
|
||||
:label (tr "workspace.options.text-options.text-align-justify")
|
||||
:icon i/text-justify}])
|
||||
:icon (if vertical? i/text-justify-vertical i/text-justify)}])
|
||||
|
||||
handle-change
|
||||
(mf/use-fn
|
||||
@ -90,7 +99,9 @@
|
||||
|
||||
(mf/defc text-direction-options*
|
||||
[{:keys [values on-change on-blur]}]
|
||||
(let [direction (radio-selected (:text-direction values))
|
||||
(let [vertical? (and (wm/vertical-layout-active?)
|
||||
(tjl/vertical-japanese-layout? values))
|
||||
direction (radio-selected (:text-direction values))
|
||||
options
|
||||
(mf/with-memo []
|
||||
[{:value "ltr"
|
||||
@ -109,29 +120,38 @@
|
||||
(on-change {:text-direction (if (= value direction) "none" value)})
|
||||
(when (some? on-blur) (on-blur))))]
|
||||
|
||||
[:div {:class (stl/css :text-direction-options)}
|
||||
[:> radio-buttons* {:selected direction
|
||||
:on-change handle-change
|
||||
:name "text-direction-options"
|
||||
:options options}]]))
|
||||
(when-not vertical?
|
||||
[:div {:class (stl/css :text-direction-options)}
|
||||
[:> radio-buttons* {:selected direction
|
||||
:on-change handle-change
|
||||
:name "text-direction-options"
|
||||
:options options}]])))
|
||||
|
||||
(mf/defc vertical-align*
|
||||
[{:keys [values on-change on-blur]}]
|
||||
(let [vertical-align (radio-selected (:vertical-align values) "top")
|
||||
(let [vertical? (and (wm/vertical-layout-active?)
|
||||
(tjl/vertical-japanese-layout? values))
|
||||
vertical-align (radio-selected (:vertical-align values) "top")
|
||||
options
|
||||
(mf/with-memo []
|
||||
(mf/with-memo [vertical?]
|
||||
[{:value "top"
|
||||
:id "vertical-text-align-top"
|
||||
:label (tr "workspace.options.text-options.align-top")
|
||||
:icon i/text-top}
|
||||
:label (if vertical?
|
||||
(tr "workspace.options.text-options.text-align-right")
|
||||
(tr "workspace.options.text-options.align-top"))
|
||||
:icon (if vertical? i/text-right i/text-top)}
|
||||
{:value "center"
|
||||
:id "vertical-text-align-center"
|
||||
:label (tr "workspace.options.text-options.align-middle")
|
||||
:icon i/text-middle}
|
||||
:label (if vertical?
|
||||
(tr "workspace.options.text-options.text-align-center")
|
||||
(tr "workspace.options.text-options.align-middle"))
|
||||
:icon (if vertical? i/text-horizontal-center i/text-middle)}
|
||||
{:value "bottom"
|
||||
:id "vertical-text-align-bottom"
|
||||
:label (tr "workspace.options.text-options.align-bottom")
|
||||
:icon i/text-bottom}])
|
||||
:label (if vertical?
|
||||
(tr "workspace.options.text-options.text-align-left")
|
||||
(tr "workspace.options.text-options.align-bottom"))
|
||||
:icon (if vertical? i/text-left i/text-bottom)}])
|
||||
|
||||
handle-change
|
||||
(mf/use-fn
|
||||
@ -148,23 +168,29 @@
|
||||
|
||||
(mf/defc grow-options*
|
||||
[{:keys [ids values on-blur]}]
|
||||
(let [grow-type (:grow-type values)
|
||||
(let [vertical? (and (wm/vertical-layout-active?)
|
||||
(tjl/vertical-japanese-layout? values))
|
||||
grow-type (:grow-type values)
|
||||
selected (radio-selected grow-type)
|
||||
editor-instance (mf/deref refs/workspace-editor)
|
||||
options
|
||||
(mf/with-memo []
|
||||
(mf/with-memo [vertical?]
|
||||
[{:value "fixed"
|
||||
:id "text-fixed-grow"
|
||||
:label (tr "workspace.options.text-options.grow-fixed")
|
||||
:icon i/text-fixed}
|
||||
{:value "auto-width"
|
||||
:id "text-auto-width-grow"
|
||||
:label (tr "workspace.options.text-options.grow-auto-width")
|
||||
:icon i/text-auto-width}
|
||||
:label (if vertical?
|
||||
(tr "workspace.options.text-options.grow-auto-height")
|
||||
(tr "workspace.options.text-options.grow-auto-width"))
|
||||
:icon (if vertical? i/text-auto-width-vertical i/text-auto-width)}
|
||||
{:value "auto-height"
|
||||
:id "text-auto-height-grow"
|
||||
:label (tr "workspace.options.text-options.grow-auto-height")
|
||||
:icon i/text-auto-height}])
|
||||
:label (if vertical?
|
||||
(tr "workspace.options.text-options.grow-auto-width")
|
||||
(tr "workspace.options.text-options.grow-auto-height"))
|
||||
:icon (if vertical? i/text-auto-height-vertical i/text-auto-height)}])
|
||||
|
||||
handle-change
|
||||
(mf/use-fn
|
||||
@ -651,9 +677,6 @@
|
||||
:on-click toggle-more-options
|
||||
:icon i/menu}]]
|
||||
|
||||
(when japanese-layout-config-enabled?
|
||||
[:> tjl/line-adjustment-option* common-props])
|
||||
|
||||
(when more-options-open?
|
||||
[:div {:class (stl/css :text-decoration-options)}
|
||||
[:> vertical-align* common-props]
|
||||
|
||||
@ -506,6 +506,7 @@
|
||||
(when ^boolean vertical?
|
||||
[:> text-combine-upright-count-options* common-props])
|
||||
[:> font-features-options* common-props]
|
||||
[:> line-adjustment-option* common-props]
|
||||
;; Emphasis marks (圏点 / bouten) apply to the selected characters.
|
||||
(when ^boolean text-selection-active
|
||||
[:> span-select-option* (mf/spread-props common-props
|
||||
|
||||
@ -10,9 +10,11 @@
|
||||
[app.common.types.text.cjk-layout :as cjk]
|
||||
[app.main.data.workspace.texts :as dwt]
|
||||
[app.main.ui.ds.controls.select :as select]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
[app.main.ui.shapes.text.html-text :as html-text]
|
||||
[app.main.ui.shapes.text.styles :as text-styles]
|
||||
[app.main.ui.workspace.sidebar.options.common :refer [radio-selected]]
|
||||
[app.main.ui.workspace.sidebar.options.menus.text :as text-menu]
|
||||
[app.main.ui.workspace.sidebar.options.menus.text-japanese-layout :as tjl]
|
||||
[app.util.text.writing-mode :as wm]
|
||||
[cljs.test :as t :include-macros true]
|
||||
@ -246,3 +248,115 @@
|
||||
(t/is (not (str/includes? (markup) "vertical-rl"))))
|
||||
(with-redefs [wm/vertical-layout-active? (constantly true)]
|
||||
(t/is (str/includes? (markup) "writing-mode:vertical-rl")))))
|
||||
|
||||
(defn- alignment-markup
|
||||
([component writing-mode wasm-enabled]
|
||||
(alignment-markup component writing-mode wasm-enabled {}))
|
||||
([component writing-mode wasm-enabled values]
|
||||
;; Server rendering has no DOM container for tooltip portals.
|
||||
(with-redefs [wm/vertical-layout-active? (constantly wasm-enabled)
|
||||
hooks/use-portal-container (fn ([] nil) ([_] nil))]
|
||||
(rds/renderToStaticMarkup
|
||||
(mf/element component #js {:values (assoc values :writing-mode writing-mode)
|
||||
:on-change identity})))))
|
||||
|
||||
(defn- alignment-labels
|
||||
[markup]
|
||||
(mapv second (re-seq #"aria-label=\"([^\"]+)\"" markup)))
|
||||
|
||||
(defn- alignment-icons
|
||||
[markup]
|
||||
(mapv second (re-seq #"href=\"#icon-([^\"]+)\"" markup)))
|
||||
|
||||
(t/deftest vertical-paragraph-alignment-shows-top-middle-bottom-and-vertical-justify
|
||||
(let [markup (alignment-markup text-menu/text-align-options* "vertical-rl" true)]
|
||||
(t/is (= ["text-align-top" "text-align-middle" "text-align-bottom" "text-justify-vertical"]
|
||||
(alignment-icons markup)))
|
||||
(t/is (= ["workspace.options.text-options.align-top"
|
||||
"workspace.options.text-options.align-middle"
|
||||
"workspace.options.text-options.align-bottom"
|
||||
"workspace.options.text-options.text-align-justify"]
|
||||
(alignment-labels markup)))
|
||||
(t/is (= ["left" "center" "right" "justify"]
|
||||
(mapv second (re-seq #"value=\"([^\"]+)\"" markup))))))
|
||||
|
||||
(t/deftest vertical-column-block-alignment-shows-right-center-and-left
|
||||
(let [markup (alignment-markup text-menu/vertical-align* "vertical-rl" true)]
|
||||
(t/is (= ["text-right" "text-horizontal-center" "text-left"]
|
||||
(alignment-icons markup)))
|
||||
(t/is (= ["workspace.options.text-options.text-align-right"
|
||||
"workspace.options.text-options.text-align-center"
|
||||
"workspace.options.text-options.text-align-left"]
|
||||
(alignment-labels markup)))
|
||||
(t/is (= ["top" "center" "bottom"]
|
||||
(mapv second (re-seq #"value=\"([^\"]+)\"" markup))))))
|
||||
|
||||
(t/deftest horizontal-and-mixed-writing-modes-use-horizontal-alignment-controls
|
||||
(doseq [writing-mode [nil "horizontal-tb" :multiple]]
|
||||
(let [paragraph (alignment-markup text-menu/text-align-options* writing-mode true)
|
||||
block (alignment-markup text-menu/vertical-align* writing-mode true)]
|
||||
(t/is (= ["text-align-left" "text-align-center" "text-align-right" "text-justify"]
|
||||
(alignment-icons paragraph)))
|
||||
(t/is (= ["text-top" "text-middle" "text-bottom"] (alignment-icons block))))))
|
||||
|
||||
(t/deftest svg-renderer-keeps-horizontal-alignment-for-stored-vertical-text
|
||||
(let [paragraph (alignment-markup text-menu/text-align-options* "vertical-rl" false)
|
||||
block (alignment-markup text-menu/vertical-align* "vertical-rl" false)]
|
||||
(t/is (= ["text-align-left" "text-align-center" "text-align-right" "text-justify"]
|
||||
(alignment-icons paragraph)))
|
||||
(t/is (= ["text-top" "text-middle" "text-bottom"] (alignment-icons block)))
|
||||
(t/is (= "workspace.options.text-options.text-align-left" (first (alignment-labels paragraph))))
|
||||
(t/is (= "workspace.options.text-options.align-top" (first (alignment-labels block))))))
|
||||
|
||||
|
||||
(t/deftest vertical-text-growth-controls-show-the-physical-growth-direction
|
||||
(let [markup (alignment-markup text-menu/grow-options* "vertical-rl" true)]
|
||||
(t/is (= ["text-fixed" "text-auto-width-vertical" "text-auto-height-vertical"]
|
||||
(alignment-icons markup)))
|
||||
(t/is (= ["workspace.options.text-options.grow-fixed"
|
||||
"workspace.options.text-options.grow-auto-height"
|
||||
"workspace.options.text-options.grow-auto-width"]
|
||||
(alignment-labels markup)))
|
||||
(t/is (= ["fixed" "auto-width" "auto-height"]
|
||||
(mapv second (re-seq #"value=\"([^\"]+)\"" markup))))))
|
||||
|
||||
(t/deftest horizontal-and-svg-text-growth-controls-keep-horizontal-directions
|
||||
(doseq [[writing-mode wasm-enabled] [[nil true]
|
||||
["horizontal-tb" true]
|
||||
[:multiple true]
|
||||
["vertical-rl" false]]]
|
||||
(let [markup (alignment-markup text-menu/grow-options* writing-mode wasm-enabled)]
|
||||
(t/is (= ["text-fixed" "text-auto-width" "text-auto-height"]
|
||||
(alignment-icons markup)))
|
||||
(t/is (= ["workspace.options.text-options.grow-fixed"
|
||||
"workspace.options.text-options.grow-auto-width"
|
||||
"workspace.options.text-options.grow-auto-height"]
|
||||
(alignment-labels markup))))))
|
||||
|
||||
|
||||
(t/deftest japanese-layout-controls-include-line-adjustment
|
||||
(let [markup (alignment-markup tjl/japanese-layout-options* "vertical-rl" true)]
|
||||
(t/is (str/includes? markup "workspace.options.text-options.line-adjustment"))))
|
||||
|
||||
|
||||
(t/deftest vertical-text-hides-ltr-and-rtl-controls
|
||||
(t/is (empty? (alignment-markup text-menu/text-direction-options* "vertical-rl" true))))
|
||||
|
||||
(t/deftest horizontal-and-svg-text-show-ltr-and-rtl-controls
|
||||
(doseq [[writing-mode wasm-enabled] [[nil true]
|
||||
["horizontal-tb" true]
|
||||
[:multiple true]
|
||||
["vertical-rl" false]]]
|
||||
(let [markup (alignment-markup text-menu/text-direction-options* writing-mode wasm-enabled)]
|
||||
(t/is (= ["text-ltr" "text-rtl"] (alignment-icons markup))))))
|
||||
|
||||
(t/deftest hiding-direction-controls-preserves-the-stored-direction
|
||||
(let [values {:text-direction "rtl"}
|
||||
render #(alignment-markup text-menu/text-direction-options* % true values)]
|
||||
(t/is (str/includes? (re-find #"<input[^>]*id=\"rtl-text-direction\"[^>]*>"
|
||||
(render "horizontal-tb"))
|
||||
"checked=\"\""))
|
||||
(t/is (empty? (render "vertical-rl")))
|
||||
(t/is (str/includes? (re-find #"<input[^>]*id=\"rtl-text-direction\"[^>]*>"
|
||||
(render "horizontal-tb"))
|
||||
"checked=\"\""))))
|
||||
|
||||