@@ -266,7 +266,6 @@ function RemoteFunctions(config = {}) {
266266 this . elements = [ ] ;
267267 this . selector = "" ;
268268 this . _divs = [ ] ;
269- this . _originalOutlines = new Map ( ) ;
270269 }
271270
272271 Highlight . prototype = {
@@ -278,12 +277,6 @@ function RemoteFunctions(config = {}) {
278277 _trigger ( element , "highlight" , 1 ) ;
279278 }
280279
281- // Save original outline and apply highlight outline
282- this . _originalOutlines . set ( element , element . style . outline ) ;
283- const isEditable = element . hasAttribute ( GLOBALS . DATA_BRACKETS_ID_ATTR ) ;
284- const outlineColor = isEditable ? COLORS . outlineEditable : COLORS . outlineNonEditable ;
285- element . style . outline = `1px solid ${ outlineColor } ` ;
286-
287280 this . elements . push ( element ) ;
288281 this . _createOverlay ( element ) ;
289282 } ,
@@ -302,14 +295,6 @@ function RemoteFunctions(config = {}) {
302295 } ) ;
303296 }
304297
305- // Restore original outlines
306- this . elements . forEach ( function ( el ) {
307- if ( this . _originalOutlines . has ( el ) ) {
308- el . style . outline = this . _originalOutlines . get ( el ) ;
309- }
310- } , this ) ;
311- this . _originalOutlines = new Map ( ) ;
312-
313298 this . elements = [ ] ;
314299 } ,
315300
@@ -326,11 +311,8 @@ function RemoteFunctions(config = {}) {
326311 if ( bounds . width === 0 && bounds . height === 0 ) { return ; }
327312
328313 const cs = window . getComputedStyle ( element ) ;
329- const div = window . document . createElement ( "div" ) ;
330- div . className = GLOBALS . HIGHLIGHT_CLASSNAME ;
331- div . trackingElement = element ;
332314
333- // Parse box model values
315+ // Parse box model values (getComputedStyle always resolves to px)
334316 const bt = parseFloat ( cs . borderTopWidth ) || 0 ,
335317 br = parseFloat ( cs . borderRightWidth ) || 0 ,
336318 bb = parseFloat ( cs . borderBottomWidth ) || 0 ,
@@ -344,72 +326,107 @@ function RemoteFunctions(config = {}) {
344326 mb = parseFloat ( cs . marginBottom ) || 0 ,
345327 ml = parseFloat ( cs . marginLeft ) || 0 ;
346328
347- const isBorderBox = cs . boxSizing === "border-box" ;
348- const w = parseFloat ( cs . width ) || 0 ;
349- const h = parseFloat ( cs . height ) || 0 ;
350-
351- // Dimensions inside border
352- let innerW , innerH ;
353- if ( isBorderBox ) {
354- innerW = w - bl - br ;
355- innerH = h - bt - bb ;
356- } else {
357- innerW = w + pl + pr ;
358- innerH = h + pt + pb ;
359- }
360- const contentH = innerH - pt - pb ;
361- const outerW = innerW + bl + br ;
362- const outerH = innerH + bt + bb ;
363-
364- // Position the overlay to match the element
365- const offset = LivePreviewView . screenOffset ( element ) ;
329+ // Compute the 4 absolute boxes exactly like dev tools:
330+ // getBoundingClientRect() always returns the border box regardless of box-sizing.
331+ const scroll = LivePreviewView . screenOffset ( element ) ;
332+ const borderBox = {
333+ left : scroll . left ,
334+ top : scroll . top ,
335+ width : bounds . width ,
336+ height : bounds . height
337+ } ;
338+ const paddingBox = {
339+ left : borderBox . left + bl ,
340+ top : borderBox . top + bt ,
341+ width : borderBox . width - bl - br ,
342+ height : borderBox . height - bt - bb
343+ } ;
344+ const contentBox = {
345+ left : paddingBox . left + pl ,
346+ top : paddingBox . top + pt ,
347+ width : paddingBox . width - pl - pr ,
348+ height : paddingBox . height - pt - pb
349+ } ;
350+ const marginBox = {
351+ left : borderBox . left - ml ,
352+ top : borderBox . top - mt ,
353+ width : borderBox . width + ml + mr ,
354+ height : borderBox . height + mt + mb
355+ } ;
356+
357+ // Container div — sized to the margin box so all rects fit inside it
358+ const div = window . document . createElement ( "div" ) ;
359+ div . className = GLOBALS . HIGHLIGHT_CLASSNAME ;
360+ div . trackingElement = element ;
366361 const divStyle = div . style ;
367362 divStyle . position = "absolute" ;
368- divStyle . left = offset . left + "px" ;
369- divStyle . top = offset . top + "px" ;
370- divStyle . width = bounds . width + "px" ;
371- divStyle . height = bounds . height + "px" ;
363+ divStyle . left = marginBox . left + "px" ;
364+ divStyle . top = marginBox . top + "px" ;
365+ divStyle . width = marginBox . width + "px" ;
366+ divStyle . height = marginBox . height + "px" ;
372367 divStyle . zIndex = 2147483645 ;
373368 divStyle . margin = "0" ;
374369 divStyle . padding = "0" ;
370+ divStyle . border = "none" ;
375371 divStyle . pointerEvents = "none" ;
376- divStyle . boxSizing = cs . boxSizing ;
377- divStyle . borderTopWidth = bt + "px" ;
378- divStyle . borderRightWidth = br + "px" ;
379- divStyle . borderBottomWidth = bb + "px" ;
380- divStyle . borderLeftWidth = bl + "px" ;
381- divStyle . borderStyle = "solid" ;
382- divStyle . borderColor = "transparent" ;
383-
384- // Helper to create a colored rect
385- function makeRect ( styles , color ) {
386- if ( parseFloat ( styles . width ) <= 0 || parseFloat ( styles . height ) <= 0 ) { return ; }
372+ divStyle . boxSizing = "border-box" ;
373+
374+ // Helper to create a colored rect at absolute page coordinates, offset by the container origin
375+ function makeRect ( left , top , width , height , color ) {
376+ if ( width <= 0 || height <= 0 ) { return ; }
387377 const r = window . document . createElement ( "div" ) ;
388378 r . style . position = "absolute" ;
379+ r . style . left = ( left - marginBox . left ) + "px" ;
380+ r . style . top = ( top - marginBox . top ) + "px" ;
381+ r . style . width = width + "px" ;
382+ r . style . height = height + "px" ;
389383 r . style . backgroundColor = color ;
390- r . style . transform = "none" ;
391- for ( const prop in styles ) {
392- r . style [ prop ] = styles [ prop ] ;
393- }
394384 div . appendChild ( r ) ;
395385 }
396386
397- // Padding rects (top/bottom full width, left/right content height)
387+ // Padding region: 4 rects filling paddingBox minus contentBox
398388 const padColor = COLORS . highlightPadding ;
399- makeRect ( { top : "0" , left : "0" , width : innerW + "px" , height : pt + "px" } , padColor ) ;
400- makeRect ( { bottom : "0" , left : "0" , width : innerW + "px" , height : pb + "px" } , padColor ) ;
401- makeRect ( { top : pt + "px" , left : "0" , width : pl + "px" , height : contentH + "px" } , padColor ) ;
402- makeRect ( { top : pt + "px" , right : "0" , width : pr + "px" , height : contentH + "px" } , padColor ) ;
403-
404- // Margin rects (top/bottom element width, left/right full height)
389+ // top padding
390+ makeRect ( paddingBox . left , paddingBox . top ,
391+ paddingBox . width , pt , padColor ) ;
392+ // bottom padding
393+ makeRect ( paddingBox . left , contentBox . top + contentBox . height ,
394+ paddingBox . width , pb , padColor ) ;
395+ // left padding
396+ makeRect ( paddingBox . left , contentBox . top ,
397+ pl , contentBox . height , padColor ) ;
398+ // right padding
399+ makeRect ( contentBox . left + contentBox . width , contentBox . top ,
400+ pr , contentBox . height , padColor ) ;
401+
402+ // Margin region: 4 rects filling marginBox minus borderBox
405403 const margColor = COLORS . highlightMargin ;
406- const mTop = - ( mt + bt ) + "px" ;
407- const mBot = - ( mb + bb ) + "px" ;
408- const fullH = ( outerH + mt + mb ) + "px" ;
409- makeRect ( { top : mTop , left : - bl + "px" , width : outerW + "px" , height : mt + "px" } , margColor ) ;
410- makeRect ( { bottom : mBot , left : - bl + "px" , width : outerW + "px" , height : mb + "px" } , margColor ) ;
411- makeRect ( { top : mTop , left : - ( ml + bl ) + "px" , width : ml + "px" , height : fullH } , margColor ) ;
412- makeRect ( { top : mTop , right : - ( mr + br ) + "px" , width : mr + "px" , height : fullH } , margColor ) ;
404+ // top margin
405+ makeRect ( marginBox . left , marginBox . top ,
406+ marginBox . width , mt , margColor ) ;
407+ // bottom margin
408+ makeRect ( marginBox . left , borderBox . top + borderBox . height ,
409+ marginBox . width , mb , margColor ) ;
410+ // left margin
411+ makeRect ( marginBox . left , borderBox . top ,
412+ ml , borderBox . height , margColor ) ;
413+ // right margin
414+ makeRect ( borderBox . left + borderBox . width , borderBox . top ,
415+ mr , borderBox . height , margColor ) ;
416+
417+ // Selection outline: 1px border at the border-box edge (drawn inside the border area)
418+ const isEditable = element . hasAttribute ( GLOBALS . DATA_BRACKETS_ID_ATTR ) ;
419+ const outlineColor = isEditable ? COLORS . outlineEditable : COLORS . outlineNonEditable ;
420+ const outlineDiv = window . document . createElement ( "div" ) ;
421+ outlineDiv . style . position = "absolute" ;
422+ outlineDiv . style . left = ( borderBox . left - marginBox . left ) + "px" ;
423+ outlineDiv . style . top = ( borderBox . top - marginBox . top ) + "px" ;
424+ outlineDiv . style . width = borderBox . width + "px" ;
425+ outlineDiv . style . height = borderBox . height + "px" ;
426+ outlineDiv . style . border = `1px solid ${ outlineColor } ` ;
427+ outlineDiv . style . boxSizing = "border-box" ;
428+ outlineDiv . style . pointerEvents = "none" ;
429+ div . appendChild ( outlineDiv ) ;
413430
414431 window . document . body . appendChild ( div ) ;
415432 this . _divs . push ( div ) ;
@@ -451,8 +468,8 @@ function RemoteFunctions(config = {}) {
451468 if ( _hoverHighlight && shouldShowHighlightOnHover ( ) ) {
452469 _hoverHighlight . clear ( ) ;
453470
454- // Skip hover outline and overlay for the currently click-selected element.
455- // It already has its own outline and overlay from the click/selection flow,
471+ // Skip hover overlay for the currently click-selected element.
472+ // It already has its own overlay from the click/selection flow,
456473 // and adding hover state on top would stack duplicate overlays.
457474 if ( element !== previouslySelectedElement ) {
458475 _hoverHighlight . add ( element ) ;
@@ -508,7 +525,7 @@ function RemoteFunctions(config = {}) {
508525 * this function is responsible to select an element in the live preview
509526 * @param {Element } element - The DOM element to select
510527 * @param {boolean } [fromEditor] - If true, this is an editor-cursor-driven selection;
511- * only lightweight highlights (outline + margin/padding) are shown, not interactive
528+ * only lightweight highlights (outline, margin/padding overlay ) are shown, not interactive
512529 * UI like control box, spacing handles, or measurements.
513530 */
514531 function selectElement ( element , fromEditor ) {
@@ -1113,13 +1130,6 @@ function RemoteFunctions(config = {}) {
11131130 if ( previouslySelectedElement && ! previouslySelectedElement . isConnected ) {
11141131 dismissUIAndCleanupState ( ) ;
11151132 } else {
1116- // Re-apply outline since attrChange may have wiped it
1117- // (e.g. user edited the style attribute in source)
1118- if ( previouslySelectedElement && previouslySelectedElement . isConnected ) {
1119- const isEditable = previouslySelectedElement . hasAttribute ( GLOBALS . DATA_BRACKETS_ID_ATTR ) ;
1120- const outlineColor = isEditable ? COLORS . outlineEditable : COLORS . outlineNonEditable ;
1121- previouslySelectedElement . style . outline = `1px solid ${ outlineColor } ` ;
1122- }
11231133 redrawEverything ( ) ;
11241134 }
11251135 } else {
@@ -1177,11 +1187,6 @@ function RemoteFunctions(config = {}) {
11771187 window . __current_ph_lp_selected = freshElement ;
11781188 redrawEverything ( ) ;
11791189 }
1180- } else if ( previouslySelectedElement && previouslySelectedElement . isConnected ) {
1181- // Re-apply outline since attrChange may have wiped it
1182- const isEditable = previouslySelectedElement . hasAttribute ( GLOBALS . DATA_BRACKETS_ID_ATTR ) ;
1183- const outlineColor = isEditable ? COLORS . outlineEditable : COLORS . outlineNonEditable ;
1184- previouslySelectedElement . style . outline = `1px solid ${ outlineColor } ` ;
11851190 }
11861191 }
11871192 } ;
@@ -1253,7 +1258,7 @@ function RemoteFunctions(config = {}) {
12531258 window . __current_ph_lp_selected = null ;
12541259 }
12551260
1256- // Highlight.clear() handles both outline restoration and overlay removal
1261+ // Highlight.clear() removes all overlay divs (outline + margin/padding rects)
12571262 hideHighlight ( ) ;
12581263
12591264 if ( config . mode === 'edit' ) {
0 commit comments