@@ -345,4 +345,117 @@ describe('applyTargetedLayout', () => {
345345 result . existing . position . y + existingMetrics . height
346346 )
347347 } )
348+
349+ it ( 'places a new sibling container below a frozen container at its rendered height' , ( ) => {
350+ // The frozen container's children sit further apart than a fresh layout would
351+ // place them (a stale layout from when those blocks measured taller). Its
352+ // rendered height therefore exceeds the height a hypothetical re-layout
353+ // predicts, and the new sibling must clear the rendered one.
354+ const spacedChild = ( id : string , y : number , parentId : string ) =>
355+ createBlock ( id , {
356+ position : { x : 150 , y } ,
357+ data : { parentId, extent : 'parent' } ,
358+ layout : { measuredWidth : 250 , measuredHeight : 300 } ,
359+ height : 300 ,
360+ } )
361+
362+ const blocks = {
363+ start : createBlock ( 'start' , {
364+ type : 'start_trigger' ,
365+ position : { x : 0 , y : 0 } ,
366+ layout : { measuredWidth : 250 , measuredHeight : 100 } ,
367+ height : 100 ,
368+ } ) ,
369+ frozenLoop : createBlock ( 'frozenLoop' , {
370+ type : 'loop' ,
371+ position : { x : 400 , y : 0 } ,
372+ data : { width : 900 , height : 1200 } ,
373+ layout : { measuredWidth : 900 , measuredHeight : 1200 } ,
374+ } ) ,
375+ frozenTop : spacedChild ( 'frozenTop' , 100 , 'frozenLoop' ) ,
376+ frozenBottom : spacedChild ( 'frozenBottom' , 750 , 'frozenLoop' ) ,
377+ newLoop : createBlock ( 'newLoop' , {
378+ type : 'loop' ,
379+ position : { x : 0 , y : 0 } ,
380+ data : { width : 500 , height : 300 } ,
381+ } ) ,
382+ newChild : createBlock ( 'newChild' , {
383+ position : { x : 0 , y : 0 } ,
384+ data : { parentId : 'newLoop' , extent : 'parent' } ,
385+ } ) ,
386+ }
387+
388+ const edges : Edge [ ] = [
389+ { id : 'e1' , source : 'start' , target : 'frozenLoop' } ,
390+ { id : 'e2' , source : 'start' , target : 'newLoop' } ,
391+ { id : 'e3' , source : 'frozenTop' , target : 'frozenBottom' } ,
392+ ]
393+
394+ const result = applyTargetedLayout ( blocks , edges , {
395+ changedBlockIds : [ 'newLoop' , 'newChild' ] ,
396+ } )
397+
398+ // Frozen children must not move, so the frozen container keeps its tall size.
399+ expect ( result . frozenTop . position ) . toEqual ( { x : 150 , y : 100 } )
400+ expect ( result . frozenBottom . position ) . toEqual ( { x : 150 , y : 750 } )
401+
402+ const containers = [ result . frozenLoop , result . newLoop ] . sort (
403+ ( a , b ) => a . position . y - b . position . y
404+ )
405+ const upperBottom = containers [ 0 ] . position . y + getBlockMetrics ( containers [ 0 ] ) . height
406+ expect ( containers [ 1 ] . position . y ) . toBeGreaterThanOrEqual ( upperBottom )
407+ } )
408+
409+ it ( 'shifts downstream blocks right when a container grows from an inserted child' , ( ) => {
410+ // Inserting inside a container widens it, but that resize happens during
411+ // layout and so is absent from the caller's change set. Blocks after the
412+ // container must still move clear of its new right edge.
413+ const blocks = {
414+ loop : createBlock ( 'loop' , {
415+ type : 'loop' ,
416+ position : { x : 100 , y : 100 } ,
417+ data : { width : 900 , height : 400 } ,
418+ layout : { measuredWidth : 900 , measuredHeight : 400 } ,
419+ } ) ,
420+ first : createBlock ( 'first' , {
421+ position : { x : 150 , y : 150 } ,
422+ data : { parentId : 'loop' , extent : 'parent' } ,
423+ layout : { measuredWidth : 250 , measuredHeight : 120 } ,
424+ height : 120 ,
425+ } ) ,
426+ last : createBlock ( 'last' , {
427+ position : { x : 600 , y : 150 } ,
428+ data : { parentId : 'loop' , extent : 'parent' } ,
429+ layout : { measuredWidth : 250 , measuredHeight : 120 } ,
430+ height : 120 ,
431+ } ) ,
432+ inserted : createBlock ( 'inserted' , {
433+ position : { x : 0 , y : 0 } ,
434+ data : { parentId : 'loop' , extent : 'parent' } ,
435+ } ) ,
436+ after : createBlock ( 'after' , {
437+ position : { x : 1100 , y : 150 } ,
438+ layout : { measuredWidth : 250 , measuredHeight : 120 } ,
439+ height : 120 ,
440+ } ) ,
441+ }
442+
443+ const edges : Edge [ ] = [
444+ { id : 'e1' , source : 'first' , target : 'inserted' } ,
445+ { id : 'e2' , source : 'inserted' , target : 'last' } ,
446+ { id : 'e3' , source : 'loop' , target : 'after' , sourceHandle : 'loop-end-source' } ,
447+ ]
448+
449+ const result = applyTargetedLayout ( blocks , edges , {
450+ changedBlockIds : [ 'inserted' ] ,
451+ shiftSourceBlockIds : [ 'inserted' ] ,
452+ } )
453+
454+ const loopMetrics = getBlockMetrics ( result . loop )
455+ expect ( loopMetrics . width ) . toBeGreaterThan ( 900 )
456+ expect ( result . loop . position ) . toEqual ( { x : 100 , y : 100 } )
457+ expect ( result . after . position . x ) . toBeGreaterThanOrEqual (
458+ result . loop . position . x + loopMetrics . width
459+ )
460+ } )
348461} )
0 commit comments