@ -23,12 +23,15 @@ import {
arrow as fuiArrow ,
computePosition as fuiComputePosition ,
flip as fuiFlip ,
hide as fuiHide ,
offset as fuiOffset ,
shift as fuiShift ,
size as fuiSize ,
type Middleware as FuiMiddleware
} from '@floating-ui/dom'
import { hide as ownHide } from './middleware'
import type { Middleware } from './types'
import type { Measurable } from '../types'
import type { Placement , Strategy } from '../placement'
const dom = createActiveDom ( )
@ -50,13 +53,17 @@ afterEach(() => {
for ( const el of trash ) el . remove ( )
trash . length = 0
window . scrollTo ( 0 , 0 )
document . documentElement . removeAttribute ( 'dir' )
document . body . removeAttribute ( 'dir' )
document . body . style . cssText = ''
document . documentElement . style . cssText = ''
} )
// Run both engines on the same elements + equivalent middleware specs.
type Built = { own : Middleware [ ] ; fui : FuiMiddleware [ ] }
async function bothPositions (
anchor : HTMLElement,
anchor : Measurable | HTMLElement,
floating : HTMLElement ,
mw : Built ,
placement : Placement ,
@ -386,6 +393,870 @@ describe('real-DOM parity — fixed floating escaping a scroll container (clip d
}
} )
describe ( 'real-DOM parity — virtual anchor (Measurable)' , ( ) = > {
for ( const placement of [ 'bottom' , 'top-start' , 'right' , 'left-end' ] as Placement [ ] ) {
it ( placement , async ( ) = > {
// A virtual reference (context-menu pattern): only getBoundingClientRect.
const rect = { x : 380 , y : 280 , width : 4 , height : 4 , top : 280 , left : 380 , right : 384 , bottom : 284 }
const virtual : Measurable = { getBoundingClientRect : ( ) = > rect as DOMRect }
const floating = box ( { position : 'absolute' , width : '200px' , height : '120px' } )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( virtual , floating , mw , placement )
assertSame ( ` virtual ${ placement } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — RTL document' , ( ) = > {
for ( const placement of [ 'bottom-start' , 'bottom-end' , 'top-start' , 'right-start' ] as Placement [ ] ) {
it ( placement , async ( ) = > {
document . documentElement . setAttribute ( 'dir' , 'rtl' )
const anchor = box ( {
position : 'absolute' ,
left : '420px' ,
top : '300px' ,
width : '90px' ,
height : '34px'
} )
const floating = box ( { position : 'absolute' , width : '200px' , height : '120px' } )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 , alignmentAxis : 10 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 , alignmentAxis : 10 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , placement )
assertSame ( ` rtl ${ placement } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — shadow DOM' , ( ) = > {
for ( const placement of [ 'bottom' , 'top-start' , 'right' ] as Placement [ ] ) {
it ( placement , async ( ) = > {
const host = box ( { position : 'relative' } )
const root = host . attachShadow ( { mode : 'open' } )
const anchor = document . createElement ( 'div' )
Object . assign ( anchor . style , {
position : 'absolute' ,
left : '300px' ,
top : '260px' ,
width : '90px' ,
height : '34px'
} )
const floating = document . createElement ( 'div' )
Object . assign ( floating . style , { position : 'absolute' , width : '200px' , height : '120px' } )
root . appendChild ( anchor )
root . appendChild ( floating )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , placement )
assertSame ( ` shadow ${ placement } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — deeply nested scroll containers' , ( ) = > {
for ( const [ s1 , s2 ] of [
[ 0 , 0 ] ,
[ 80 , 40 ] ,
[ 160 , 120 ]
] ) {
it ( ` outerScroll= ${ s1 } innerScroll= ${ s2 } ` , async ( ) = > {
const outer = box ( {
position : 'absolute' ,
left : '80px' ,
top : '80px' ,
width : '420px' ,
height : '300px' ,
overflow : 'auto' ,
border : '1px solid'
} )
const outerTall = box ( { height : '900px' , width : '700px' , position : 'relative' } , outer )
const inner = box (
{
position : 'absolute' ,
left : '60px' ,
top : '120px' ,
width : '260px' ,
height : '180px' ,
overflow : 'auto' ,
border : '1px solid'
} ,
outerTall
)
const innerTall = box ( { height : '600px' , width : '500px' , position : 'relative' } , inner )
const anchor = box (
{ position : 'absolute' , left : '40px' , top : '220px' , width : '90px' , height : '34px' } ,
innerTall
)
const floating = box ( { position : 'absolute' , width : '200px' , height : '120px' } )
outer . scrollTop = s1
inner . scrollTop = s2
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 4 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 4 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , 'bottom' )
assertSame ( ` nested2 ${ s1 } / ${ s2 } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — hide (referenceHidden) in a scroll container' , ( ) = > {
for ( const scroll of [ 0 , 260 , 520 ] ) {
it ( ` scrollTop= ${ scroll } ` , async ( ) = > {
const scroller = box ( {
position : 'absolute' ,
left : '120px' ,
top : '120px' ,
width : '300px' ,
height : '200px' ,
overflow : 'auto' ,
border : '1px solid'
} )
const tall = box ( { height : '900px' , width : '500px' , position : 'relative' } , scroller )
const anchor = box (
{ position : 'absolute' , left : '40px' , top : '120px' , width : '90px' , height : '34px' } ,
tall
)
const floating = box ( { position : 'absolute' , width : '200px' , height : '120px' } )
scroller . scrollTop = scroll
const own = await ownComputePosition ( anchor , floating , {
placement : 'bottom' ,
strategy : 'absolute' ,
middleware : [ ownOffset ( { mainAxis : 8 } ) , ownHide ( { strategy : 'referenceHidden' } ) ] ,
dom
} )
const fui = await fuiComputePosition ( anchor , floating , {
placement : 'bottom' ,
strategy : 'absolute' ,
middleware : [ fuiOffset ( { mainAxis : 8 } ) , fuiHide ( { strategy : 'referenceHidden' } ) ]
} )
const oh = ( own . middlewareData . hide ? ? { } ) as { referenceHidden? : boolean }
const fh = ( fui . middlewareData . hide ? ? { } ) as { referenceHidden? : boolean }
expect ( ! ! oh . referenceHidden , ` hide@ ${ scroll } ` ) . toBe ( ! ! fh . referenceHidden )
} )
}
} )
describe ( 'real-DOM parity — arrow across all placements (real layout)' , ( ) = > {
for ( const placement of PLACEMENTS ) {
it ( placement , async ( ) = > {
const anchor = box ( {
position : 'absolute' ,
left : '420px' ,
top : '320px' ,
width : '110px' ,
height : '38px'
} )
const floating = box ( { position : 'absolute' , width : '220px' , height : '150px' } )
const arrowEl = box ( { position : 'absolute' , width : '14px' , height : '14px' } , floating )
const { own , fui } = await bothPositions (
anchor ,
floating ,
{
own : [ ownOffset ( { mainAxis : 10 } ) , ownArrow ( { element : arrowEl , padding : 8 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 10 } ) , fuiArrow ( { element : arrowEl , padding : 8 } ) ]
} ,
placement
)
assertSame ( ` arrow ${ placement } ` , own , fui )
const oa = own . middlewareData . arrow as { x? : number ; y? : number }
const fa = fui . middlewareData . arrow as { x? : number ; y? : number }
expect ( Math . abs ( ( oa . x ? ? oa . y ? ? 0 ) - ( fa . x ? ? fa . y ? ? 0 ) ) , ` arrow center ${ placement } ` ) . toBeLessThanOrEqual ( TOL )
} )
}
} )
describe ( 'real-DOM parity — transform on body/html ancestor' , ( ) = > {
for ( const target of [ 'body' , 'html' ] as const ) {
it ( ` transform on < ${ target } > ` , async ( ) = > {
const el = target === 'body' ? document . body : document.documentElement
el . style . transform = 'translateZ(0)'
const anchor = box ( {
position : 'absolute' ,
left : '380px' ,
top : '300px' ,
width : '90px' ,
height : '34px'
} )
const floating = box ( { position : 'absolute' , width : '200px' , height : '120px' } )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , 'bottom' )
assertSame ( ` transform- ${ target } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — body margin (non-zero document origin)' , ( ) = > {
it ( 'body margin 24px' , async ( ) = > {
document . body . style . margin = '24px'
const anchor = box ( {
position : 'absolute' ,
left : '380px' ,
top : '300px' ,
width : '90px' ,
height : '34px'
} )
const floating = box ( { position : 'absolute' , width : '200px' , height : '120px' } )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , 'bottom' )
assertSame ( 'body-margin' , own , fui )
} )
} )
describe ( 'real-DOM parity — sticky ancestor' , ( ) = > {
for ( const scroll of [ 0 , 100 ] ) {
it ( ` sticky scrollTop= ${ scroll } ` , async ( ) = > {
const scroller = box ( {
position : 'absolute' ,
left : '100px' ,
top : '100px' ,
width : '320px' ,
height : '240px' ,
overflow : 'auto' ,
border : '1px solid'
} )
const sticky = box ( { position : 'sticky' , top : '0px' , width : '300px' , height : '60px' } , scroller )
const tall = box ( { height : '700px' , width : '300px' } , scroller )
void tall
const anchor = box (
{ position : 'absolute' , left : '40px' , top : '10px' , width : '90px' , height : '34px' } ,
sticky
)
const floating = box ( { position : 'absolute' , width : '180px' , height : '110px' } )
scroller . scrollTop = scroll
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , 'bottom' )
assertSame ( ` sticky ${ scroll } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — visible scrollbar (clientWidth < offsetWidth)' , ( ) = > {
it ( 'scroll container with a forced scrollbar' , async ( ) = > {
const scroller = box ( {
position : 'absolute' ,
left : '120px' ,
top : '120px' ,
width : '320px' ,
height : '240px' ,
overflow : 'scroll' ,
border : '2px solid'
} )
const tall = box ( { height : '900px' , width : '900px' , position : 'relative' } , scroller )
const anchor = box (
{ position : 'absolute' , left : '40px' , top : '60px' , width : '90px' , height : '34px' } ,
tall
)
const floating = box ( { position : 'absolute' , width : '200px' , height : '120px' } )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 4 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 4 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , 'bottom' )
assertSame ( 'scrollbar' , own , fui )
} )
} )
describe ( 'real-DOM parity — explicit collisionBoundary element' , ( ) = > {
for ( const placement of [ 'bottom' , 'right' ] as Placement [ ] ) {
it ( placement , async ( ) = > {
const boundary = box ( {
position : 'absolute' ,
left : '150px' ,
top : '150px' ,
width : '380px' ,
height : '260px' ,
border : '1px solid'
} )
const anchor = box (
{ position : 'absolute' , left : '260px' , top : '200px' , width : '90px' , height : '34px' } ,
boundary
)
const floating = box ( { position : 'absolute' , width : '200px' , height : '130px' } )
const mw : Built = {
own : [
ownOffset ( { mainAxis : 8 } ) ,
ownFlip ( { boundary : [ boundary ] , altBoundary : true } ) ,
ownShift ( { boundary : [ boundary ] , altBoundary : true , padding : 4 } )
] ,
fui : [
fuiOffset ( { mainAxis : 8 } ) ,
fuiFlip ( { boundary : [ boundary ] , altBoundary : true } ) ,
fuiShift ( { boundary : [ boundary ] , altBoundary : true , padding : 4 } )
]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , placement )
assertSame ( ` boundary ${ placement } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — top-layer floating (native popover) escapes clipping' , ( ) = > {
for ( const placement of [ 'bottom' , 'top' ] as Placement [ ] ) {
it ( placement , async ( ) = > {
const scroller = box ( {
position : 'absolute' ,
left : '120px' ,
top : '120px' ,
width : '300px' ,
height : '200px' ,
overflow : 'auto' ,
border : '1px solid'
} )
const tall = box ( { height : '700px' , width : '500px' , position : 'relative' } , scroller )
const anchor = box (
{ position : 'absolute' , left : '40px' , top : '90px' , width : '90px' , height : '34px' } ,
tall
)
// Native popover floating element — top layer, so the clipping walk must
// short-circuit (isTopLayer) and bound it to the viewport, not the scroller.
const floating = box ( { position : 'fixed' , width : '200px' , height : '140px' } , scroller )
floating . setAttribute ( 'popover' , 'manual' )
if ( typeof floating . showPopover !== 'function' ) return // unsupported → skip body
floating . showPopover ( )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , placement , 'fixed' )
assertSame ( ` top-layer ${ placement } ` , own , fui )
floating . hidePopover ( )
} )
}
} )
// ════════ Coverage-gap sweep (real-DOM) ══════════════════════════════════════
describe ( 'real-DOM parity — document scrollbar present (viewport width)' , ( ) = > {
for ( const placement of [ 'right' , 'bottom-end' , 'top-end' ] as Placement [ ] ) {
it ( placement , async ( ) = > {
const spacer = box ( { position : 'absolute' , top : '0' , left : '0' , width : '1px' , height : '3000px' } )
void spacer
const anchor = box ( {
position : 'absolute' ,
left : ` ${ document . documentElement . clientWidth - 120 } px ` ,
top : '300px' ,
width : '90px' ,
height : '34px'
} )
const floating = box ( { position : 'absolute' , width : '200px' , height : '120px' } )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 0 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 0 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , placement )
assertSame ( ` scrollbar-vp ${ placement } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — reference clip ≠ floating clip (altBoundary)' , ( ) = > {
for ( const scroll of [ 0 , 240 ] ) {
it ( ` altBoundary flip scrollTop= ${ scroll } ` , async ( ) = > {
const scroller = box ( {
position : 'absolute' ,
left : '120px' ,
top : '120px' ,
width : '300px' ,
height : '200px' ,
overflow : 'auto' ,
border : '1px solid'
} )
const tall = box ( { height : '900px' , width : '500px' , position : 'relative' } , scroller )
const anchor = box (
{ position : 'absolute' , left : '40px' , top : '120px' , width : '90px' , height : '34px' } ,
tall
)
// floating lives in body (its own clip = viewport); altBoundary makes
// flip/shift read the REFERENCE's clip (the scroller).
const floating = box ( { position : 'absolute' , width : '200px' , height : '160px' } )
scroller . scrollTop = scroll
const mw : Built = {
own : [
ownOffset ( { mainAxis : 8 } ) ,
ownFlip ( { altBoundary : true } ) ,
ownShift ( { altBoundary : true , padding : 4 } )
] ,
fui : [
fuiOffset ( { mainAxis : 8 } ) ,
fuiFlip ( { altBoundary : true } ) ,
fuiShift ( { altBoundary : true , padding : 4 } )
]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , 'bottom' )
assertSame ( ` altBoundary ${ scroll } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — anisotropic scale offsetParent' , ( ) = > {
for ( const placement of [ 'bottom' , 'right' , 'top-start' , 'bottom-end' ] as Placement [ ] ) {
it ( placement , async ( ) = > {
const wrapper = box ( {
position : 'relative' ,
transform : 'scale(1.4, 0.7)' ,
transformOrigin : 'top left' ,
left : '180px' ,
top : '160px' ,
width : '420px' ,
height : '340px' ,
border : '1px solid'
} )
const anchor = box (
{ position : 'absolute' , left : '120px' , top : '130px' , width : '90px' , height : '34px' } ,
wrapper
)
const floating = box ( { position : 'absolute' , width : '200px' , height : '120px' } , wrapper )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , placement )
assertSame ( ` aniso ${ placement } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — scaled AND scrolled offsetParent' , ( ) = > {
for ( const placement of [ 'bottom' , 'right' ] as Placement [ ] ) {
it ( placement , async ( ) = > {
const scroller = box ( {
position : 'relative' ,
transform : 'scale(1.3)' ,
transformOrigin : 'top left' ,
overflow : 'auto' ,
left : '120px' ,
top : '120px' ,
width : '300px' ,
height : '220px' ,
border : '1px solid'
} )
const tall = box ( { height : '700px' , width : '700px' , position : 'relative' } , scroller )
const anchor = box (
{ position : 'absolute' , left : '60px' , top : '180px' , width : '90px' , height : '34px' } ,
tall
)
const floating = box ( { position : 'absolute' , width : '200px' , height : '120px' } , scroller )
scroller . scrollTop = 120
scroller . scrollLeft = 40
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , placement )
assertSame ( ` scaled+scroll ${ placement } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — multi-element collisionBoundary' , ( ) = > {
for ( const placement of [ 'bottom' , 'right' ] as Placement [ ] ) {
it ( placement , async ( ) = > {
const a = box ( { position : 'absolute' , left : '150px' , top : '150px' , width : '400px' , height : '260px' , border : '1px solid' } )
const b = box ( { position : 'absolute' , left : '300px' , top : '120px' , width : '260px' , height : '320px' , border : '1px solid' } )
const anchor = box ( { position : 'absolute' , left : '360px' , top : '230px' , width : '90px' , height : '34px' } )
const floating = box ( { position : 'absolute' , width : '200px' , height : '130px' } )
const mw : Built = {
own : [
ownOffset ( { mainAxis : 8 } ) ,
ownFlip ( { boundary : [ a , b ] , altBoundary : true } ) ,
ownShift ( { boundary : [ a , b ] , altBoundary : true , padding : 4 } )
] ,
fui : [
fuiOffset ( { mainAxis : 8 } ) ,
fuiFlip ( { boundary : [ a , b ] , altBoundary : true } ) ,
fuiShift ( { boundary : [ a , b ] , altBoundary : true , padding : 4 } )
]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , placement )
assertSame ( ` multi-boundary ${ placement } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — reference and floating under DIFFERENT offsetParents' , ( ) = > {
for ( const placement of [ 'bottom' , 'right' , 'top-start' ] as Placement [ ] ) {
it ( placement , async ( ) = > {
const wrapperA = box ( {
position : 'relative' ,
transform : 'translateZ(0)' ,
left : '160px' ,
top : '120px' ,
width : '300px' ,
height : '220px' ,
border : '1px solid'
} )
const anchor = box (
{ position : 'absolute' , left : '120px' , top : '120px' , width : '90px' , height : '34px' } ,
wrapperA
)
const wrapperB = box ( {
position : 'relative' ,
transform : 'translateZ(0)' ,
left : '560px' ,
top : '380px' ,
width : '320px' ,
height : '260px' ,
border : '1px solid'
} )
const floating = box ( { position : 'absolute' , width : '200px' , height : '120px' } , wrapperB )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , placement )
assertSame ( ` cross-op ${ placement } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — non-default flip options (real overflow)' , ( ) = > {
const VARIANTS : { name : string ; own : ( ) = > Middleware ; fui : ( ) = > FuiMiddleware } [ ] = [
{ name : 'crossAxis-alignment' , own : ( ) = > ownFlip ( { crossAxis : 'alignment' } ) , fui : ( ) = > fuiFlip ( { crossAxis : 'alignment' } ) } ,
{ name : 'fallbackAxisSideDirection-start' , own : ( ) = > ownFlip ( { fallbackAxisSideDirection : 'start' } ) , fui : ( ) = > fuiFlip ( { fallbackAxisSideDirection : 'start' } ) } ,
{ name : 'flipAlignment-false' , own : ( ) = > ownFlip ( { flipAlignment : false } ) , fui : ( ) = > fuiFlip ( { flipAlignment : false } ) }
]
for ( const v of VARIANTS ) {
it ( v . name , async ( ) = > {
const scroller = box ( {
position : 'absolute' ,
left : '120px' ,
top : '420px' ,
width : '300px' ,
height : '200px' ,
overflow : 'auto' ,
border : '1px solid'
} )
const tall = box ( { height : '700px' , width : '500px' , position : 'relative' } , scroller )
const anchor = box (
{ position : 'absolute' , left : '40px' , top : '120px' , width : '90px' , height : '34px' } ,
tall
)
const floating = box ( { position : 'absolute' , width : '200px' , height : '260px' } )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , v . own ( ) , ownShift ( { padding : 4 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , v . fui ( ) , fuiShift ( { padding : 4 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , 'bottom-start' )
assertSame ( ` flipopt ${ v . name } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — modal <dialog> top-layer escapes clipping' , ( ) = > {
for ( const placement of [ 'bottom' , 'top' ] as Placement [ ] ) {
it ( placement , async ( ) = > {
const scroller = box ( {
position : 'absolute' ,
left : '120px' ,
top : '120px' ,
width : '300px' ,
height : '200px' ,
overflow : 'auto' ,
border : '1px solid'
} )
const tall = box ( { height : '700px' , width : '500px' , position : 'relative' } , scroller )
const anchor = box (
{ position : 'absolute' , left : '40px' , top : '90px' , width : '90px' , height : '34px' } ,
tall
)
const dialog = document . createElement ( 'dialog' )
Object . assign ( dialog . style , { width : '200px' , height : '140px' , margin : '0' , padding : '0' , border : '0' } )
scroller . appendChild ( dialog )
if ( typeof dialog . showModal !== 'function' ) return
dialog . showModal ( )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , dialog , mw , placement , 'fixed' )
assertSame ( ` modal ${ placement } ` , own , fui )
dialog . close ( )
} )
}
} )
describe ( 'real-DOM parity — body as scroller (filtered from clip walk)' , ( ) = > {
it ( 'body overflow:auto' , async ( ) = > {
document . body . style . cssText = 'overflow:auto;'
const spacer = box ( { position : 'absolute' , top : '0' , left : '0' , width : '2000px' , height : '2000px' } )
void spacer
const anchor = box ( { position : 'absolute' , left : '380px' , top : '300px' , width : '90px' , height : '34px' } )
const floating = box ( { position : 'absolute' , width : '200px' , height : '120px' } )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , 'bottom' )
assertSame ( 'body-scroller' , own , fui )
} )
} )
describe ( 'real-DOM parity — nested static table chain (multi-skip)' , ( ) = > {
it ( 'table→td→table→td offsetParent skip' , async ( ) = > {
const outer = box ( {
position : 'relative' ,
left : '160px' ,
top : '160px' ,
width : '600px' ,
height : '360px' ,
border : '1px solid'
} )
const t1 = document . createElement ( 'table' )
const tb1 = document . createElement ( 'tbody' )
const r1 = document . createElement ( 'tr' )
const c1 = document . createElement ( 'td' )
c1 . style . padding = '20px'
const t2 = document . createElement ( 'table' )
const tb2 = document . createElement ( 'tbody' )
const r2 = document . createElement ( 'tr' )
const c2 = document . createElement ( 'td' )
c2 . style . padding = '20px'
t1 . appendChild ( tb1 )
tb1 . appendChild ( r1 )
r1 . appendChild ( c1 )
c1 . appendChild ( t2 )
t2 . appendChild ( tb2 )
tb2 . appendChild ( r2 )
r2 . appendChild ( c2 )
outer . appendChild ( t1 )
const anchor = box (
{ position : 'absolute' , left : '20px' , top : '20px' , width : '90px' , height : '34px' } ,
c2
)
const floating = box ( { position : 'absolute' , width : '200px' , height : '120px' } , c2 )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , 'bottom' )
assertSame ( 'table-chain' , own , fui )
} )
} )
describe ( 'real-DOM parity — transformed <html> on a scrolled page' , ( ) = > {
it ( 'html translate + scroll' , async ( ) = > {
document . documentElement . style . transform = 'translate(30px, 50px)'
const spacer = box ( { position : 'absolute' , top : '0' , left : '0' , width : '1px' , height : '2500px' } )
void spacer
const anchor = box ( {
position : 'absolute' ,
left : '380px' ,
top : '1400px' ,
width : '90px' ,
height : '34px'
} )
const floating = box ( { position : 'absolute' , width : '200px' , height : '120px' } )
window . scrollTo ( 0 , 1000 )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , 'bottom' )
assertSame ( 'html-transform-scroll' , own , fui )
} )
} )
describe ( 'real-DOM parity — thick asymmetric offsetParent border (scrolled)' , ( ) = > {
for ( const placement of [ 'bottom' , 'right' ] as Placement [ ] ) {
it ( placement , async ( ) = > {
const scroller = box ( {
position : 'relative' ,
left : '120px' ,
top : '120px' ,
width : '320px' ,
height : '240px' ,
overflow : 'auto' ,
borderLeft : '20px solid' ,
borderTop : '8px solid' ,
borderRight : '2px solid' ,
borderBottom : '2px solid'
} )
const tall = box ( { height : '700px' , width : '700px' , position : 'relative' } , scroller )
const anchor = box (
{ position : 'absolute' , left : '60px' , top : '180px' , width : '90px' , height : '34px' } ,
tall
)
const floating = box ( { position : 'absolute' , width : '200px' , height : '120px' } , scroller )
scroller . scrollTop = 120
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , placement )
assertSame ( ` thick-border ${ placement } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — writing-mode vertical-rl' , ( ) = > {
for ( const placement of [ 'bottom-start' , 'right' ] as Placement [ ] ) {
it ( placement , async ( ) = > {
document . documentElement . style . writingMode = 'vertical-rl'
const anchor = box ( {
position : 'absolute' ,
left : '420px' ,
top : '300px' ,
width : '90px' ,
height : '34px'
} )
const floating = box ( { position : 'absolute' , width : '200px' , height : '120px' } )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 , alignmentAxis : 10 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 , alignmentAxis : 10 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , placement )
assertSame ( ` writing-mode ${ placement } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — shadow boundary crossing (anchor light, floating shadow)' , ( ) = > {
for ( const placement of [ 'bottom' , 'right' ] as Placement [ ] ) {
it ( placement , async ( ) = > {
const anchor = box ( {
position : 'absolute' ,
left : '380px' ,
top : '300px' ,
width : '90px' ,
height : '34px'
} )
const host = box ( { position : 'relative' } )
const root = host . attachShadow ( { mode : 'open' } )
const floating = document . createElement ( 'div' )
Object . assign ( floating . style , { position : 'absolute' , width : '200px' , height : '120px' } )
root . appendChild ( floating )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , placement )
assertSame ( ` shadow-cross ${ placement } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — floating inside two nested scroll containers' , ( ) = > {
for ( const [ s1 , s2 ] of [
[ 0 , 0 ] ,
[ 100 , 60 ]
] ) {
it ( ` outer= ${ s1 } inner= ${ s2 } ` , async ( ) = > {
const outer = box ( {
position : 'absolute' ,
left : '80px' ,
top : '80px' ,
width : '440px' ,
height : '320px' ,
overflow : 'auto' ,
border : '1px solid'
} )
const outerTall = box ( { height : '900px' , width : '760px' , position : 'relative' } , outer )
const inner = box (
{
position : 'absolute' ,
left : '40px' ,
top : '60px' ,
width : '300px' ,
height : '220px' ,
overflow : 'auto' ,
border : '1px solid'
} ,
outerTall
)
const innerTall = box ( { height : '700px' , width : '600px' , position : 'relative' } , inner )
const anchor = box (
{ position : 'absolute' , left : '40px' , top : '120px' , width : '90px' , height : '34px' } ,
innerTall
)
// floating ALSO inside the inner scroller → its clip = inner ∩ outer ∩ vp.
const floating = box ( { position : 'absolute' , width : '180px' , height : '120px' } , innerTall )
outer . scrollTop = s1
inner . scrollTop = s2
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 4 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 4 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , 'bottom' )
assertSame ( ` floating-2scroll ${ s1 } / ${ s2 } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — fixed × scaled containing block sweep' , ( ) = > {
for ( const placement of [ 'bottom' , 'top-start' , 'right' , 'left-end' ] as Placement [ ] ) {
it ( placement , async ( ) = > {
const wrapper = box ( {
position : 'relative' ,
transform : 'scale(1.25)' ,
transformOrigin : 'top left' ,
left : '180px' ,
top : '160px' ,
width : '420px' ,
height : '320px' ,
border : '1px solid'
} )
const anchor = box (
{ position : 'absolute' , left : '120px' , top : '120px' , width : '90px' , height : '34px' } ,
wrapper
)
const floating = box ( { position : 'fixed' , width : '200px' , height : '120px' } , wrapper )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 6 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 6 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , placement , 'fixed' )
assertSame ( ` fixed-scaled ${ placement } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — scaled clipping ancestor (getInnerBoundingClientRect scale)' , ( ) = > {
for ( const placement of [ 'bottom' , 'right' ] as Placement [ ] ) {
it ( placement , async ( ) = > {
const scroller = box ( {
position : 'relative' ,
transform : 'scale(1.25)' ,
transformOrigin : 'top left' ,
overflow : 'auto' ,
left : '120px' ,
top : '120px' ,
width : '300px' ,
height : '220px' ,
border : '1px solid'
} )
const tall = box ( { height : '700px' , width : '600px' , position : 'relative' } , scroller )
const anchor = box (
{ position : 'absolute' , left : '60px' , top : '150px' , width : '90px' , height : '34px' } ,
tall
)
// floating inside the scaled scroller → the scaled clip rect bounds it.
const floating = box ( { position : 'absolute' , width : '200px' , height : '160px' } , tall )
const mw : Built = {
own : [ ownOffset ( { mainAxis : 8 } ) , ownFlip ( ) , ownShift ( { padding : 4 } ) ] ,
fui : [ fuiOffset ( { mainAxis : 8 } ) , fuiFlip ( ) , fuiShift ( { padding : 4 } ) ]
}
const { own , fui } = await bothPositions ( anchor , floating , mw , placement )
assertSame ( ` scaled-clip ${ placement } ` , own , fui )
} )
}
} )
describe ( 'real-DOM parity — arrow + size in real layout' , ( ) = > {
it ( 'arrow centering (bottom) matches' , async ( ) = > {
const anchor = box ( {