mirror of
https://github.com/penpot/penpot.git
synced 2026-03-07 18:51:14 +00:00
✨ Add Tab/Shift+Tab navigation to rename layers sequentially
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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")]
|
||||
|
||||
Reference in New Issue
Block a user