From 344dd177768e0cd4ea7be5e8ce86b2ab30ede973 Mon Sep 17 00:00:00 2001 From: Pluto Date: Wed, 29 Jul 2026 18:47:19 +0530 Subject: [PATCH 1/4] fix: ignore phoenix's own elements when locating the selected element --- .../BrowserScripts/RemoteFunctions.js | 65 +++++++++++++++---- 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/src/LiveDevelopment/BrowserScripts/RemoteFunctions.js b/src/LiveDevelopment/BrowserScripts/RemoteFunctions.js index b09735221d..434ade54cb 100644 --- a/src/LiveDevelopment/BrowserScripts/RemoteFunctions.js +++ b/src/LiveDevelopment/BrowserScripts/RemoteFunctions.js @@ -190,7 +190,10 @@ function RemoteFunctions(config = {}) { disableHoverListeners: disableHoverListeners, enableHoverListeners: enableHoverListeners, redrawHighlights: redrawHighlights, - redrawEverything: redrawEverything + redrawEverything: redrawEverything, + getTreePath: _getTreePath, + getElementByTreePath: _getElementByTreePath, + getSourceChildren: _instrumentedChildren }; /** @@ -1054,6 +1057,25 @@ function RemoteFunctions(config = {}) { return results && results[0]; }; + // True for elements Phoenix adds to the page itself, like the tool boxes and + // the highlight overlays. They are not part of the user's source file. + function _isPhoenixInternalNode(node) { + return !!node && node.nodeType === Node.ELEMENT_NODE && + (node.hasAttribute(GLOBALS.PHCODE_INTERNAL_ATTR) || + node.className === GLOBALS.HIGHLIGHT_CLASSNAME); + } + + /** The first of the Phoenix elements sitting at the end of `parent`, else null. */ + function _firstTrailingInternalNode(parent) { + let node = parent.lastChild; + let first = null; + while (_isPhoenixInternalNode(node)) { + first = node; + node = node.previousSibling; + } + return first; + } + /** * @private * Insert a new child element @@ -1068,7 +1090,12 @@ function RemoteFunctions(config = {}) { if (edit.firstChild) { before = targetElement.firstChild; } else if (edit.lastChild) { - after = targetElement.lastChild; + // Phoenix's tool boxes are the last children of , so appending + // here would put the new element after them, in the wrong place. + before = _firstTrailingInternalNode(targetElement); + if (!before) { + after = targetElement.lastChild; + } } if (before) { @@ -1492,27 +1519,38 @@ function RemoteFunctions(config = {}) { } } + // Only the children that came from the source file. Phoenix's own elements have + // no data-brackets-id, and counting them would shift the tree path indexes. + function _instrumentedChildren(parent) { + const result = []; + const children = (parent && parent.children) || []; + for (let i = 0; i < children.length; i++) { + if (children[i].hasAttribute(GLOBALS.DATA_BRACKETS_ID_ATTR)) { + result.push(children[i]); + } + } + return result; + } + /** * Compute the tree path of an element as an array of child indices * from down. Used to re-locate the element after re-instrumentation * when data-brackets-id changes and text matching is ambiguous. * E.g. [1, 0, 0, 1] means html > 2nd child > 1st child > 1st child > 2nd child. + * @return {?Array.} null if the element did not come from the source file. */ function _getTreePath(element) { const path = []; let el = element; while (el && el.parentElement) { - const parent = el.parentElement; - const children = parent.children; - for (let i = 0; i < children.length; i++) { - if (children[i] === el) { - path.unshift(i); - break; - } + const index = _instrumentedChildren(el.parentElement).indexOf(el); + if (index === -1) { + return null; } - el = parent; + path.unshift(index); + el = el.parentElement; } - return path; + return path.length ? path : null; } /** @@ -1521,10 +1559,11 @@ function RemoteFunctions(config = {}) { function _getElementByTreePath(path) { let el = document.documentElement; for (let i = 0; i < path.length; i++) { - if (!el || !el.children || !el.children[path[i]]) { + const siblings = _instrumentedChildren(el); + if (!siblings[path[i]]) { return null; } - el = el.children[path[i]]; + el = siblings[path[i]]; } return el; } From e86dfead2819979ab90c4a8cf6fc9284dca2b8cc Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 30 Jul 2026 00:36:42 +0530 Subject: [PATCH 2/4] feat: add api for controlling visibility of margin padding in element selection for styles bar --- .../BrowserScripts/RemoteFunctions.js | 30 ++++++++++++++++--- src/nls/root/strings.js | 1 + 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/LiveDevelopment/BrowserScripts/RemoteFunctions.js b/src/LiveDevelopment/BrowserScripts/RemoteFunctions.js index 434ade54cb..29862d96b7 100644 --- a/src/LiveDevelopment/BrowserScripts/RemoteFunctions.js +++ b/src/LiveDevelopment/BrowserScripts/RemoteFunctions.js @@ -26,7 +26,8 @@ function RemoteFunctions(config = {}) { const SHARED_STATE = { __description: "Use this to keep shared state for Live Preview Edit instead of window.*", _suppressDOMEditDismissal: false, - _suppressDOMEditDismissalTimeout: null + _suppressDOMEditDismissalTimeout: null, + _boxModelHighlightHidden: false }; let _hoverHighlight; @@ -449,15 +450,17 @@ function RemoteFunctions(config = {}) { s.backgroundColor = color; } - // Padding region - const padColor = COLORS.highlightPadding; + // Padding region. Rects stay in place when hidden, only their fill goes away, + // so nothing has to be rebuilt when they come back. + const boxModelHidden = SHARED_STATE._boxModelHighlightHidden; + const padColor = boxModelHidden ? "transparent" : COLORS.highlightPadding; setRect(refs.padTop, paddingBox.left, paddingBox.top, paddingBox.width, pt, padColor); setRect(refs.padBottom, paddingBox.left, contentBox.top + contentBox.height, paddingBox.width, pb, padColor); setRect(refs.padLeft, paddingBox.left, contentBox.top, pl, contentBox.height, padColor); setRect(refs.padRight, contentBox.left + contentBox.width, contentBox.top, pr, contentBox.height, padColor); // Margin region - const margColor = COLORS.highlightMargin; + const margColor = boxModelHidden ? "transparent" : COLORS.highlightMargin; setRect(refs.marTop, marginBox.left, marginBox.top, marginBox.width, mt, margColor); setRect(refs.marBottom, marginBox.left, borderBox.top + borderBox.height, marginBox.width, mb, margColor); setRect(refs.marLeft, marginBox.left, borderBox.top, ml, borderBox.height, margColor); @@ -1506,6 +1509,9 @@ function RemoteFunctions(config = {}) { _pendingHoverRAF = null; } + // the selection is gone, so a popover can no longer turn the fills back on + SHARED_STATE._boxModelHighlightHidden = false; + // Highlight.clear() removes all overlay divs (outline + margin/padding rects) hideHighlight(); @@ -1766,6 +1772,21 @@ function RemoteFunctions(config = {}) { } } + /** + * Hide just the margin/padding fills of the selected element highlight, keeping + * the outline and the selection itself. Used while editing paint properties like + * background color, where the fills sit on top of what the user is changing. + * @param {Boolean} hidden + */ + function setBoxModelHighlightHidden(hidden) { + hidden = !!hidden; + if (SHARED_STATE._boxModelHighlightHidden === hidden) { + return; + } + SHARED_STATE._boxModelHighlightHidden = hidden; + redrawHighlights(); + } + let customReturns = {}; // only apis that needs to be called from phoenix js layer should be customReturns. APis that are shared within // the remote function context only should not be in customReturns and should be in @@ -1789,6 +1810,7 @@ function RemoteFunctions(config = {}) { "getHighlightTrackingElement": getHighlightTrackingElement, "getHighlightStyle": getHighlightStyle, "setHotCornerHidden": setHotCornerHidden, + "setBoxModelHighlightHidden": setBoxModelHighlightHidden, "clearHoverState": _clearHoverState }; diff --git a/src/nls/root/strings.js b/src/nls/root/strings.js index 2aa2a2031e..cf2716b780 100644 --- a/src/nls/root/strings.js +++ b/src/nls/root/strings.js @@ -202,6 +202,7 @@ define({ "LIVE_DEV_STYLER_BACKGROUND": "Background color", "LIVE_DEV_STYLER_TEXT_COLOR": "Text color", "LIVE_DEV_STYLER_FONT": "Font family", + "LIVE_DEV_STYLER_FONT_DEFAULT": "Default", "LIVE_DEV_STYLER_SIZE": "Font size", "LIVE_DEV_STYLER_WEIGHT": "Font weight", "LIVE_DEV_STYLER_ALIGN": "Text alignment", From a5d7039baafd75db4c93d45eec6b1bd55ea08763 Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 30 Jul 2026 16:18:49 +0530 Subject: [PATCH 3/4] build: update pro deps --- docs/API-Reference/command/Commands.md | 2 +- src-node/package-lock.json | 12 ------------ src/nls/root/strings.js | 2 +- tracking-repos.json | 2 +- 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/docs/API-Reference/command/Commands.md b/docs/API-Reference/command/Commands.md index 24bad4cd08..d535db0d51 100644 --- a/docs/API-Reference/command/Commands.md +++ b/docs/API-Reference/command/Commands.md @@ -986,7 +986,7 @@ Opens git settings ## CMD\_GIT\_CLOSE\_UNMODIFIED Closes unmodified files -**Kind**: global variable +**Kind**: global variable ## CMD\_GIT\_OPEN\_CHANGED\_FILES diff --git a/src-node/package-lock.json b/src-node/package-lock.json index 673a465423..a9fac4c791 100644 --- a/src-node/package-lock.json +++ b/src-node/package-lock.json @@ -88,9 +88,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "SEE LICENSE IN LICENSE.md", "optional": true, "os": [ @@ -104,9 +101,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "SEE LICENSE IN LICENSE.md", "optional": true, "os": [ @@ -120,9 +114,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "SEE LICENSE IN LICENSE.md", "optional": true, "os": [ @@ -136,9 +127,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "SEE LICENSE IN LICENSE.md", "optional": true, "os": [ diff --git a/src/nls/root/strings.js b/src/nls/root/strings.js index cf2716b780..255989b398 100644 --- a/src/nls/root/strings.js +++ b/src/nls/root/strings.js @@ -207,7 +207,7 @@ define({ "LIVE_DEV_STYLER_WEIGHT": "Font weight", "LIVE_DEV_STYLER_ALIGN": "Text alignment", "LIVE_DEV_STYLER_BORDER": "Border", - "LIVE_DEV_STYLER_SPACING": "Margin & padding", + "LIVE_DEV_STYLER_SPACING": "Box model", "LIVE_DEV_STYLER_LAYOUT": "Layout", "LIVE_DEV_STYLER_TEXT_STYLE": "Text style", "LIVE_DEV_STYLER_DOCK_TOP": "Dock to top", diff --git a/tracking-repos.json b/tracking-repos.json index 0dff12e0a5..f58c08b100 100644 --- a/tracking-repos.json +++ b/tracking-repos.json @@ -1,5 +1,5 @@ { "phoenixPro": { - "commitID": "73d6e0afa0e6788d0c8338b5e62983891879c802" + "commitID": "4aa07ee038916c8765baa9f87959759a657b9221" } } From 8b826308d152aa734f1577cac692b1b9b45f578e Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 30 Jul 2026 16:25:37 +0530 Subject: [PATCH 4/4] fix: failing html instrumention test as has and get attribute apis not present --- test/spec/HTMLInstrumentation-test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/spec/HTMLInstrumentation-test.js b/test/spec/HTMLInstrumentation-test.js index 9291bbbffd..055a85f278 100644 --- a/test/spec/HTMLInstrumentation-test.js +++ b/test/spec/HTMLInstrumentation-test.js @@ -233,6 +233,12 @@ define(function (require, exports, module) { removeAttribute: function (key) { delete this.attributes[key]; }, + hasAttribute: function (key) { + return !!this.attributes && this.attributes.hasOwnProperty(key); + }, + getAttribute: function (key) { + return (this.attributes && this.attributes.hasOwnProperty(key)) ? this.attributes[key] : null; + }, returnFailure: function (other) { console.log("TEST FAILURE AT TAG ID ", this.tagID, this, other);