🐛 Fix .component() returning outermost component for nested instances

The shape API method .component() used locate-component which walks
to the outermost instance root via get-instance-root. For nested
component instances (e.g. a button inside a card), this incorrectly
returned the outer component (the card) instead of the nearest one
(the button).

Added locate-head-component in utils.cljs which uses get-head-shape
to find the nearest component head, and updated the :component
property in shape.cljs to use it.

Fixes #9183
This commit is contained in:
Dominik Jain 2026-04-28 17:24:06 +02:00 committed by Alonso Torres
parent 4ce56e96fe
commit 07ad152ae5
3 changed files with 14 additions and 2 deletions

View File

@ -130,6 +130,7 @@
- Fix internal error on layer prev/next sibling selection (by @jsdevninja) [Github #9003](https://github.com/penpot/penpot/issues/9003)
- Fix tooltip appearing two times when nested elements [Github #9031](https://github.com/penpot/penpot/issues/9031)
- Fix broken update library notification link in the UI [Github #9070](https://github.com/penpot/penpot/issues/9070)
- Fix plugin API `ShapeBase.component()` returning the outermost component instead of the immediate component in case of nested component instances [Github #9183](https://github.com/penpot/penpot/issues/9183)
## 2.15.0 (Unreleased)

View File

@ -1186,8 +1186,8 @@
(let [objects (u/locate-objects file-id page-id)
shape (u/locate-shape file-id page-id id)]
(when (ctn/in-any-component? objects shape)
(let [[root component] (u/locate-component objects shape)]
(lib-component-proxy plugin-id (:component-file root) (:id component))))))
(when-let [[head component] (u/locate-head-component objects shape)]
(lib-component-proxy plugin-id (:component-file head) (:id component))))))
:detach
(fn []

View File

@ -100,6 +100,17 @@
root (ctn/get-instance-root objects shape)]
[root (ctf/resolve-component root file libraries {:include-deleted? true})]))
(defn locate-head-component
"Like locate-component but resolves via the nearest component head
instead of the outermost instance root."
[objects shape]
(let [state (deref st/state)
file (dsh/lookup-file state)
libraries (dsh/lookup-libraries state)
head (ctn/get-head-shape objects shape)]
(when head
[head (ctf/resolve-component head file libraries {:include-deleted? true})])))
(defn proxy->file
[proxy]
(let [id (obj/get proxy "$id")]