Add Tab/Shift+Tab navigation to rename layers sequentially

This commit is contained in:
bittoby
2026-03-02 12:51:23 +01:00
committed by Andrey Antukh
parent 23e77b5f03
commit c18375c66e
2 changed files with 55 additions and 12 deletions

View File

@@ -58,7 +58,8 @@
is-filtered is-expanded dnd-over dnd-over-top dnd-over-bot hide-toggle
;; Callbacks
on-select-shape on-context-menu on-pointer-enter on-pointer-leave on-zoom-to-selected
on-toggle-collapse on-enable-drag on-disable-drag on-toggle-visibility on-toggle-blocking]}]
on-toggle-collapse on-enable-drag on-disable-drag on-toggle-visibility on-toggle-blocking
on-tab-press]}]
(let [id (:id item)
name (:name item)
@@ -164,7 +165,8 @@
:variant-properties variant-properties
:variant-error variant-error
:component-id component-id
:is-hidden hidden?}]]
:is-hidden hidden?
:on-tab-press on-tab-press}]]
(when (not ^boolean is-read-only)
[:div {:class (stl/css-case
:element-actions true
@@ -416,7 +418,24 @@
;; We don't want to change the structure of component copies
:draggable? (and ^boolean is-sortable
^boolean (not is-read-only)
^boolean (not (ctn/has-any-copy-parent? objects item))))]
^boolean (not (ctn/has-any-copy-parent? objects item))))
on-tab-press
(mf/use-fn
(mf/deps id objects)
(fn [shift?]
(let [shape (get objects id)
parent (get objects (:parent-id shape))
siblings (:shapes parent)
pos (d/index-of siblings id)]
(when (some? pos)
(let [;; Layers render in reverse: Tab (visually down) = dec index,
;; Shift+Tab (visually up) = inc index
target-id (if shift?
(get siblings (inc pos))
(get siblings (dec pos)))]
(when (some? target-id)
(st/emit! (dw/start-rename-shape target-id)))))))))]
(mf/with-effect [is-selected selected]
(let [single? (= (count selected) 1)
@@ -531,6 +550,7 @@
:on-disable-drag disable-drag
:on-toggle-visibility toggle-visibility
:on-toggle-blocking toggle-blocking
:on-tab-press on-tab-press
:style style}
(when (and ^boolean render-children

View File

@@ -24,11 +24,17 @@
[{:keys [shape-id rename-id shape-name is-shape-touched disabled-double-click
on-start-edit on-stop-edit depth parent-size is-selected
type-comp type-frame component-id is-hidden is-blocked
variant-id variant-name variant-properties variant-error ref]}]
variant-id variant-name variant-properties variant-error
on-tab-press ref]}]
(let [edition* (mf/use-state false)
edition? (deref edition*)
;; Mutable ref to track editing state inside mf/use-fn callbacks.
;; mf/use-state wraps React useState, so @edition* inside memoized
;; callbacks captures a stale State object. A ref is a stable mutable
;; container that always reflects the latest value.
editing-ref (mf/use-ref false)
local-ref (mf/use-ref)
ref (d/nilv ref local-ref)
@@ -53,6 +59,7 @@
(when (and (not is-blocked)
(not disabled-double-click))
(on-start-edit)
(mf/set-ref-val! editing-ref true)
(reset! edition* true)
(st/emit! (dw/start-rename-shape shape-id)))))
@@ -60,26 +67,42 @@
(mf/use-fn
(mf/deps shape-id on-stop-edit component-id variant-id variant-name variant-properties)
(fn []
(let [name-input (mf/ref-val ref)
name (str/trim (dom/get-value name-input))]
(on-stop-edit)
(reset! edition* false)
(st/emit! (dw/rename-shape-or-variant shape-id name)))))
(when (mf/ref-val editing-ref)
(let [name-input (mf/ref-val ref)
name (str/trim (dom/get-value name-input))]
(on-stop-edit)
(mf/set-ref-val! editing-ref false)
(reset! edition* false)
(st/emit! (dw/rename-shape-or-variant shape-id name))))))
cancel-edit
(mf/use-fn
(mf/deps shape-id on-stop-edit)
(fn []
(on-stop-edit)
(mf/set-ref-val! editing-ref false)
(reset! edition* false)
(st/emit! (dw/end-rename-shape shape-id nil))))
on-key-down
(mf/use-fn
(mf/deps accept-edit cancel-edit)
(mf/deps accept-edit cancel-edit on-tab-press shape-id on-stop-edit)
(fn [event]
(when (kbd/enter? event) (accept-edit))
(when (kbd/esc? event) (cancel-edit))))
(when (kbd/esc? event) (cancel-edit))
(when (kbd/tab? event)
(dom/prevent-default event)
(dom/stop-propagation event)
(when (mf/ref-val editing-ref)
(let [shift? (kbd/shift? event)
name-input (mf/ref-val ref)
name (str/trim (dom/get-value name-input))]
(on-stop-edit)
(mf/set-ref-val! editing-ref false)
(reset! edition* false)
(st/emit! (dw/end-rename-shape shape-id name))
(when (fn? on-tab-press)
(on-tab-press shift?)))))))
parent-size
(dm/str (- parent-size space-for-icons) "px")]