From 5b4303451816c7b39c711cf93654ce207a786fe5 Mon Sep 17 00:00:00 2001 From: Damian Tarnawski Date: Mon, 30 Dec 2024 17:08:55 +0100 Subject: [PATCH] Update scroll data in timeout (fixes #307) --- .changeset/healthy-doors-beam.md | 9 ++++++ packages/frontend/src/structure.tsx | 45 +++++++++++++++++++---------- 2 files changed, 38 insertions(+), 16 deletions(-) create mode 100644 .changeset/healthy-doors-beam.md diff --git a/.changeset/healthy-doors-beam.md b/.changeset/healthy-doors-beam.md new file mode 100644 index 00000000..c607a58a --- /dev/null +++ b/.changeset/healthy-doors-beam.md @@ -0,0 +1,9 @@ +--- +"@solid-devtools/frontend": patch +--- + +Update scroll data in timeout, after the ResizeObserver callback +To prevent this error: + > ResizeObserver loop completed with undelivered notifications +As changing scroll data can then change el.scrollTop +Fixes #307 \ No newline at end of file diff --git a/packages/frontend/src/structure.tsx b/packages/frontend/src/structure.tsx index e7918167..5749cd47 100644 --- a/packages/frontend/src/structure.tsx +++ b/packages/frontend/src/structure.tsx @@ -495,15 +495,21 @@ const getFocusedNodeData = ( } const DisplayStructureTree: s.Component = () => { - const [containerScroll, setContainerScroll] = s.createSignal({top: 0, height: 0}) + + const [containerScroll, setContainerScroll] = s.createSignal({ + top: 0, + height: 0, + }, { + equals: (a, b) => a.top === b.top && a.height === b.height + }) const remSize = useRemSize() - const getContainerTopMargin = (): number => remSize() * v_margin_in_rem - const getRowHeight = (): number => remSize() * row_height_in_rem + const getContainerTopMargin = () => remSize() * v_margin_in_rem + const getRowHeight = () => remSize() * row_height_in_rem const updateScrollData = (el: HTMLElement): void => { setContainerScroll({ - top: Math.max(el.scrollTop - getContainerTopMargin(), 0), + top: Math.max(el.scrollTop - getContainerTopMargin(), 0), height: el.clientHeight, }) } @@ -621,16 +627,14 @@ const DisplayStructureTree: s.Component = () => { }) // Seep the inspected or central node in view when the list is changing - s.createEffect( - defer(collapsedList, () => { - if (!lastFocusedNodeData) return - const [nodeId, lastPosition] = lastFocusedNodeData - const index = getNodeIndexById(nodeId) - if (index === -1) return - const move = index - virtual().start - lastPosition - if (move !== 0) container.scrollTop += move * getRowHeight() - }), - ) + s.createEffect(defer(collapsedList, () => { + if (!lastFocusedNodeData) return + const [nodeId, lastPosition] = lastFocusedNodeData + const index = getNodeIndexById(nodeId) + if (index === -1) return + const move = index - virtual().start - lastPosition + if (move !== 0) container.scrollTop += move * getRowHeight() + })) // Scroll to selected node when it changes // listen to inspected ID, instead of node, because node reference can change @@ -752,8 +756,17 @@ const DisplayStructureTree: s.Component = () => { { container = el - setTimeout(() => updateScrollData(el)) - createResizeObserver(el, () => updateScrollData(el)) + createResizeObserver(el, () => { + /* + Update data in timeout, after the ResizeObserver callback + To prevent this error: + > ResizeObserver loop completed with undelivered notifications + As changing scroll data can then change el.scrollTop + */ + setTimeout(() => { + updateScrollData(el) + }) + }) }} onScroll={e => updateScrollData(e.currentTarget)} >