Skip to content

#3538727 Nested astro overlay fixes

This is a three pronged solution to various issues with the positioning of the overlays for slots and components.

First, the iFrame swapper has been refactored. Previously the iFrame swap was being done on the 'load' event of the iframe document. Now I have created a requestAnimationFrame based loop (so the loop isn't render blocking)

  1. When the iframe loads, I loop for up to 1 second and monitor the iframe content looking for document.querySelectorAll('template[data-astro-template]').length
  2. If there are any astro templates found (which means Astro hasn’t hydrated a component because once hydration is complete the template is removed) I continue monitoring on a loop
  3. Once there are no templates found, I know all the astro components are hydrated and THEN I swap the iframes

So now, when the iframe swaps the new iframe should have finished loading all the astro islands which means that the swap happens totally seamlessly with no layout shift after the swap.

The second part of the solution was to improve the way that the "offsetLeft" and "offsetTop" calculations are made for components in slots and slots in components. To achieve this I created a new hook (hooks/useSyncPreviewElementOffset.ts) that very closely follows the pattern of hooks/useSyncPreviewElementSize.ts (mutation observers, etc) but instead of taking an array of elements and returning the bounding rectangle it takes TWO arrays of elements and returns the top and left offsets of their bounding rectangles. This means that the calculation is a) centralised rather than being duplicated in both the SlotOverlay and ComponentOverlay components and b) is more robust because it takes into account any resize/mutation that might make the calculation out of sync.

The third part of the solution is that I updated the API of hooks/useSyncPreviewElementSize.ts to also return a 'force recalculate' function. This is then used to ensure that if a parent component or slot re-calculates its position/size/offset, it also instructs all of it's children to recalculate their position/size/offset. This should catch cases where a parent component changes size/position but a resize event isn't fired on a descendant of it because the descendent's dom structure wasn't mutated and it didn't change size (just position).

Edited by Jesse Baker

Merge request reports

Loading