Rewrite settings bar updates to improve performance

This commit is contained in:
Andrew Kingston 2024-08-12 14:45:17 +01:00
parent 1f99ecc529
commit d423d530e4
No known key found for this signature in database
2 changed files with 110 additions and 96 deletions

View File

@ -198,7 +198,7 @@
overflow: hidden; overflow: hidden;
height: 410px; height: 410px;
} }
div.in-builder { div.in-builder :global(> *) {
pointer-events: none !important; pointer-events: none !important;
} }
</style> </style>

View File

@ -11,25 +11,24 @@
const context = getContext("context") const context = getContext("context")
const verticalOffset = 36 const verticalOffset = 36
const horizontalOffset = 2 const horizontalOffset = 2
const observer = new MutationObserver(() => debouncedUpdate())
let top = 0 let top = 0
let left = 0 let left = 0
let interval let interval
let self let self
let measured = false let measured = false
let observer let observing = false
let insideGrid = false let insideGrid = false
let gridHAlign let gridHAlign
let gridVAlign let gridVAlign
let deviceEl
// TODO: respect dependsOn keys $: id = $builderStore.selectedComponentId
$: id, reset()
$: componentId = $builderStore.selectedComponentId
$: measured, observeComputedStyles(componentId)
$: component = $componentStore.selectedComponent $: component = $componentStore.selectedComponent
$: definition = $componentStore.selectedComponentDefinition $: definition = $componentStore.selectedComponentDefinition
$: instance = componentStore.actions.getComponentInstance(componentId) $: instance = componentStore.actions.getComponentInstance(id)
$: state = $instance?.state $: state = $instance?.state
$: showBar = $: showBar =
definition?.showSettingsBar !== false && definition?.showSettingsBar !== false &&
@ -37,7 +36,7 @@
definition && definition &&
!$state?.errorState !$state?.errorState
$: settings = getBarSettings(component, definition) $: settings = getBarSettings(component, definition)
$: isRoot = componentId === $builderStore.screen?.props?._id $: isRoot = id === $builderStore.screen?.props?._id
$: showGridStyles = $: showGridStyles =
insideGrid && insideGrid &&
(definition?.grid?.hAlign !== "stretch" || (definition?.grid?.hAlign !== "stretch" ||
@ -47,6 +46,21 @@
$: gridHAlignVar = getGridVar(device, GridParams.HAlign) $: gridHAlignVar = getGridVar(device, GridParams.HAlign)
$: gridVAlignVar = getGridVar(device, GridParams.VAlign) $: gridVAlignVar = getGridVar(device, GridParams.VAlign)
const reset = () => {
observer.disconnect()
measured = false
observing = false
insideGrid = false
}
const startObserving = domBoundary => {
observer.observe(domBoundary, {
attributes: true,
attributeFilter: ["style"],
})
observing = true
}
const getBarSettings = (component, definition) => { const getBarSettings = (component, definition) => {
let allSettings = [] let allSettings = []
definition?.settings?.forEach(setting => { definition?.settings?.forEach(setting => {
@ -68,25 +82,40 @@
if (!showBar) { if (!showBar) {
return return
} }
const id = $builderStore.selectedComponentId
let element = document.getElementsByClassName(id)?.[0]
// Check if we're inside a grid // Find DOM boundary and ensure it is valid
insideGrid = element?.parentNode.classList.contains("grid") let domBoundary = document.getElementsByClassName(id)[0]
if (!insideGrid) { if (!domBoundary) {
element = element?.children?.[0] return reset()
}
// If we're inside a grid, allow time for buttons to render
const nextInsideGrid = domBoundary.dataset.insideGrid === "true"
if (nextInsideGrid && !insideGrid) {
insideGrid = true
return
} else {
insideGrid = nextInsideGrid
}
// Get the correct DOM boundary depending if we're inside a grid or not
if (!insideGrid) {
domBoundary =
domBoundary.getElementsByClassName(`${id}-dom`)[0] ||
domBoundary.children?.[0]
}
if (!domBoundary || !self) {
return reset()
}
// Start observing if required
if (!observing) {
startObserving(domBoundary)
} }
// The settings bar is higher in the dom tree than the selection indicators
// as we want to be able to render the settings bar wider than the screen,
// or outside the screen.
// Therefore we use the clip root rather than the app root to determine
// its position.
const device = document.getElementById("clip-root")
if (element && self) {
// Batch reads to minimize reflow // Batch reads to minimize reflow
const deviceBounds = device.getBoundingClientRect() const deviceBounds = deviceEl.getBoundingClientRect()
const elBounds = element.getBoundingClientRect() const elBounds = domBoundary.getBoundingClientRect()
const width = self.offsetWidth const width = self.offsetWidth
const height = self.offsetHeight const height = self.offsetHeight
const { scrollX, scrollY, innerWidth } = window const { scrollX, scrollY, innerWidth } = window
@ -94,11 +123,11 @@
// Read grid metadata from data attributes // Read grid metadata from data attributes
if (insideGrid) { if (insideGrid) {
if (mobile) { if (mobile) {
gridHAlign = element.dataset.gridMobileHAlign gridHAlign = domBoundary.dataset.gridMobileHAlign
gridVAlign = element.dataset.gridMobileVAlign gridVAlign = domBoundary.dataset.gridMobileVAlign
} else { } else {
gridHAlign = element.dataset.gridDesktopHAlign gridHAlign = domBoundary.dataset.gridDesktopHAlign
gridVAlign = element.dataset.gridDesktopVAlign gridVAlign = domBoundary.dataset.gridDesktopVAlign
} }
} }
@ -143,27 +172,12 @@
if (Math.round(newLeft) !== Math.round(left)) { if (Math.round(newLeft) !== Math.round(left)) {
left = newLeft left = newLeft
} }
measured = true measured = true
} }
}
const debouncedUpdate = Utils.domDebounce(updatePosition) const debouncedUpdate = Utils.domDebounce(updatePosition)
const observeComputedStyles = id => {
observer?.disconnect()
const node = document.getElementsByClassName(`${id}-dom`)[0]?.parentNode
if (node) {
observer = new MutationObserver(updatePosition)
observer.observe(node, {
attributes: true,
attributeFilter: ["style"],
childList: false,
subtree: false,
})
}
}
onMount(() => { onMount(() => {
deviceEl = document.getElementById("clip-root")
debouncedUpdate() debouncedUpdate()
interval = setInterval(debouncedUpdate, 100) interval = setInterval(debouncedUpdate, 100)
document.addEventListener("scroll", debouncedUpdate, true) document.addEventListener("scroll", debouncedUpdate, true)
@ -172,7 +186,7 @@
onDestroy(() => { onDestroy(() => {
clearInterval(interval) clearInterval(interval)
document.removeEventListener("scroll", debouncedUpdate, true) document.removeEventListener("scroll", debouncedUpdate, true)
observer?.disconnect() reset()
}) })
</script> </script>
@ -190,7 +204,7 @@
icon="AlignLeft" icon="AlignLeft"
title="Align left" title="Align left"
active={gridHAlign === "start"} active={gridHAlign === "start"}
{componentId} componentId={id}
/> />
<GridStylesButton <GridStylesButton
style={gridHAlignVar} style={gridHAlignVar}
@ -198,7 +212,7 @@
icon="AlignCenter" icon="AlignCenter"
title="Align center" title="Align center"
active={gridHAlign === "center"} active={gridHAlign === "center"}
{componentId} componentId={id}
/> />
<GridStylesButton <GridStylesButton
style={gridHAlignVar} style={gridHAlignVar}
@ -206,7 +220,7 @@
icon="AlignRight" icon="AlignRight"
title="Align right" title="Align right"
active={gridHAlign === "end"} active={gridHAlign === "end"}
{componentId} componentId={id}
/> />
<GridStylesButton <GridStylesButton
style={gridHAlignVar} style={gridHAlignVar}
@ -214,7 +228,7 @@
icon="MoveLeftRight" icon="MoveLeftRight"
title="Stretch horizontally" title="Stretch horizontally"
active={gridHAlign === "stretch"} active={gridHAlign === "stretch"}
{componentId} componentId={id}
/> />
<div class="divider" /> <div class="divider" />
<GridStylesButton <GridStylesButton
@ -223,7 +237,7 @@
icon="AlignTop" icon="AlignTop"
title="Align top" title="Align top"
active={gridVAlign === "start"} active={gridVAlign === "start"}
{componentId} componentId={id}
/> />
<GridStylesButton <GridStylesButton
style={gridVAlignVar} style={gridVAlignVar}
@ -231,7 +245,7 @@
icon="AlignMiddle" icon="AlignMiddle"
title="Align middle" title="Align middle"
active={gridVAlign === "center"} active={gridVAlign === "center"}
{componentId} componentId={id}
/> />
<GridStylesButton <GridStylesButton
style={gridVAlignVar} style={gridVAlignVar}
@ -239,7 +253,7 @@
icon="AlignBottom" icon="AlignBottom"
title="Align bottom" title="Align bottom"
active={gridVAlign === "end"} active={gridVAlign === "end"}
{componentId} componentId={id}
/> />
<GridStylesButton <GridStylesButton
style={gridVAlignVar} style={gridVAlignVar}
@ -247,7 +261,7 @@
icon="MoveUpDown" icon="MoveUpDown"
title="Stretch vertically" title="Stretch vertically"
active={gridVAlign === "stretch"} active={gridVAlign === "stretch"}
{componentId} componentId={id}
/> />
<div class="divider" /> <div class="divider" />
{/if} {/if}