@@ -23,6 +23,8 @@ import { store as blockEditorStore } from '../../store';
2323import { __unstableUseBlockElement as useBlockElement } from '../block-list/use-block-props/use-block-refs' ;
2424import usePopoverScroll from './use-popover-scroll' ;
2525
26+ const MAX_POPOVER_RECOMPUTE_COUNTER = Number . MAX_SAFE_INTEGER ;
27+
2628export const InsertionPointOpenRef = createContext ( ) ;
2729
2830function BlockPopoverInbetween ( {
@@ -34,8 +36,9 @@ function BlockPopoverInbetween( {
3436 ...props
3537} ) {
3638 // This is a temporary hack to get the inbetween inserter to recompute properly.
37- const [ positionRecompute , forceRecompute ] = useReducer (
38- ( s ) => s + 1 ,
39+ const [ popoverRecomputeCounter , forcePopoverRecompute ] = useReducer (
40+ // Module is there to make sure that the counter doesn't overflow.
41+ ( s ) => ( s + 1 ) % MAX_POPOVER_RECOMPUTE_COUNTER ,
3942 0
4043 ) ;
4144
@@ -66,7 +69,14 @@ function BlockPopoverInbetween( {
6669 const nextElement = useBlockElement ( nextClientId ) ;
6770 const isVertical = orientation === 'vertical' ;
6871 const style = useMemo ( ( ) => {
69- if ( ( ! previousElement && ! nextElement ) || ! isVisible ) {
72+ if (
73+ // popoverRecomputeCounter is by definition always equal or greater than 0.
74+ // This check is only there to satisfy the correctness of the
75+ // exhaustive-deps rule for the `useMemo` hook.
76+ popoverRecomputeCounter < 0 ||
77+ ( ! previousElement && ! nextElement ) ||
78+ ! isVisible
79+ ) {
7080 return { } ;
7181 }
7282
@@ -102,12 +112,19 @@ function BlockPopoverInbetween( {
102112 previousElement ,
103113 nextElement ,
104114 isVertical ,
105- positionRecompute ,
115+ popoverRecomputeCounter ,
106116 isVisible ,
107117 ] ) ;
108118
109119 const popoverAnchor = useMemo ( ( ) => {
110- if ( ( ! previousElement && ! nextElement ) || ! isVisible ) {
120+ if (
121+ // popoverRecomputeCounter is by definition always equal or greater than 0.
122+ // This check is only there to satisfy the correctness of the
123+ // exhaustive-deps rule for the `useMemo` hook.
124+ popoverRecomputeCounter < 0 ||
125+ ( ! previousElement && ! nextElement ) ||
126+ ! isVisible
127+ ) {
111128 return undefined ;
112129 }
113130
@@ -161,19 +178,26 @@ function BlockPopoverInbetween( {
161178 } , [
162179 previousElement ,
163180 nextElement ,
164- positionRecompute ,
181+ popoverRecomputeCounter ,
165182 isVertical ,
166183 isVisible ,
167184 ] ) ;
168185
169186 const popoverScrollRef = usePopoverScroll ( __unstableContentRef ) ;
170187
171188 // This is only needed for a smooth transition when moving blocks.
189+ // When blocks are moved up/down, their position can be set by
190+ // updating the `transform` property manually (i.e. without using CSS
191+ // transitions or animations). The animation, which can also scroll the block
192+ // editor, can sometimes cause the position of the Popover to get out of sync.
193+ // A MutationObserver is therefore used to make sure that changes to the
194+ // selectedElement's attribute (i.e. `transform`) can be tracked and used to
195+ // trigger the Popover to rerender.
172196 useLayoutEffect ( ( ) => {
173197 if ( ! previousElement ) {
174198 return ;
175199 }
176- const observer = new window . MutationObserver ( forceRecompute ) ;
200+ const observer = new window . MutationObserver ( forcePopoverRecompute ) ;
177201 observer . observe ( previousElement , { attributes : true } ) ;
178202
179203 return ( ) => {
@@ -185,7 +209,7 @@ function BlockPopoverInbetween( {
185209 if ( ! nextElement ) {
186210 return ;
187211 }
188- const observer = new window . MutationObserver ( forceRecompute ) ;
212+ const observer = new window . MutationObserver ( forcePopoverRecompute ) ;
189213 observer . observe ( nextElement , { attributes : true } ) ;
190214
191215 return ( ) => {
@@ -199,12 +223,12 @@ function BlockPopoverInbetween( {
199223 }
200224 previousElement . ownerDocument . defaultView . addEventListener (
201225 'resize' ,
202- forceRecompute
226+ forcePopoverRecompute
203227 ) ;
204228 return ( ) => {
205229 previousElement . ownerDocument . defaultView . removeEventListener (
206230 'resize' ,
207- forceRecompute
231+ forcePopoverRecompute
208232 ) ;
209233 } ;
210234 } , [ previousElement ] ) ;
0 commit comments