mirror of
https://github.com/penpot/penpot.git
synced 2025-02-13 02:28:18 -05:00
🐛 Fix text focus issues
This commit is contained in:
parent
9ebafddac2
commit
1fc5182979
10 changed files with 118 additions and 57 deletions
|
@ -60,7 +60,7 @@
|
|||
(a/close! output)))
|
||||
|
||||
(defn- send-mattermost-notification!
|
||||
[cfg {:keys [host version id] :as cdata}]
|
||||
[cfg {:keys [host id] :as cdata}]
|
||||
(try
|
||||
(let [uri (:uri cfg)
|
||||
text (str "Unhandled exception (host: " host ", url: " (cfg/get :public-uri) "/dbg/error-by-id/" id "\n"
|
||||
|
|
|
@ -258,7 +258,7 @@
|
|||
|
||||
(defmethod migrate 11
|
||||
[data]
|
||||
(letfn [(update-object [objects id shape]
|
||||
(letfn [(update-object [objects _id shape]
|
||||
(if (= :frame (:type shape))
|
||||
(d/update-when shape :shapes (fn [shapes]
|
||||
(filterv (fn [id] (contains? objects id)) shapes)))
|
||||
|
|
|
@ -203,8 +203,11 @@
|
|||
(when-not (some? (get-in state [:workspace-editor-state id]))
|
||||
(let [objects (wsh/lookup-page-objects state)
|
||||
shape (get objects id)
|
||||
update-node? (fn [node]
|
||||
(or (txt/is-text-node? node)
|
||||
(txt/is-paragraph-node? node)))
|
||||
|
||||
update-fn #(update-shape % txt/is-text-node? attrs/merge attrs)
|
||||
update-fn #(update-shape % update-node? attrs/merge attrs)
|
||||
shape-ids (cond (= (:type shape) :text) [id]
|
||||
(= (:type shape) :group) (cp/get-children id objects))]
|
||||
(rx/of (dch/update-shapes shape-ids update-fn)))))))
|
||||
|
@ -325,8 +328,8 @@
|
|||
(ptk/reify ::save-font
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
;; Check if the data has any multiple
|
||||
(assoc-in state
|
||||
[:workspace-local :defaults :font]
|
||||
data))))
|
||||
(let [multiple? (->> data vals (d/seek #(= % :multiple)))]
|
||||
(cond-> state
|
||||
(not multiple?)
|
||||
(assoc-in [:workspace-local :defaults :font] data))))))
|
||||
|
||||
|
|
|
@ -14,19 +14,23 @@
|
|||
[app.util.timers :as timers]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
(mf/defc editable-select [{:keys [value type options class on-change placeholder]}]
|
||||
(mf/defc editable-select [{:keys [value type options class on-change placeholder on-blur]}]
|
||||
(let [state (mf/use-state {:id (uuid/next)
|
||||
:is-open? false
|
||||
:current-value value
|
||||
:top nil
|
||||
:left nil
|
||||
:bottom nil})
|
||||
|
||||
emit-blur? (mf/use-ref nil)
|
||||
|
||||
open-dropdown #(swap! state assoc :is-open? true)
|
||||
close-dropdown #(swap! state assoc :is-open? false)
|
||||
select-item (fn [value]
|
||||
(fn [_]
|
||||
(swap! state assoc :current-value value)
|
||||
(when on-change (on-change value))))
|
||||
(when on-change (on-change value))
|
||||
(when on-blur (on-blur))))
|
||||
|
||||
as-key-value (fn [item] (if (map? item) [(:value item) (:label item)] [item item]))
|
||||
|
||||
|
@ -55,21 +59,38 @@
|
|||
assoc
|
||||
:left left
|
||||
:top top
|
||||
:bottom bottom))))))]
|
||||
:bottom bottom))))))
|
||||
|
||||
handle-focus
|
||||
(mf/use-callback
|
||||
(fn []
|
||||
(mf/set-ref-val! emit-blur? false)))
|
||||
|
||||
handle-blur
|
||||
(mf/use-callback
|
||||
(fn []
|
||||
(mf/set-ref-val! emit-blur? true)
|
||||
(timers/schedule
|
||||
200
|
||||
(fn []
|
||||
(when (and on-blur (mf/ref-val emit-blur?)) (on-blur))))))]
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps value)
|
||||
#(reset! state {:current-value value}))
|
||||
(mf/deps value (:current-value @state))
|
||||
#(when (not= value (:current-value @state))
|
||||
(reset! state {:current-value value})))
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps options)
|
||||
#(reset! state {:is-open? false
|
||||
:current-value value}))
|
||||
(mf/deps (:is-open? @state))
|
||||
(fn []
|
||||
(mf/set-ref-val! emit-blur? (not (:is-open? @state)))))
|
||||
|
||||
[:div.editable-select {:class class
|
||||
:ref on-node-load}
|
||||
[:input.input-text {:value (or (-> @state :current-value value->label) "")
|
||||
:on-change handle-change-input
|
||||
:on-focus handle-focus
|
||||
:on-blur handle-blur
|
||||
:placeholder placeholder
|
||||
:type type}]
|
||||
[:span.dropdown-button {:on-click open-dropdown} i/arrow-down]
|
||||
|
|
|
@ -157,11 +157,11 @@
|
|||
on-change
|
||||
(mf/use-callback
|
||||
(fn [val]
|
||||
(let [val (handle-change val)]
|
||||
(let [val (if (true? @blured)
|
||||
(ted/add-editor-blur-selection val)
|
||||
(ted/remove-editor-blur-selection val))]
|
||||
(st/emit! (dwt/update-editor-state shape val))))))
|
||||
(let [val (handle-change val)
|
||||
val (if (true? @blured)
|
||||
(ted/add-editor-blur-selection val)
|
||||
(ted/remove-editor-blur-selection val))]
|
||||
(st/emit! (dwt/update-editor-state shape val)))))
|
||||
|
||||
on-editor
|
||||
(mf/use-callback
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
[app.main.ui.workspace.sidebar.options.menus.typography :refer [typography-entry typography-options]]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.timers :as tm]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
|
@ -80,11 +81,12 @@
|
|||
(def attrs (d/concat #{} shape-attrs root-attrs paragraph-attrs text-attrs))
|
||||
|
||||
(mf/defc text-align-options
|
||||
[{:keys [values on-change] :as props}]
|
||||
[{:keys [values on-change on-blur] :as props}]
|
||||
(let [{:keys [text-align]} values
|
||||
handle-change
|
||||
(fn [_ new-align]
|
||||
(on-change {:text-align new-align}))]
|
||||
(on-change {:text-align new-align})
|
||||
(when (some? on-blur) (on-blur)))]
|
||||
|
||||
;; --- Align
|
||||
[:div.align-icons
|
||||
|
@ -110,10 +112,12 @@
|
|||
i/text-align-justify]]))
|
||||
|
||||
(mf/defc text-direction-options
|
||||
[{:keys [values on-change] :as props}]
|
||||
[{:keys [values on-change on-blur] :as props}]
|
||||
(let [direction (:text-direction values)
|
||||
handle-change (fn [_ val]
|
||||
(on-change {:text-direction val}))]
|
||||
handle-change
|
||||
(fn [_ val]
|
||||
(on-change {:text-direction val})
|
||||
(when (some? on-blur) (on-blur)))]
|
||||
;; --- Align
|
||||
[:div.align-icons
|
||||
[:span.tooltip.tooltip-bottom-left
|
||||
|
@ -128,12 +132,13 @@
|
|||
i/text-direction-rtl]]))
|
||||
|
||||
(mf/defc vertical-align
|
||||
[{:keys [values on-change] :as props}]
|
||||
[{:keys [values on-change on-blur] :as props}]
|
||||
(let [{:keys [vertical-align]} values
|
||||
vertical-align (or vertical-align "top")
|
||||
handle-change
|
||||
(fn [_ new-align]
|
||||
(on-change {:vertical-align new-align}))]
|
||||
(on-change {:vertical-align new-align})
|
||||
(when (some? on-blur) (on-blur)))]
|
||||
|
||||
[:div.align-icons
|
||||
[:span.tooltip.tooltip-bottom-left
|
||||
|
@ -153,11 +158,12 @@
|
|||
i/align-bottom]]))
|
||||
|
||||
(mf/defc grow-options
|
||||
[{:keys [ids values] :as props}]
|
||||
[{:keys [ids values on-blur] :as props}]
|
||||
(let [grow-type (:grow-type values)
|
||||
handle-change-grow
|
||||
(fn [_ grow-type]
|
||||
(st/emit! (dch/update-shapes ids #(assoc % :grow-type grow-type))))]
|
||||
(st/emit! (dch/update-shapes ids #(assoc % :grow-type grow-type)))
|
||||
(when (some? on-blur) (on-blur)))]
|
||||
|
||||
[:div.align-icons
|
||||
[:span.tooltip.tooltip-bottom
|
||||
|
@ -177,11 +183,12 @@
|
|||
i/auto-height]]))
|
||||
|
||||
(mf/defc text-decoration-options
|
||||
[{:keys [values on-change] :as props}]
|
||||
[{:keys [values on-change on-blur] :as props}]
|
||||
(let [text-decoration (or (:text-decoration values) "none")
|
||||
handle-change
|
||||
(fn [_ type]
|
||||
(on-change {:text-decoration type}))]
|
||||
(on-change {:text-decoration type})
|
||||
(when (some? on-blur) (on-blur)))]
|
||||
[:div.align-icons
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt (tr "workspace.options.text-options.none")
|
||||
|
@ -222,7 +229,8 @@
|
|||
(mf/use-callback
|
||||
(mf/deps values)
|
||||
(fn [id attrs]
|
||||
(st/emit! (dwt/save-font (merge txt/default-text-attrs values attrs)))
|
||||
(st/emit! (dwt/save-font (-> (merge txt/default-text-attrs values attrs)
|
||||
(select-keys text-attrs))))
|
||||
|
||||
(let [attrs (select-keys attrs root-attrs)]
|
||||
(when-not (empty? attrs)
|
||||
|
@ -290,7 +298,15 @@
|
|||
|
||||
opts #js {:ids ids
|
||||
:values values
|
||||
:on-change on-change}]
|
||||
:on-change on-change
|
||||
:on-blur
|
||||
(fn []
|
||||
(tm/schedule
|
||||
100
|
||||
(fn []
|
||||
(when (not= "INPUT" (-> (dom/get-active) (dom/get-tag-name)))
|
||||
(let [node (dom/get-element-by-class "public-DraftEditor-content")]
|
||||
(dom/focus! node))))))}]
|
||||
|
||||
[:div.element-set
|
||||
[:div.element-set-title
|
||||
|
|
|
@ -230,7 +230,7 @@
|
|||
:current? (= (:id font) (:id selected))}])))
|
||||
|
||||
(mf/defc font-options
|
||||
[{:keys [values on-change] :as props}]
|
||||
[{:keys [values on-change on-blur] :as props}]
|
||||
(let [{:keys [font-id font-size font-variant-id]} values
|
||||
|
||||
font-id (or font-id (:font-id txt/default-text-attrs))
|
||||
|
@ -271,18 +271,26 @@
|
|||
:font-family (:family font)
|
||||
:font-variant-id new-variant-id
|
||||
:font-weight (:weight variant)
|
||||
:font-style (:style variant)}))))
|
||||
:font-style (:style variant)})
|
||||
(dom/blur! (dom/get-target event)))))
|
||||
|
||||
on-font-select
|
||||
(mf/use-callback
|
||||
(mf/deps change-font)
|
||||
(fn [font*]
|
||||
(when (not= font font*)
|
||||
(change-font (:id font*)))))
|
||||
(change-font (:id font*)))
|
||||
|
||||
(when (some? on-blur)
|
||||
(on-blur))))
|
||||
|
||||
on-font-selector-close
|
||||
(mf/use-callback
|
||||
#(reset! open-selector? false))]
|
||||
(fn []
|
||||
(reset! open-selector? false)
|
||||
(when (some? on-blur)
|
||||
(on-blur))
|
||||
))]
|
||||
|
||||
[:*
|
||||
(when @open-selector?
|
||||
|
@ -314,12 +322,14 @@
|
|||
:options size-options
|
||||
:type "number"
|
||||
:placeholder "--"
|
||||
:on-change on-font-size-change}])
|
||||
:on-change on-font-size-change
|
||||
:on-blur on-blur}])
|
||||
|
||||
[:select.input-select.variant-option
|
||||
{:disabled (= font-id :multiple)
|
||||
:value (attr->string font-variant-id)
|
||||
:on-change on-font-variant-change}
|
||||
:on-change on-font-variant-change
|
||||
:on-blur on-blur}
|
||||
(when (or (= font-id :multiple) (= font-variant-id :multiple))
|
||||
[:option {:value ""} "--"])
|
||||
(for [variant (:variants font)]
|
||||
|
@ -329,7 +339,7 @@
|
|||
|
||||
|
||||
(mf/defc spacing-options
|
||||
[{:keys [values on-change] :as props}]
|
||||
[{:keys [values on-change on-blur] :as props}]
|
||||
(let [{:keys [line-height
|
||||
letter-spacing]} values
|
||||
|
||||
|
@ -353,7 +363,8 @@
|
|||
:max "200"
|
||||
:value (attr->string line-height)
|
||||
:placeholder (tr "settings.multiple")
|
||||
:on-change #(handle-change % :line-height)}]]
|
||||
:on-change #(handle-change % :line-height)
|
||||
:on-blur on-blur}]]
|
||||
|
||||
[:div.input-icon
|
||||
[:span.icon-before.tooltip.tooltip-bottom
|
||||
|
@ -366,18 +377,21 @@
|
|||
:max "200"
|
||||
:value (attr->string letter-spacing)
|
||||
:placeholder (tr "settings.multiple")
|
||||
:on-change #(handle-change % :letter-spacing)}]]]))
|
||||
:on-change #(handle-change % :letter-spacing)
|
||||
:on-blur on-blur}]]]))
|
||||
|
||||
(mf/defc text-transform-options
|
||||
[{:keys [values on-change] :as props}]
|
||||
[{:keys [values on-change on-blur] :as props}]
|
||||
(let [text-transform (or (:text-transform values) "none")
|
||||
handle-change
|
||||
(fn [_ type]
|
||||
(on-change {:text-transform type}))]
|
||||
(on-change {:text-transform type})
|
||||
(when (some? on-blur) (on-blur)))]
|
||||
[:div.align-icons
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt (tr "workspace.options.text-options.none")
|
||||
:class (dom/classnames :current (= "none" text-transform))
|
||||
:focus #(dom/prevent-default %)
|
||||
:on-click #(handle-change % "none")}
|
||||
i/minus]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
|
@ -397,11 +411,12 @@
|
|||
i/titlecase]]))
|
||||
|
||||
(mf/defc typography-options
|
||||
[{:keys [ids editor values on-change]}]
|
||||
[{:keys [ids editor values on-change on-blur]}]
|
||||
(let [opts #js {:editor editor
|
||||
:ids ids
|
||||
:values values
|
||||
:on-change on-change}]
|
||||
:on-change on-change
|
||||
:on-blur on-blur}]
|
||||
[:div.element-set-content
|
||||
[:> font-options opts]
|
||||
[:div.row-flex
|
||||
|
|
|
@ -9,10 +9,9 @@
|
|||
[app.common.data :as d]
|
||||
[app.main.data.workspace.texts :as dwt]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.ui.workspace.sidebar.options.menus.fill :refer [fill-attrs]]
|
||||
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
|
||||
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
|
||||
[app.main.ui.workspace.sidebar.options.menus.fill :refer [fill-menu]]
|
||||
[app.main.ui.workspace.sidebar.options.menus.fill :refer [fill-menu fill-attrs]]
|
||||
[app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]]
|
||||
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu]]
|
||||
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]]
|
||||
|
|
|
@ -223,11 +223,13 @@
|
|||
|
||||
(defn focus!
|
||||
[node]
|
||||
(.focus node))
|
||||
(when (some? node)
|
||||
(.focus node)))
|
||||
|
||||
(defn blur!
|
||||
[node]
|
||||
(.blur node))
|
||||
(when (some? node)
|
||||
(.blur node)))
|
||||
|
||||
(defn fullscreen?
|
||||
[]
|
||||
|
@ -291,8 +293,11 @@
|
|||
(defn get-user-agent []
|
||||
(.-userAgent globals/navigator))
|
||||
|
||||
(defn get-active []
|
||||
(.-activeElement globals/document))
|
||||
|
||||
(defn active? [node]
|
||||
(= (.-activeElement globals/document) node))
|
||||
(= (get-active) node))
|
||||
|
||||
(defn get-data [^js node ^string attr]
|
||||
(.getAttribute node (str "data-" attr)))
|
||||
|
|
|
@ -34,7 +34,7 @@ function mergeBlockData(block, newData) {
|
|||
}
|
||||
}
|
||||
|
||||
return block.merge({
|
||||
return block.mergeDeep({
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
@ -119,29 +119,31 @@ export function updateCurrentBlockData(state, attrs) {
|
|||
}
|
||||
|
||||
export function applyInlineStyle(state, styles) {
|
||||
let selection = state.getSelection();
|
||||
const userSelection = state.getSelection();
|
||||
let selection = userSelection;
|
||||
|
||||
if (selection.isCollapsed()) {
|
||||
selection = getSelectAllSelection(state);
|
||||
}
|
||||
|
||||
let result = state;
|
||||
let content = null;
|
||||
|
||||
for (let style of styles) {
|
||||
const [p, k, v] = style.split("$$$");
|
||||
const prefix = [p, k, ""].join("$$$");
|
||||
|
||||
content = state.getCurrentContent();
|
||||
content = result.getCurrentContent();
|
||||
content = removeInlineStylePrefix(content, selection, prefix);
|
||||
|
||||
if (v !== "z:null") {
|
||||
content = Modifier.applyInlineStyle(content, selection, style);
|
||||
}
|
||||
|
||||
state = EditorState.push(state, content, "change-inline-style");
|
||||
result = EditorState.push(result, content, "change-inline-style");
|
||||
}
|
||||
|
||||
return state;
|
||||
return EditorState.acceptSelection(result, userSelection);
|
||||
}
|
||||
|
||||
export function splitBlockPreservingData(state) {
|
||||
|
@ -308,7 +310,7 @@ export function updateBlockData(state, blockKey, data) {
|
|||
);
|
||||
|
||||
const result = EditorState.push(state, newContent, 'change-block-data');
|
||||
return EditorState.acceptSelection(result, userSelection)
|
||||
return EditorState.acceptSelection(result, userSelection);
|
||||
}
|
||||
|
||||
export function getSelection(state) {
|
||||
|
|
Loading…
Add table
Reference in a new issue