@radix-ui/popper
Advanced tools
Comparing version 0.1.0 to 0.1.1-rc.1
@@ -1,2 +0,342 @@ | ||
exports.SIDE_OPTIONS=["top","right","bottom","left"];function t(t,e,r){const o=t["x"===r?"left":"top"],n="x"===r?"width":"height",i=t[n],p=e[n];return{before:o-p,start:o,center:o+(i-p)/2,end:o+i-p,after:o+i}}function e(t){return{position:"absolute",top:0,left:0,minWidth:"max-content",willChange:"transform",transform:`translate3d(${Math.round(t.x+window.scrollX)}px, ${Math.round(t.y+window.scrollY)}px, 0)`}}function r(t,e,r,o,n){const i="top"===e||"bottom"===e,p=n?n.width:0,a=n?n.height:0,s=p/2+o;let c="",f="";return i?(c={start:`${s}px`,center:"center",end:t.width-s+"px"}[r],f="top"===e?`${t.height+a}px`:-a+"px"):(c="left"===e?`${t.width+a}px`:-a+"px",f={start:`${s}px`,center:"center",end:t.height-s+"px"}[r]),`${c} ${f}`}exports.ALIGN_OPTIONS=["start","center","end"],exports.getPlacementData=function({anchorRect:p,popperSize:c,arrowSize:f,arrowOffset:l=0,side:d,sideOffset:h=0,align:x,alignOffset:g=0,shouldAvoidCollisions:u=!0,collisionBoundariesRect:w,collisionTolerance:m=0}){if(!p||!c||!w)return{popperStyles:o,arrowStyles:n};const y=function(e,r,o=0,n=0,i){const p=i?i.height:0,a=t(r,e,"x"),s=t(r,e,"y"),c=s.before-o-p,f=s.after+o+p,l=a.before-o-p,d=a.after+o+p;return{top:{start:{x:a.start+n,y:c},center:{x:a.center,y:c},end:{x:a.end-n,y:c}},right:{start:{x:d,y:s.start+n},center:{x:d,y:s.center},end:{x:d,y:s.end-n}},bottom:{start:{x:a.start+n,y:f},center:{x:a.center,y:f},end:{x:a.end-n,y:f}},left:{start:{x:l,y:s.start+n},center:{x:l,y:s.center},end:{x:l,y:s.end-n}}}}(c,p,h,g,f),b=y[d][x];if(!1===u){const t=e(b);let o=n;f&&(o=i({popperSize:c,arrowSize:f,arrowOffset:l,side:d,align:x}));return{popperStyles:{...t,"--radix-popper-transform-origin":r(c,d,x,l,f)},arrowStyles:o,placedSide:d,placedAlign:x}}const S=DOMRect.fromRect({...c,...b}),$=(O=w,z=m,DOMRect.fromRect({width:O.width-2*z,height:O.height-2*z,x:O.left+z,y:O.top+z}));var O,z;const R=s(S,$),M=y[a(d)][x],D=function(t,e,r){const o=a(t);return e[t]&&!r[o]?o:t}(d,R,s(DOMRect.fromRect({...c,...M}),$)),A=function(t,e,r,o,n){const i="top"===r||"bottom"===r,p=i?"left":"top",a=i?"right":"bottom",s=i?"width":"height",c=e[s]>t[s];if(("start"===o||"center"===o)&&(n[p]&&c||n[a]&&!c))return"end";if(("end"===o||"center"===o)&&(n[a]&&c||n[p]&&!c))return"start";return o}(c,p,d,x,R),I=e(y[D][A]);let C=n;return f&&(C=i({popperSize:c,arrowSize:f,arrowOffset:l,side:D,align:A})),{popperStyles:{...I,"--radix-popper-transform-origin":r(c,D,A,l,f)},arrowStyles:C,placedSide:D,placedAlign:A}};const o={position:"fixed",top:0,left:0,opacity:0,transform:"translate3d(0, -200%, 0)"},n={position:"absolute",opacity:0};function i({popperSize:t,arrowSize:e,arrowOffset:r,side:o,align:n}){const i=(t.width-e.width)/2,a=(t.height-e.width)/2,s={top:0,right:90,bottom:180,left:-90}[o],c=Math.max(e.width,e.height),f={width:`${c}px`,height:`${c}px`,transform:`rotate(${s}deg)`,willChange:"transform",position:"absolute",[o]:"100%",direction:p(o,n)};return"top"!==o&&"bottom"!==o||("start"===n&&(f.left=`${r}px`),"center"===n&&(f.left=`${i}px`),"end"===n&&(f.right=`${r}px`)),"left"!==o&&"right"!==o||("start"===n&&(f.top=`${r}px`),"center"===n&&(f.top=`${a}px`),"end"===n&&(f.bottom=`${r}px`)),f}function p(t,e){return("top"!==t&&"right"!==t||"end"!==e)&&("bottom"!==t&&"left"!==t||"end"===e)?"ltr":"rtl"}function a(t){return{top:"bottom",right:"left",bottom:"top",left:"right"}[t]}function s(t,e){return{top:t.top<e.top,right:t.right>e.right,bottom:t.bottom>e.bottom,left:t.left<e.left}} | ||
function $parcel$export(e, n, v, s) { | ||
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true}); | ||
} | ||
$parcel$export(module.exports, "getPlacementData", () => $25d1e7214bd08a9d$export$d3e7649885811a7d); | ||
$parcel$export(module.exports, "SIDE_OPTIONS", () => $25d1e7214bd08a9d$export$36f0086da09c4b9f); | ||
$parcel$export(module.exports, "ALIGN_OPTIONS", () => $25d1e7214bd08a9d$export$3671ffab7b302fc9); | ||
const $25d1e7214bd08a9d$export$36f0086da09c4b9f = [ | ||
'top', | ||
'right', | ||
'bottom', | ||
'left' | ||
]; | ||
const $25d1e7214bd08a9d$export$3671ffab7b302fc9 = [ | ||
'start', | ||
'center', | ||
'end' | ||
]; | ||
/** | ||
* Given all the information necessary to compute it, | ||
* this function calculates all the necessary placement data. | ||
* | ||
* It will return: | ||
* | ||
* - the styles to apply to the popper (including a custom property that is useful to set the transform origin in the right place) | ||
* - the styles to apply to the arrow | ||
* - the placed side (because it might have changed because of collisions) | ||
* - the placed align (because it might have changed because of collisions) | ||
*/ function $25d1e7214bd08a9d$export$d3e7649885811a7d({ anchorRect: anchorRect , popperSize: popperSize , arrowSize: arrowSize , arrowOffset: arrowOffset = 0 , side: side , sideOffset: sideOffset = 0 , align: align , alignOffset: alignOffset = 0 , shouldAvoidCollisions: shouldAvoidCollisions = true , collisionBoundariesRect: collisionBoundariesRect , collisionTolerance: collisionTolerance = 0 }) { | ||
// if we're not ready to do all the measurements yet, | ||
// we return some good default styles | ||
if (!anchorRect || !popperSize || !collisionBoundariesRect) return { | ||
popperStyles: $25d1e7214bd08a9d$var$UNMEASURED_POPPER_STYLES, | ||
arrowStyles: $25d1e7214bd08a9d$var$UNMEASURED_ARROW_STYLES | ||
}; | ||
// pre-compute points for all potential placements | ||
const allPlacementPoints = $25d1e7214bd08a9d$var$getAllPlacementPoints(popperSize, anchorRect, sideOffset, alignOffset, arrowSize); // get point based on side / align | ||
const popperPoint = allPlacementPoints[side][align]; // if we don't need to avoid collisions, we can stop here | ||
if (shouldAvoidCollisions === false) { | ||
const popperStyles = $25d1e7214bd08a9d$var$getPlacementStylesForPoint(popperPoint); | ||
let arrowStyles = $25d1e7214bd08a9d$var$UNMEASURED_ARROW_STYLES; | ||
if (arrowSize) arrowStyles = $25d1e7214bd08a9d$var$getPopperArrowStyles({ | ||
popperSize: popperSize, | ||
arrowSize: arrowSize, | ||
arrowOffset: arrowOffset, | ||
side: side, | ||
align: align | ||
}); | ||
const transformOrigin = $25d1e7214bd08a9d$var$getTransformOrigin(popperSize, side, align, arrowOffset, arrowSize); | ||
return { | ||
popperStyles: { | ||
...popperStyles, | ||
['--radix-popper-transform-origin']: transformOrigin | ||
}, | ||
arrowStyles: arrowStyles, | ||
placedSide: side, | ||
placedAlign: align | ||
}; | ||
} // create a new rect as if element had been moved to new placement | ||
const popperRect = DOMRect.fromRect({ | ||
...popperSize, | ||
...popperPoint | ||
}); // create a new rect representing the collision boundaries but taking into account any added tolerance | ||
const collisionBoundariesRectWithTolerance = $25d1e7214bd08a9d$var$getContractedRect(collisionBoundariesRect, collisionTolerance); // check for any collisions in new placement | ||
const popperCollisions = $25d1e7214bd08a9d$var$getCollisions(popperRect, collisionBoundariesRectWithTolerance); // do all the same calculations for the opposite side | ||
// this is because we need to check for potential collisions if we were to swap side | ||
const oppositeSide = $25d1e7214bd08a9d$var$getOppositeSide(side); | ||
const oppositeSidePopperPoint = allPlacementPoints[oppositeSide][align]; | ||
const updatedOppositeSidePopperPoint = DOMRect.fromRect({ | ||
...popperSize, | ||
...oppositeSidePopperPoint | ||
}); | ||
const oppositeSidePopperCollisions = $25d1e7214bd08a9d$var$getCollisions(updatedOppositeSidePopperPoint, collisionBoundariesRectWithTolerance); // adjust side accounting for collisions / opposite side collisions | ||
const placedSide = $25d1e7214bd08a9d$var$getSideAccountingForCollisions(side, popperCollisions, oppositeSidePopperCollisions); // adjust alignnment accounting for collisions | ||
const placedAlign = $25d1e7214bd08a9d$var$getAlignAccountingForCollisions(popperSize, anchorRect, side, align, popperCollisions); | ||
const placedPopperPoint = allPlacementPoints[placedSide][placedAlign]; // compute adjusted popper / arrow styles | ||
const popperStyles = $25d1e7214bd08a9d$var$getPlacementStylesForPoint(placedPopperPoint); | ||
let arrowStyles = $25d1e7214bd08a9d$var$UNMEASURED_ARROW_STYLES; | ||
if (arrowSize) arrowStyles = $25d1e7214bd08a9d$var$getPopperArrowStyles({ | ||
popperSize: popperSize, | ||
arrowSize: arrowSize, | ||
arrowOffset: arrowOffset, | ||
side: placedSide, | ||
align: placedAlign | ||
}); | ||
const transformOrigin = $25d1e7214bd08a9d$var$getTransformOrigin(popperSize, placedSide, placedAlign, arrowOffset, arrowSize); | ||
return { | ||
popperStyles: { | ||
...popperStyles, | ||
['--radix-popper-transform-origin']: transformOrigin | ||
}, | ||
arrowStyles: arrowStyles, | ||
placedSide: placedSide, | ||
placedAlign: placedAlign | ||
}; | ||
} | ||
function $25d1e7214bd08a9d$var$getAllPlacementPoints(popperSize, anchorRect, sideOffset = 0, alignOffset = 0, arrowSize) { | ||
const arrowBaseToTipLength = arrowSize ? arrowSize.height : 0; | ||
const x = $25d1e7214bd08a9d$var$getPopperSlotsForAxis(anchorRect, popperSize, 'x'); | ||
const y = $25d1e7214bd08a9d$var$getPopperSlotsForAxis(anchorRect, popperSize, 'y'); | ||
const topY = y.before - sideOffset - arrowBaseToTipLength; // prettier-ignore | ||
const bottomY = y.after + sideOffset + arrowBaseToTipLength; // prettier-ignore | ||
const leftX = x.before - sideOffset - arrowBaseToTipLength; // prettier-ignore | ||
const rightX = x.after + sideOffset + arrowBaseToTipLength; // prettier-ignore | ||
// prettier-ignore | ||
const map = { | ||
top: { | ||
start: { | ||
x: x.start + alignOffset, | ||
y: topY | ||
}, | ||
center: { | ||
x: x.center, | ||
y: topY | ||
}, | ||
end: { | ||
x: x.end - alignOffset, | ||
y: topY | ||
} | ||
}, | ||
right: { | ||
start: { | ||
x: rightX, | ||
y: y.start + alignOffset | ||
}, | ||
center: { | ||
x: rightX, | ||
y: y.center | ||
}, | ||
end: { | ||
x: rightX, | ||
y: y.end - alignOffset | ||
} | ||
}, | ||
bottom: { | ||
start: { | ||
x: x.start + alignOffset, | ||
y: bottomY | ||
}, | ||
center: { | ||
x: x.center, | ||
y: bottomY | ||
}, | ||
end: { | ||
x: x.end - alignOffset, | ||
y: bottomY | ||
} | ||
}, | ||
left: { | ||
start: { | ||
x: leftX, | ||
y: y.start + alignOffset | ||
}, | ||
center: { | ||
x: leftX, | ||
y: y.center | ||
}, | ||
end: { | ||
x: leftX, | ||
y: y.end - alignOffset | ||
} | ||
} | ||
}; | ||
return map; | ||
} | ||
function $25d1e7214bd08a9d$var$getPopperSlotsForAxis(anchorRect, popperSize, axis) { | ||
const startSide = axis === 'x' ? 'left' : 'top'; | ||
const anchorStart = anchorRect[startSide]; | ||
const dimension = axis === 'x' ? 'width' : 'height'; | ||
const anchorDimension = anchorRect[dimension]; | ||
const popperDimension = popperSize[dimension]; // prettier-ignore | ||
return { | ||
before: anchorStart - popperDimension, | ||
start: anchorStart, | ||
center: anchorStart + (anchorDimension - popperDimension) / 2, | ||
end: anchorStart + anchorDimension - popperDimension, | ||
after: anchorStart + anchorDimension | ||
}; | ||
} | ||
/** | ||
* Gets an adjusted side based on collision information | ||
*/ function $25d1e7214bd08a9d$var$getSideAccountingForCollisions(/** The side we want to ideally position to */ side, /** The collisions for this given side */ collisions, /** The collisions for the opposite side (if we were to swap side) */ oppositeSideCollisions) { | ||
const oppositeSide = $25d1e7214bd08a9d$var$getOppositeSide(side); // in order to prevent premature jumps | ||
// we only swap side if there's enough space to fit on the opposite side | ||
return collisions[side] && !oppositeSideCollisions[oppositeSide] ? oppositeSide : side; | ||
} | ||
/** | ||
* Gets an adjusted alignment based on collision information | ||
*/ function $25d1e7214bd08a9d$var$getAlignAccountingForCollisions(/** The size of the popper to place */ popperSize, /** The size of the anchor we are placing around */ anchorSize, /** The final side */ side, /** The desired align */ align, /** The collisions */ collisions) { | ||
const isHorizontalSide = side === 'top' || side === 'bottom'; | ||
const startBound = isHorizontalSide ? 'left' : 'top'; | ||
const endBound = isHorizontalSide ? 'right' : 'bottom'; | ||
const dimension = isHorizontalSide ? 'width' : 'height'; | ||
const isAnchorBigger = anchorSize[dimension] > popperSize[dimension]; | ||
if (align === 'start' || align === 'center') { | ||
if (collisions[startBound] && isAnchorBigger || collisions[endBound] && !isAnchorBigger) return 'end'; | ||
} | ||
if (align === 'end' || align === 'center') { | ||
if (collisions[endBound] && isAnchorBigger || collisions[startBound] && !isAnchorBigger) return 'start'; | ||
} | ||
return align; | ||
} | ||
function $25d1e7214bd08a9d$var$getPlacementStylesForPoint(point) { | ||
const x = Math.round(point.x + window.scrollX); | ||
const y = Math.round(point.y + window.scrollY); | ||
return { | ||
position: 'absolute', | ||
top: 0, | ||
left: 0, | ||
minWidth: 'max-content', | ||
willChange: 'transform', | ||
transform: `translate3d(${x}px, ${y}px, 0)` | ||
}; | ||
} | ||
function $25d1e7214bd08a9d$var$getTransformOrigin(popperSize, side, align, arrowOffset, arrowSize) { | ||
const isHorizontalSide = side === 'top' || side === 'bottom'; | ||
const arrowBaseLength = arrowSize ? arrowSize.width : 0; | ||
const arrowBaseToTipLength = arrowSize ? arrowSize.height : 0; | ||
const sideOffset = arrowBaseToTipLength; | ||
const alignOffset = arrowBaseLength / 2 + arrowOffset; | ||
let x = ''; | ||
let y = ''; | ||
if (isHorizontalSide) { | ||
x = ({ | ||
start: `${alignOffset}px`, | ||
center: 'center', | ||
end: `${popperSize.width - alignOffset}px` | ||
})[align]; | ||
y = side === 'top' ? `${popperSize.height + sideOffset}px` : `${-sideOffset}px`; | ||
} else { | ||
x = side === 'left' ? `${popperSize.width + sideOffset}px` : `${-sideOffset}px`; | ||
y = ({ | ||
start: `${alignOffset}px`, | ||
center: 'center', | ||
end: `${popperSize.height - alignOffset}px` | ||
})[align]; | ||
} | ||
return `${x} ${y}`; | ||
} | ||
const $25d1e7214bd08a9d$var$UNMEASURED_POPPER_STYLES = { | ||
// position: 'fixed' here is important because it will take the popper | ||
// out of the flow so it does not disturb the position of the anchor | ||
position: 'fixed', | ||
top: 0, | ||
left: 0, | ||
opacity: 0, | ||
transform: 'translate3d(0, -200%, 0)' | ||
}; | ||
const $25d1e7214bd08a9d$var$UNMEASURED_ARROW_STYLES = { | ||
// given the arrow is nested inside the popper, | ||
// make sure that it is out of the flow and doesn't hinder then popper's measurement | ||
position: 'absolute', | ||
opacity: 0 | ||
}; | ||
/** | ||
* Computes the styles necessary to position, rotate and align the arrow correctly. | ||
* It can adjust itself based on anchor/popper size, side/align and an optional offset. | ||
*/ function $25d1e7214bd08a9d$var$getPopperArrowStyles({ popperSize: popperSize , arrowSize: arrowSize , arrowOffset: arrowOffset , side: side , align: align }) { | ||
const popperCenterX = (popperSize.width - arrowSize.width) / 2; | ||
const popperCenterY = (popperSize.height - arrowSize.width) / 2; | ||
const rotationMap = { | ||
top: 0, | ||
right: 90, | ||
bottom: 180, | ||
left: -90 | ||
}; | ||
const rotation = rotationMap[side]; | ||
const arrowMaxDimension = Math.max(arrowSize.width, arrowSize.height); | ||
const styles = { | ||
// we make sure we put the arrow inside a 1:1 ratio container | ||
// this is to make the rotation handling simpler | ||
// as we do no need to worry about changing the transform-origin | ||
width: `${arrowMaxDimension}px`, | ||
height: `${arrowMaxDimension}px`, | ||
// rotate the arrow appropriately | ||
transform: `rotate(${rotation}deg)`, | ||
willChange: 'transform', | ||
// position the arrow appropriately | ||
position: 'absolute', | ||
[side]: '100%', | ||
// Because the arrow gets rotated (see `transform above`) | ||
// and we are putting it inside a 1:1 ratio container | ||
// we need to adjust the CSS direction from `ltr` to `rtl` | ||
// in some circumstances | ||
direction: $25d1e7214bd08a9d$var$getArrowCssDirection(side, align) | ||
}; | ||
if (side === 'top' || side === 'bottom') { | ||
if (align === 'start') styles.left = `${arrowOffset}px`; | ||
if (align === 'center') styles.left = `${popperCenterX}px`; | ||
if (align === 'end') styles.right = `${arrowOffset}px`; | ||
} | ||
if (side === 'left' || side === 'right') { | ||
if (align === 'start') styles.top = `${arrowOffset}px`; | ||
if (align === 'center') styles.top = `${popperCenterY}px`; | ||
if (align === 'end') styles.bottom = `${arrowOffset}px`; | ||
} | ||
return styles; | ||
} | ||
/** | ||
* Adjusts the arrow's CSS direction (`ltr` / `rtl`) | ||
*/ function $25d1e7214bd08a9d$var$getArrowCssDirection(side, align) { | ||
if ((side === 'top' || side === 'right') && align === 'end') return 'rtl'; | ||
if ((side === 'bottom' || side === 'left') && align !== 'end') return 'rtl'; | ||
return 'ltr'; | ||
} | ||
/** | ||
* Gets the opposite side of a given side (ie. top => bottom, left => right, …) | ||
*/ function $25d1e7214bd08a9d$var$getOppositeSide(side) { | ||
const oppositeSides = { | ||
top: 'bottom', | ||
right: 'left', | ||
bottom: 'top', | ||
left: 'right' | ||
}; | ||
return oppositeSides[side]; | ||
} | ||
/** | ||
* Creates a new rect (`ClientRect`) based on a given one but contracted by | ||
* a given amout on each side. | ||
*/ function $25d1e7214bd08a9d$var$getContractedRect(rect, amount) { | ||
return DOMRect.fromRect({ | ||
width: rect.width - amount * 2, | ||
height: rect.height - amount * 2, | ||
x: rect.left + amount, | ||
y: rect.top + amount | ||
}); | ||
} | ||
/** | ||
* Gets collisions for each side of a rect (top, right, bottom, left) | ||
*/ function $25d1e7214bd08a9d$var$getCollisions(/** The rect to test collisions against */ rect, /** The rect which represents the boundaries for collision checks */ collisionBoundariesRect) { | ||
return { | ||
top: rect.top < collisionBoundariesRect.top, | ||
right: rect.right > collisionBoundariesRect.right, | ||
bottom: rect.bottom > collisionBoundariesRect.bottom, | ||
left: rect.left < collisionBoundariesRect.left | ||
}; | ||
} | ||
//# sourceMappingURL=index.js.map |
@@ -1,2 +0,336 @@ | ||
export const SIDE_OPTIONS=["top","right","bottom","left"];export const ALIGN_OPTIONS=["start","center","end"];export function getPlacementData({anchorRect:p,popperSize:c,arrowSize:f,arrowOffset:l=0,side:d,sideOffset:h=0,align:x,alignOffset:g=0,shouldAvoidCollisions:u=!0,collisionBoundariesRect:w,collisionTolerance:m=0}){if(!p||!c||!w)return{popperStyles:o,arrowStyles:n};const y=function(e,r,o=0,n=0,i){const p=i?i.height:0,a=t(r,e,"x"),s=t(r,e,"y"),c=s.before-o-p,f=s.after+o+p,l=a.before-o-p,d=a.after+o+p;return{top:{start:{x:a.start+n,y:c},center:{x:a.center,y:c},end:{x:a.end-n,y:c}},right:{start:{x:d,y:s.start+n},center:{x:d,y:s.center},end:{x:d,y:s.end-n}},bottom:{start:{x:a.start+n,y:f},center:{x:a.center,y:f},end:{x:a.end-n,y:f}},left:{start:{x:l,y:s.start+n},center:{x:l,y:s.center},end:{x:l,y:s.end-n}}}}(c,p,h,g,f),b=y[d][x];if(!1===u){const t=e(b);let o=n;f&&(o=i({popperSize:c,arrowSize:f,arrowOffset:l,side:d,align:x}));return{popperStyles:{...t,"--radix-popper-transform-origin":r(c,d,x,l,f)},arrowStyles:o,placedSide:d,placedAlign:x}}const S=DOMRect.fromRect({...c,...b}),$=(O=w,z=m,DOMRect.fromRect({width:O.width-2*z,height:O.height-2*z,x:O.left+z,y:O.top+z}));var O,z;const R=s(S,$),M=y[a(d)][x],D=function(t,e,r){const o=a(t);return e[t]&&!r[o]?o:t}(d,R,s(DOMRect.fromRect({...c,...M}),$)),A=function(t,e,r,o,n){const i="top"===r||"bottom"===r,p=i?"left":"top",a=i?"right":"bottom",s=i?"width":"height",c=e[s]>t[s];if(("start"===o||"center"===o)&&(n[p]&&c||n[a]&&!c))return"end";if(("end"===o||"center"===o)&&(n[a]&&c||n[p]&&!c))return"start";return o}(c,p,d,x,R),I=e(y[D][A]);let C=n;f&&(C=i({popperSize:c,arrowSize:f,arrowOffset:l,side:D,align:A}));return{popperStyles:{...I,"--radix-popper-transform-origin":r(c,D,A,l,f)},arrowStyles:C,placedSide:D,placedAlign:A}}function t(t,e,r){const o=t["x"===r?"left":"top"],n="x"===r?"width":"height",i=t[n],p=e[n];return{before:o-p,start:o,center:o+(i-p)/2,end:o+i-p,after:o+i}}function e(t){return{position:"absolute",top:0,left:0,minWidth:"max-content",willChange:"transform",transform:`translate3d(${Math.round(t.x+window.scrollX)}px, ${Math.round(t.y+window.scrollY)}px, 0)`}}function r(t,e,r,o,n){const i="top"===e||"bottom"===e,p=n?n.width:0,a=n?n.height:0,s=p/2+o;let c="",f="";return i?(c={start:`${s}px`,center:"center",end:t.width-s+"px"}[r],f="top"===e?`${t.height+a}px`:-a+"px"):(c="left"===e?`${t.width+a}px`:-a+"px",f={start:`${s}px`,center:"center",end:t.height-s+"px"}[r]),`${c} ${f}`}const o={position:"fixed",top:0,left:0,opacity:0,transform:"translate3d(0, -200%, 0)"},n={position:"absolute",opacity:0};function i({popperSize:t,arrowSize:e,arrowOffset:r,side:o,align:n}){const i=(t.width-e.width)/2,a=(t.height-e.width)/2,s={top:0,right:90,bottom:180,left:-90}[o],c=Math.max(e.width,e.height),f={width:`${c}px`,height:`${c}px`,transform:`rotate(${s}deg)`,willChange:"transform",position:"absolute",[o]:"100%",direction:p(o,n)};return"top"!==o&&"bottom"!==o||("start"===n&&(f.left=`${r}px`),"center"===n&&(f.left=`${i}px`),"end"===n&&(f.right=`${r}px`)),"left"!==o&&"right"!==o||("start"===n&&(f.top=`${r}px`),"center"===n&&(f.top=`${a}px`),"end"===n&&(f.bottom=`${r}px`)),f}function p(t,e){return("top"!==t&&"right"!==t||"end"!==e)&&("bottom"!==t&&"left"!==t||"end"===e)?"ltr":"rtl"}function a(t){return{top:"bottom",right:"left",bottom:"top",left:"right"}[t]}function s(t,e){return{top:t.top<e.top,right:t.right>e.right,bottom:t.bottom>e.bottom,left:t.left<e.left}} | ||
const $dcd28e347ddb21ab$export$36f0086da09c4b9f = [ | ||
'top', | ||
'right', | ||
'bottom', | ||
'left' | ||
]; | ||
const $dcd28e347ddb21ab$export$3671ffab7b302fc9 = [ | ||
'start', | ||
'center', | ||
'end' | ||
]; | ||
/** | ||
* Given all the information necessary to compute it, | ||
* this function calculates all the necessary placement data. | ||
* | ||
* It will return: | ||
* | ||
* - the styles to apply to the popper (including a custom property that is useful to set the transform origin in the right place) | ||
* - the styles to apply to the arrow | ||
* - the placed side (because it might have changed because of collisions) | ||
* - the placed align (because it might have changed because of collisions) | ||
*/ function $dcd28e347ddb21ab$export$d3e7649885811a7d({ anchorRect: anchorRect , popperSize: popperSize , arrowSize: arrowSize , arrowOffset: arrowOffset = 0 , side: side , sideOffset: sideOffset = 0 , align: align , alignOffset: alignOffset = 0 , shouldAvoidCollisions: shouldAvoidCollisions = true , collisionBoundariesRect: collisionBoundariesRect , collisionTolerance: collisionTolerance = 0 }) { | ||
// if we're not ready to do all the measurements yet, | ||
// we return some good default styles | ||
if (!anchorRect || !popperSize || !collisionBoundariesRect) return { | ||
popperStyles: $dcd28e347ddb21ab$var$UNMEASURED_POPPER_STYLES, | ||
arrowStyles: $dcd28e347ddb21ab$var$UNMEASURED_ARROW_STYLES | ||
}; | ||
// pre-compute points for all potential placements | ||
const allPlacementPoints = $dcd28e347ddb21ab$var$getAllPlacementPoints(popperSize, anchorRect, sideOffset, alignOffset, arrowSize); // get point based on side / align | ||
const popperPoint = allPlacementPoints[side][align]; // if we don't need to avoid collisions, we can stop here | ||
if (shouldAvoidCollisions === false) { | ||
const popperStyles = $dcd28e347ddb21ab$var$getPlacementStylesForPoint(popperPoint); | ||
let arrowStyles = $dcd28e347ddb21ab$var$UNMEASURED_ARROW_STYLES; | ||
if (arrowSize) arrowStyles = $dcd28e347ddb21ab$var$getPopperArrowStyles({ | ||
popperSize: popperSize, | ||
arrowSize: arrowSize, | ||
arrowOffset: arrowOffset, | ||
side: side, | ||
align: align | ||
}); | ||
const transformOrigin = $dcd28e347ddb21ab$var$getTransformOrigin(popperSize, side, align, arrowOffset, arrowSize); | ||
return { | ||
popperStyles: { | ||
...popperStyles, | ||
['--radix-popper-transform-origin']: transformOrigin | ||
}, | ||
arrowStyles: arrowStyles, | ||
placedSide: side, | ||
placedAlign: align | ||
}; | ||
} // create a new rect as if element had been moved to new placement | ||
const popperRect = DOMRect.fromRect({ | ||
...popperSize, | ||
...popperPoint | ||
}); // create a new rect representing the collision boundaries but taking into account any added tolerance | ||
const collisionBoundariesRectWithTolerance = $dcd28e347ddb21ab$var$getContractedRect(collisionBoundariesRect, collisionTolerance); // check for any collisions in new placement | ||
const popperCollisions = $dcd28e347ddb21ab$var$getCollisions(popperRect, collisionBoundariesRectWithTolerance); // do all the same calculations for the opposite side | ||
// this is because we need to check for potential collisions if we were to swap side | ||
const oppositeSide = $dcd28e347ddb21ab$var$getOppositeSide(side); | ||
const oppositeSidePopperPoint = allPlacementPoints[oppositeSide][align]; | ||
const updatedOppositeSidePopperPoint = DOMRect.fromRect({ | ||
...popperSize, | ||
...oppositeSidePopperPoint | ||
}); | ||
const oppositeSidePopperCollisions = $dcd28e347ddb21ab$var$getCollisions(updatedOppositeSidePopperPoint, collisionBoundariesRectWithTolerance); // adjust side accounting for collisions / opposite side collisions | ||
const placedSide = $dcd28e347ddb21ab$var$getSideAccountingForCollisions(side, popperCollisions, oppositeSidePopperCollisions); // adjust alignnment accounting for collisions | ||
const placedAlign = $dcd28e347ddb21ab$var$getAlignAccountingForCollisions(popperSize, anchorRect, side, align, popperCollisions); | ||
const placedPopperPoint = allPlacementPoints[placedSide][placedAlign]; // compute adjusted popper / arrow styles | ||
const popperStyles = $dcd28e347ddb21ab$var$getPlacementStylesForPoint(placedPopperPoint); | ||
let arrowStyles = $dcd28e347ddb21ab$var$UNMEASURED_ARROW_STYLES; | ||
if (arrowSize) arrowStyles = $dcd28e347ddb21ab$var$getPopperArrowStyles({ | ||
popperSize: popperSize, | ||
arrowSize: arrowSize, | ||
arrowOffset: arrowOffset, | ||
side: placedSide, | ||
align: placedAlign | ||
}); | ||
const transformOrigin = $dcd28e347ddb21ab$var$getTransformOrigin(popperSize, placedSide, placedAlign, arrowOffset, arrowSize); | ||
return { | ||
popperStyles: { | ||
...popperStyles, | ||
['--radix-popper-transform-origin']: transformOrigin | ||
}, | ||
arrowStyles: arrowStyles, | ||
placedSide: placedSide, | ||
placedAlign: placedAlign | ||
}; | ||
} | ||
function $dcd28e347ddb21ab$var$getAllPlacementPoints(popperSize, anchorRect, sideOffset = 0, alignOffset = 0, arrowSize) { | ||
const arrowBaseToTipLength = arrowSize ? arrowSize.height : 0; | ||
const x = $dcd28e347ddb21ab$var$getPopperSlotsForAxis(anchorRect, popperSize, 'x'); | ||
const y = $dcd28e347ddb21ab$var$getPopperSlotsForAxis(anchorRect, popperSize, 'y'); | ||
const topY = y.before - sideOffset - arrowBaseToTipLength; // prettier-ignore | ||
const bottomY = y.after + sideOffset + arrowBaseToTipLength; // prettier-ignore | ||
const leftX = x.before - sideOffset - arrowBaseToTipLength; // prettier-ignore | ||
const rightX = x.after + sideOffset + arrowBaseToTipLength; // prettier-ignore | ||
// prettier-ignore | ||
const map = { | ||
top: { | ||
start: { | ||
x: x.start + alignOffset, | ||
y: topY | ||
}, | ||
center: { | ||
x: x.center, | ||
y: topY | ||
}, | ||
end: { | ||
x: x.end - alignOffset, | ||
y: topY | ||
} | ||
}, | ||
right: { | ||
start: { | ||
x: rightX, | ||
y: y.start + alignOffset | ||
}, | ||
center: { | ||
x: rightX, | ||
y: y.center | ||
}, | ||
end: { | ||
x: rightX, | ||
y: y.end - alignOffset | ||
} | ||
}, | ||
bottom: { | ||
start: { | ||
x: x.start + alignOffset, | ||
y: bottomY | ||
}, | ||
center: { | ||
x: x.center, | ||
y: bottomY | ||
}, | ||
end: { | ||
x: x.end - alignOffset, | ||
y: bottomY | ||
} | ||
}, | ||
left: { | ||
start: { | ||
x: leftX, | ||
y: y.start + alignOffset | ||
}, | ||
center: { | ||
x: leftX, | ||
y: y.center | ||
}, | ||
end: { | ||
x: leftX, | ||
y: y.end - alignOffset | ||
} | ||
} | ||
}; | ||
return map; | ||
} | ||
function $dcd28e347ddb21ab$var$getPopperSlotsForAxis(anchorRect, popperSize, axis) { | ||
const startSide = axis === 'x' ? 'left' : 'top'; | ||
const anchorStart = anchorRect[startSide]; | ||
const dimension = axis === 'x' ? 'width' : 'height'; | ||
const anchorDimension = anchorRect[dimension]; | ||
const popperDimension = popperSize[dimension]; // prettier-ignore | ||
return { | ||
before: anchorStart - popperDimension, | ||
start: anchorStart, | ||
center: anchorStart + (anchorDimension - popperDimension) / 2, | ||
end: anchorStart + anchorDimension - popperDimension, | ||
after: anchorStart + anchorDimension | ||
}; | ||
} | ||
/** | ||
* Gets an adjusted side based on collision information | ||
*/ function $dcd28e347ddb21ab$var$getSideAccountingForCollisions(/** The side we want to ideally position to */ side, /** The collisions for this given side */ collisions, /** The collisions for the opposite side (if we were to swap side) */ oppositeSideCollisions) { | ||
const oppositeSide = $dcd28e347ddb21ab$var$getOppositeSide(side); // in order to prevent premature jumps | ||
// we only swap side if there's enough space to fit on the opposite side | ||
return collisions[side] && !oppositeSideCollisions[oppositeSide] ? oppositeSide : side; | ||
} | ||
/** | ||
* Gets an adjusted alignment based on collision information | ||
*/ function $dcd28e347ddb21ab$var$getAlignAccountingForCollisions(/** The size of the popper to place */ popperSize, /** The size of the anchor we are placing around */ anchorSize, /** The final side */ side, /** The desired align */ align, /** The collisions */ collisions) { | ||
const isHorizontalSide = side === 'top' || side === 'bottom'; | ||
const startBound = isHorizontalSide ? 'left' : 'top'; | ||
const endBound = isHorizontalSide ? 'right' : 'bottom'; | ||
const dimension = isHorizontalSide ? 'width' : 'height'; | ||
const isAnchorBigger = anchorSize[dimension] > popperSize[dimension]; | ||
if (align === 'start' || align === 'center') { | ||
if (collisions[startBound] && isAnchorBigger || collisions[endBound] && !isAnchorBigger) return 'end'; | ||
} | ||
if (align === 'end' || align === 'center') { | ||
if (collisions[endBound] && isAnchorBigger || collisions[startBound] && !isAnchorBigger) return 'start'; | ||
} | ||
return align; | ||
} | ||
function $dcd28e347ddb21ab$var$getPlacementStylesForPoint(point) { | ||
const x = Math.round(point.x + window.scrollX); | ||
const y = Math.round(point.y + window.scrollY); | ||
return { | ||
position: 'absolute', | ||
top: 0, | ||
left: 0, | ||
minWidth: 'max-content', | ||
willChange: 'transform', | ||
transform: `translate3d(${x}px, ${y}px, 0)` | ||
}; | ||
} | ||
function $dcd28e347ddb21ab$var$getTransformOrigin(popperSize, side, align, arrowOffset, arrowSize) { | ||
const isHorizontalSide = side === 'top' || side === 'bottom'; | ||
const arrowBaseLength = arrowSize ? arrowSize.width : 0; | ||
const arrowBaseToTipLength = arrowSize ? arrowSize.height : 0; | ||
const sideOffset = arrowBaseToTipLength; | ||
const alignOffset = arrowBaseLength / 2 + arrowOffset; | ||
let x = ''; | ||
let y = ''; | ||
if (isHorizontalSide) { | ||
x = ({ | ||
start: `${alignOffset}px`, | ||
center: 'center', | ||
end: `${popperSize.width - alignOffset}px` | ||
})[align]; | ||
y = side === 'top' ? `${popperSize.height + sideOffset}px` : `${-sideOffset}px`; | ||
} else { | ||
x = side === 'left' ? `${popperSize.width + sideOffset}px` : `${-sideOffset}px`; | ||
y = ({ | ||
start: `${alignOffset}px`, | ||
center: 'center', | ||
end: `${popperSize.height - alignOffset}px` | ||
})[align]; | ||
} | ||
return `${x} ${y}`; | ||
} | ||
const $dcd28e347ddb21ab$var$UNMEASURED_POPPER_STYLES = { | ||
// position: 'fixed' here is important because it will take the popper | ||
// out of the flow so it does not disturb the position of the anchor | ||
position: 'fixed', | ||
top: 0, | ||
left: 0, | ||
opacity: 0, | ||
transform: 'translate3d(0, -200%, 0)' | ||
}; | ||
const $dcd28e347ddb21ab$var$UNMEASURED_ARROW_STYLES = { | ||
// given the arrow is nested inside the popper, | ||
// make sure that it is out of the flow and doesn't hinder then popper's measurement | ||
position: 'absolute', | ||
opacity: 0 | ||
}; | ||
/** | ||
* Computes the styles necessary to position, rotate and align the arrow correctly. | ||
* It can adjust itself based on anchor/popper size, side/align and an optional offset. | ||
*/ function $dcd28e347ddb21ab$var$getPopperArrowStyles({ popperSize: popperSize , arrowSize: arrowSize , arrowOffset: arrowOffset , side: side , align: align }) { | ||
const popperCenterX = (popperSize.width - arrowSize.width) / 2; | ||
const popperCenterY = (popperSize.height - arrowSize.width) / 2; | ||
const rotationMap = { | ||
top: 0, | ||
right: 90, | ||
bottom: 180, | ||
left: -90 | ||
}; | ||
const rotation = rotationMap[side]; | ||
const arrowMaxDimension = Math.max(arrowSize.width, arrowSize.height); | ||
const styles = { | ||
// we make sure we put the arrow inside a 1:1 ratio container | ||
// this is to make the rotation handling simpler | ||
// as we do no need to worry about changing the transform-origin | ||
width: `${arrowMaxDimension}px`, | ||
height: `${arrowMaxDimension}px`, | ||
// rotate the arrow appropriately | ||
transform: `rotate(${rotation}deg)`, | ||
willChange: 'transform', | ||
// position the arrow appropriately | ||
position: 'absolute', | ||
[side]: '100%', | ||
// Because the arrow gets rotated (see `transform above`) | ||
// and we are putting it inside a 1:1 ratio container | ||
// we need to adjust the CSS direction from `ltr` to `rtl` | ||
// in some circumstances | ||
direction: $dcd28e347ddb21ab$var$getArrowCssDirection(side, align) | ||
}; | ||
if (side === 'top' || side === 'bottom') { | ||
if (align === 'start') styles.left = `${arrowOffset}px`; | ||
if (align === 'center') styles.left = `${popperCenterX}px`; | ||
if (align === 'end') styles.right = `${arrowOffset}px`; | ||
} | ||
if (side === 'left' || side === 'right') { | ||
if (align === 'start') styles.top = `${arrowOffset}px`; | ||
if (align === 'center') styles.top = `${popperCenterY}px`; | ||
if (align === 'end') styles.bottom = `${arrowOffset}px`; | ||
} | ||
return styles; | ||
} | ||
/** | ||
* Adjusts the arrow's CSS direction (`ltr` / `rtl`) | ||
*/ function $dcd28e347ddb21ab$var$getArrowCssDirection(side, align) { | ||
if ((side === 'top' || side === 'right') && align === 'end') return 'rtl'; | ||
if ((side === 'bottom' || side === 'left') && align !== 'end') return 'rtl'; | ||
return 'ltr'; | ||
} | ||
/** | ||
* Gets the opposite side of a given side (ie. top => bottom, left => right, …) | ||
*/ function $dcd28e347ddb21ab$var$getOppositeSide(side) { | ||
const oppositeSides = { | ||
top: 'bottom', | ||
right: 'left', | ||
bottom: 'top', | ||
left: 'right' | ||
}; | ||
return oppositeSides[side]; | ||
} | ||
/** | ||
* Creates a new rect (`ClientRect`) based on a given one but contracted by | ||
* a given amout on each side. | ||
*/ function $dcd28e347ddb21ab$var$getContractedRect(rect, amount) { | ||
return DOMRect.fromRect({ | ||
width: rect.width - amount * 2, | ||
height: rect.height - amount * 2, | ||
x: rect.left + amount, | ||
y: rect.top + amount | ||
}); | ||
} | ||
/** | ||
* Gets collisions for each side of a rect (top, right, bottom, left) | ||
*/ function $dcd28e347ddb21ab$var$getCollisions(/** The rect to test collisions against */ rect, /** The rect which represents the boundaries for collision checks */ collisionBoundariesRect) { | ||
return { | ||
top: rect.top < collisionBoundariesRect.top, | ||
right: rect.right > collisionBoundariesRect.right, | ||
bottom: rect.bottom > collisionBoundariesRect.bottom, | ||
left: rect.left < collisionBoundariesRect.left | ||
}; | ||
} | ||
export {$dcd28e347ddb21ab$export$d3e7649885811a7d as getPlacementData, $dcd28e347ddb21ab$export$36f0086da09c4b9f as SIDE_OPTIONS, $dcd28e347ddb21ab$export$3671ffab7b302fc9 as ALIGN_OPTIONS}; | ||
//# sourceMappingURL=index.module.js.map |
{ | ||
"name": "@radix-ui/popper", | ||
"version": "0.1.0", | ||
"version": "0.1.1-rc.1", | ||
"license": "MIT", | ||
@@ -29,3 +29,4 @@ "source": "src/index.ts", | ||
"url": "https://github.com/radix-ui/primitives/issues" | ||
} | ||
}, | ||
"stableVersion": "0.1.0" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
92560
723
2