🔧 Support text style shortcuts (#11002)

This commit is contained in:
Elena Torró 2026-08-04 15:30:26 +02:00 committed by GitHub
parent ca29f734c7
commit 14a6ea5c52
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 55 additions and 4 deletions

View File

@ -11,6 +11,7 @@
[app.common.types.text :as txt]
[app.main.data.shortcuts :as ds]
[app.main.data.workspace.texts :as dwt]
[app.main.data.workspace.texts-v3 :as dwt-v3]
[app.main.data.workspace.undo :as dwu]
[app.main.features :as features]
[app.main.fonts :as fonts]
@ -170,6 +171,8 @@
:else props)]
(when (and shape props)
(when (features/active-feature? @st/state "text-editor-wasm/v1")
(st/emit! (dwt-v3/v3-update-text-editor-styles (:id shape) props)))
(st/emit! (dwt/update-attrs (:id shape) props)))))
(defn blend-props

View File

@ -99,6 +99,18 @@
(or (.-isComposing native)
(= 229 (.-keyCode event)))))
(defn- input-surface-class
"Class list for the contenteditable capture surface.
Mousetrap's `stopCallback` drops every keystroke whose target is
contentEditable, so without the `mousetrap` class (as in V1/V2) the text
shortcuts (Ctrl+B, Ctrl+I, …) never reach the dispatcher."
[rotation]
(dm/str "mousetrap "
(cur/get-dynamic "text" rotation)
" "
(stl/css :text-editor-container)))
(mf/defc text-editor*
"Contenteditable element positioned over the text shape to capture input events."
[{:keys [shape]}]
@ -359,7 +371,9 @@
(let [native-event (dom/event->native-event event)
off-pt (dom/get-offset-position native-event)]
(mf/set-ref-val! dragging-ref true)
(wasm.api/text-editor-pointer-down off-pt)
(if (.-shiftKey event)
(wasm.api/text-editor-pointer-down-extend off-pt)
(wasm.api/text-editor-pointer-down off-pt))
;; Repaint the caret over the cached tiles instead of a full render,
;; which flashes at high zoom (see `render-text-editor-overlay!`).
(wasm.api/render-text-editor-overlay!))))
@ -505,7 +519,5 @@
:on-focus on-focus
:on-blur on-blur
:id "text-editor-wasm-input"
:class (dm/str (cur/get-dynamic "text" (:rotation shape))
" "
(stl/css :text-editor-container))
:class (input-surface-class (:rotation shape))
:data-testid "text-editor-container"}]]]]))

View File

@ -281,6 +281,7 @@
(def text-editor-set-cursor-from-point text-editor/text-editor-set-cursor-from-point)
(def text-editor-toggle-overtype-mode text-editor/text-editor-toggle-overtype-mode)
(def text-editor-pointer-down text-editor/text-editor-pointer-down)
(def text-editor-pointer-down-extend text-editor/text-editor-pointer-down-extend)
(def text-editor-pointer-move text-editor/text-editor-pointer-move)
(def text-editor-pointer-up text-editor/text-editor-pointer-up)
(def text-editor-get-current-styles text-editor/text-editor-get-current-styles)

View File

@ -222,6 +222,12 @@
(when (wasm/ready?)
(h/call wasm/internal-module "_text_editor_pointer_down" x y)))
(defn text-editor-pointer-down-extend
"Extends the selection up to the pointer instead of collapsing the caret."
[{:keys [x y]}]
(when (wasm/ready?)
(h/call wasm/internal-module "_text_editor_pointer_down_extend" x y)))
(defn text-editor-pointer-move
[{:keys [x y]}]
(when (wasm/ready?)

View File

@ -192,6 +192,35 @@ pub extern "C" fn text_editor_pointer_down(x: f32, y: f32) {
});
}
/// Like `text_editor_pointer_down`, but keeps the current anchor and moves the
/// focus to the pointer instead of collapsing the caret there (Shift+click).
#[no_mangle]
pub extern "C" fn text_editor_pointer_down_extend(x: f32, y: f32) {
with_state!(state, {
if !get_text_editor_state().has_focus {
return;
}
let Some(shape_id) = get_text_editor_state().active_shape_id else {
return;
};
let Some(shape) = state.shapes.get(&shape_id) else {
return;
};
let Type::Text(text_content) = &shape.shape_type else {
return;
};
let point = Point::new(x, y);
get_text_editor_state().start_pointer_selection();
if let Some(position) = text_content.get_caret_position_from_shape_coords(&point) {
get_text_editor_state().extend_selection_from_position(&position);
// The click after pointerup would collapse the caret and drop the
// selection we just extended.
get_text_editor_state().is_click_event_skipped = true;
get_text_editor_state().update_styles(text_content);
}
});
}
#[no_mangle]
pub extern "C" fn text_editor_pointer_move(x: f32, y: f32) {
with_state!(state, {