From 550dc5f96e49c24a1a4e101f6b67cda1169877d9 Mon Sep 17 00:00:00 2001 From: hitesh-shetty-cstk Date: Wed, 8 Jul 2026 15:15:08 +0530 Subject: [PATCH 1/2] fix(visual-builder): keep overlayPropagation from piercing the SDK's own toolbar With overlayPropagation enabled, clicks landing on the visual builder's own UI (field toolbar, overlays) were resolved through document.elementsFromPoint and could hit a data-cslp element rendered underneath. A click on the edit (pencil) button then also counted as a canvas click on the overlapped field, sending a focus event for the wrong entry and breaking the edit modal's apply flow. Skip the elementsFromPoint fallback whenever the click target sits inside .visual-builder__container: the fallback exists to pierce the website's own overlapping elements, never the SDK's chrome. --- .../utils/__test__/getCsDataOfElement.test.ts | 32 +++++++++++++++++++ src/visualBuilder/utils/getCsDataOfElement.ts | 15 ++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/visualBuilder/utils/__test__/getCsDataOfElement.test.ts b/src/visualBuilder/utils/__test__/getCsDataOfElement.test.ts index 91b5c471..42c01485 100644 --- a/src/visualBuilder/utils/__test__/getCsDataOfElement.test.ts +++ b/src/visualBuilder/utils/__test__/getCsDataOfElement.test.ts @@ -196,6 +196,38 @@ describe("getCsDataOfElement", () => { }); }); + test("does not pierce the visual builder's own UI (e.g. the field toolbar) even when fallback is enabled", () => { + Config.set("overlayPropagation", { enable: true }); + + // clicks on the SDK's own toolbar land on elements inside the + // visual builder container and must never resolve to the canvas + // field underneath + const vbContainer = document.createElement("div"); + vbContainer.classList.add("visual-builder__container"); + const toolbarButton = document.createElement("button"); + vbContainer.appendChild(toolbarButton); + document.body.appendChild(vbContainer); + + const toolbarClick = new MouseEvent("click", { + bubbles: true, + cancelable: true, + clientX: 100, + clientY: 100, + }); + Object.defineProperty(toolbarClick, "target", { + value: toolbarButton, + writable: false, + }); + ( + document.elementsFromPoint as ReturnType + ).mockReturnValue([toolbarButton, vbContainer, cslpEl]); + + const result = getCsDataOfElement(toolbarClick); + + expect(result).toBeUndefined(); + expect(document.elementsFromPoint).not.toHaveBeenCalled(); + }); + test("returns undefined when fallback is enabled but no element under the cursor has data-cslp", () => { Config.set("overlayPropagation", { enable: true }); const otherBlocker = document.createElement("div"); diff --git a/src/visualBuilder/utils/getCsDataOfElement.ts b/src/visualBuilder/utils/getCsDataOfElement.ts index 50cc76ca..79a864b9 100644 --- a/src/visualBuilder/utils/getCsDataOfElement.ts +++ b/src/visualBuilder/utils/getCsDataOfElement.ts @@ -28,7 +28,20 @@ export function getCsDataOfElement( let editableElement: Element | null = targetElement.closest("[data-cslp]"); - if (!editableElement && Config.get().overlayPropagation.enable) { + // Clicks on the visual builder's own UI (field toolbar, overlays, add + // buttons) must never resolve to the canvas field underneath them. The + // elementsFromPoint fallback exists to pierce the website's own empty + // overlapping elements, not the SDK's chrome: piercing the toolbar made + // the edit (pencil) button double as a click on the field it covered. + const isVisualBuilderUi = targetElement.closest( + ".visual-builder__container" + ); + + if ( + !editableElement && + !isVisualBuilderUi && + Config.get().overlayPropagation.enable + ) { const stack = document.elementsFromPoint( event.clientX, event.clientY From e4155462a6ffd5d0fa99af8f5919dca237c53ecd Mon Sep 17 00:00:00 2001 From: hitesh-shetty-cstk Date: Wed, 8 Jul 2026 16:15:43 +0530 Subject: [PATCH 2/2] refactor(visual-builder): fold the own-UI guard into the fallback condition Run the closest() check only when the overlayPropagation fallback is enabled and no field matched, so hover events skip the extra DOM traversal in the common case. --- src/visualBuilder/utils/getCsDataOfElement.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/visualBuilder/utils/getCsDataOfElement.ts b/src/visualBuilder/utils/getCsDataOfElement.ts index 79a864b9..220fd937 100644 --- a/src/visualBuilder/utils/getCsDataOfElement.ts +++ b/src/visualBuilder/utils/getCsDataOfElement.ts @@ -33,14 +33,12 @@ export function getCsDataOfElement( // elementsFromPoint fallback exists to pierce the website's own empty // overlapping elements, not the SDK's chrome: piercing the toolbar made // the edit (pencil) button double as a click on the field it covered. - const isVisualBuilderUi = targetElement.closest( - ".visual-builder__container" - ); - + // The closest() check runs last so hover events only pay for it when + // the fallback is enabled and no field matched. if ( !editableElement && - !isVisualBuilderUi && - Config.get().overlayPropagation.enable + Config.get().overlayPropagation.enable && + !targetElement.closest(".visual-builder__container") ) { const stack = document.elementsFromPoint( event.clientX,