1616 *
1717 * Object able to project a bounding box 2D data to only one of its dimensions
1818 *
19- * @property {(subject: BoundingBox) => number } getPosition return the position of the subject
20- * @property {(subject: BoundingBox, position: number) => void } setPosition set the position of the subject to a given value
21- * @property {(subject: BoundingBox) => number } getSize return the size of the subject
22- * @property {(subject: BoundingBox, size: number) => void } setSize set the size of the subject to a given value
19+ * @template T
20+ *
21+ * @property {(subject: {left: T, top: T} | {x: T, y: T}) => T } getPosition return the position of the subject
22+ * @property {(subject: {left: T, top: T} | {x: T, y: T}, position: T) => void } setPosition set the position of the subject to a given value
23+ * @property {(subject: {width: T, height: T}) => t } getSize return the size of the subject
24+ * @property {(subject: {width: T, height: T}, size: T) => void } setSize set the size of the subject to a given value
2325 */
2426
2527/**
2628 * @type BoundingBoxProjector
2729 */
2830const verticalProjector = Object . freeze ( {
29- getPosition : ( subject ) => subject . top ,
31+ getPosition : ( subject ) => 'top' in subject ? subject . top : subject . y ,
3032
3133 setPosition : ( subject , position ) => {
32- subject . top = position ;
34+ if ( 'top' in subject ) {
35+ subject . top = position ;
36+ } else {
37+ subject . y = position ;
38+ }
3339 } ,
3440
3541 getSize : ( subject ) => subject . height ,
@@ -43,10 +49,14 @@ const verticalProjector = Object.freeze({
4349 * @type BoundingBoxProjector
4450 */
4551const horizontalProjector = Object . freeze ( {
46- getPosition : ( subject ) => subject . left ,
52+ getPosition : ( subject ) => 'left' in subject ? subject . left : subject . x ,
4753
4854 setPosition : ( subject , position ) => {
49- subject . left = position ;
55+ if ( 'left' in subject ) {
56+ subject . left = position ;
57+ } else {
58+ subject . y = position ;
59+ }
5060 } ,
5161
5262 getSize : ( subject ) => subject . width ,
@@ -129,32 +139,31 @@ class PopoverEngine {
129139 * @param {HTMLElement } trigger the bounding box of the trigger
130140 * @param {HTMLElement } popover the bounding box of the popover
131141 * @param {BoundingBox } displayBoundingBox the bounding box of the display zone, representing the limits where the popover may be drawn
132- * @param {MainAxisPopoverPosition } mainAxisPosition the position of the popover along the main axis
133- * @param {BoundingBoxProjector } mainAxisProjector the main axis projector
134- * @param {CrossAxisPopoverPosition } crossAxisPosition the position of the popover along the cross axis
135- * @param {BoundingBoxProjector } crossAxisProjector the cross axis projector
142+ * @param {{x: number, y: number} } displayZoneMargins the margins to apply at the edge of the display zone
143+ * @param {{main: MainAxisPopoverPosition, cross: CrossAxisPopoverPosition} } position the position of the popover relative to the trigger
144+ * @param {{main: BoundingBoxProjector, cross: BoundingBoxProjector} } projectors the axis projectors
136145 */
137146 constructor (
138147 trigger ,
139148 popover ,
140149 displayBoundingBox ,
141- mainAxisPosition ,
142- mainAxisProjector ,
143- crossAxisPosition ,
144- crossAxisProjector ,
150+ displayZoneMargins ,
151+ position ,
152+ projectors ,
145153 ) {
146154 this . _popover = popover ;
147155
148156 this . _triggerBoundingBox = trigger . getBoundingClientRect ( ) ;
149157 this . _popoverBoundingBox = popover . getBoundingClientRect ( ) ;
150158
151- this . _mainAxisProjector = mainAxisProjector ;
152- this . _crossAxisProjector = crossAxisProjector ;
159+ this . _mainAxisPosition = position . main ;
160+ this . _crossAxisPosition = position . cross ;
153161
154- this . _mainAxisPosition = mainAxisPosition ;
155- this . _crossAxisPosition = crossAxisPosition ;
162+ this . _mainAxisProjector = projectors . main ;
163+ this . _crossAxisProjector = projectors . cross ;
156164
157165 this . _displayBoundingBox = displayBoundingBox ;
166+ this . _displayZoneMargins = displayZoneMargins ;
158167 }
159168
160169 /**
@@ -245,7 +254,7 @@ class PopoverEngine {
245254 mainAxisPosition = this . _triggerEndMainAxis ;
246255 }
247256
248- // Popover is placed absolutely relatively to the document, and its position should be offseted by the window scroll
257+ // Popover is placed absolutely relatively to the document, and its position should be offset by the window scroll
249258 mainAxisPosition += this . _mainAxisProjector . getPosition ( this . _offsets ) ;
250259
251260 this . _mainAxisProjector . setPosition ( this . _popover . style , `${ mainAxisPosition } px` ) ;
@@ -270,7 +279,8 @@ class PopoverEngine {
270279 targetStartCrossAxis += this . _crossAxisProjector . getPosition ( this . _offsets ) ;
271280
272281 const crossAxisPosition = Math . max (
273- 0 ,
282+ this . _crossAxisProjector . getPosition ( this . _displayBoundingBox )
283+ + this . _crossAxisProjector . getPosition ( this . _displayZoneMargins ) ,
274284 Math . min (
275285 this . _availableSpaceInCrossAxis - this . _popoverSizeCrossAxis ,
276286 targetStartCrossAxis ,
@@ -296,7 +306,8 @@ class PopoverEngine {
296306 * @private
297307 */
298308 get _availableSpaceInMainAxis ( ) {
299- return this . _mainAxisProjector . getSize ( this . _displayBoundingBox ) ;
309+ return this . _mainAxisProjector . getSize ( this . _displayBoundingBox )
310+ - this . _mainAxisProjector . getPosition ( this . _displayZoneMargins ) ;
300311 }
301312
302313 /**
@@ -306,7 +317,8 @@ class PopoverEngine {
306317 * @private
307318 */
308319 get _availableSpaceInCrossAxis ( ) {
309- return this . _crossAxisProjector . getSize ( this . _displayBoundingBox ) ;
320+ return this . _crossAxisProjector . getSize ( this . _displayBoundingBox )
321+ - this . _crossAxisProjector . getPosition ( this . _displayZoneMargins ) * 2 ;
310322 }
311323
312324 /**
@@ -406,10 +418,11 @@ class PopoverEngine {
406418 * @param {HTMLElement } trigger the bounding box of the trigger
407419 * @param {HTMLElement } popover the bounding box of the popover
408420 * @param {BoundingBox } displayBoundingBox the bounding box of the display zone, representing the limits where the popover may be drawn
421+ * @param {{x: number, y: number} } displayZoneMargins the margins to apply at the edge of the display zone
409422 * @param {PopoverAnchor } anchor the anchor to place the popover
410423 * @return {PopoverEngine } the created popover engine
411424 */
412- export const createPopoverEngine = ( trigger , popover , displayBoundingBox , anchor ) => {
425+ export const createPopoverEngine = ( trigger , popover , displayBoundingBox , displayZoneMargins , anchor ) => {
413426 // Top and Bottom are the 6 first anchors
414427 const mainAxisProjector = anchor / 6 < 1 ? verticalProjector : horizontalProjector ;
415428 const crossAxisProjector = anchor / 6 < 1 ? horizontalProjector : verticalProjector ;
@@ -424,9 +437,8 @@ export const createPopoverEngine = (trigger, popover, displayBoundingBox, anchor
424437 trigger ,
425438 popover ,
426439 displayBoundingBox ,
427- mainAxisPosition ,
428- mainAxisProjector ,
429- crossAxisPosition ,
430- crossAxisProjector ,
440+ displayZoneMargins ,
441+ { main : mainAxisPosition , cross : crossAxisPosition } ,
442+ { main : mainAxisProjector , cross : crossAxisProjector } ,
431443 ) ;
432444} ;
0 commit comments