Add Alt+click to expand a layer subtree in the Layers sidebar (#9179)

Closes #7736.

The Layers sidebar offered no way to expand every nested level of a
single subtree at once. Unfolding a layer that wraps a deep tree
required clicking each disclosure indicator one level at a time -
O(siblings * depth) clicks. The asymmetry was particularly visible
next to the existing Shift+click gesture, which collapses every
layer in the panel in a single action via `dwc/collapse-all`, with
no expand counterpart for either a single subtree or the whole
tree.

Add a new `dwc/expand-subtree` event in
`app.main.data.workspace.collapse` that uses
`cfh/get-children-ids-with-self` to gather the shape's id together
with every descendant id, then merges `{descendant-id true}` entries
into `[:workspace-local :expanded]` so the entire subtree opens in
one update. Existing expansion state on unrelated branches is left
untouched (`merge`, not `assoc`), matching the per-key shape used by
`toggle-collapse` and `expand-collapse`.

Wire the gesture into `layer_item.cljs` `toggle-collapse` callback as
a third branch:

  - Shift+click while expanded - collapse every layer (existing).
  - Alt+click while collapsed   - expand the entire subtree (new).
  - Otherwise                   - toggle this single level (existing).

Alt is chosen instead of Shift to avoid the ambiguity the issue
author flagged: "for a layer of middle depth it is unclear whether
[Shift+click] should fold all (up to the topmost parent) or expand
all (only the current subtree)". Alt is a common platform
convention for "do this recursively" (Finder, file managers,
several IDEs), so the asymmetric mapping matches user expectations.
The callback's `mf/deps` vector is extended with `id` and `objects`
so the closure refreshes when the shape tree changes.

CHANGES.md entry added under the 2.17.0 New features section.
This commit is contained in:
Milos Milic 2026-04-27 21:36:15 +02:00 committed by GitHub
parent 8a8ebb7943
commit bd1e0fb23f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 27 additions and 2 deletions

View File

@ -8,6 +8,7 @@
### :sparkles: New features & Enhancements
- Add `Alt+click` on a layer's disclosure arrow to recursively expand the entire subtree rooted at that layer in the Layers sidebar; symmetric with the existing `Shift+click` collapse-all gesture, and removes the O(siblings × depth) click cost of unfolding a deep subtree one level at a time [Github #7736](https://github.com/penpot/penpot/issues/7736)
- Show alpha percentage next to library color values to distinguish colors that differ only in opacity (by @rockchris099) [Github #6328](https://github.com/penpot/penpot/issues/6328)
- Add "Clear artboard guides" option to right-click context menu for frames (by @eureka0928) [Github #6987](https://github.com/penpot/penpot/issues/6987)
- Add loader feedback while importing and exporting files [Github #9020](https://github.com/penpot/penpot/issues/9020)

View File

@ -49,3 +49,19 @@
(update [_ state]
(update state :workspace-local dissoc :expanded))))
(defn expand-subtree
"Recursively expand the layer subtree rooted at `id`, marking the shape
and all of its descendants as expanded in the Layers sidebar.
Closes the gap with `collapse-all`: there was no symmetric way to
open every nested level of a single subtree, so unfolding a deep
shape required clicking each disclosure indicator one by one
(O(siblings × depth) clicks)."
[id objects]
(ptk/reify ::expand-subtree
ptk/UpdateEvent
(update [_ state]
(let [ids (cfh/get-children-ids-with-self objects id)
expansions (into {} (map (fn [descendant-id] [descendant-id true])) ids)]
(update-in state [:workspace-local :expanded] merge expansions)))))

View File

@ -275,11 +275,19 @@
toggle-collapse
(mf/use-fn
(mf/deps is-expanded)
(mf/deps is-expanded id objects)
(fn [event]
(dom/stop-propagation event)
(if (and is-expanded (kbd/shift? event))
(cond
;; Shift+click while expanded collapses every layer in the sidebar
(and is-expanded (kbd/shift? event))
(st/emit! (dwc/collapse-all))
;; Alt+click while collapsed expands the entire subtree rooted at this id
(and (not is-expanded) (kbd/alt? event))
(st/emit! (dwc/expand-subtree id objects))
:else
(st/emit! (dwc/toggle-collapse id)))))
toggle-blocking