2021-10-06 09:53:27 +00:00
|
|
|
const LEFT_RIGHT_OFFSET = 25;
|
|
|
|
const TOP_BOTTOM_OFFSET = 20;
|
|
|
|
|
2022-09-21 08:32:50 +00:00
|
|
|
const getLeftAlignedStyle = (bounds: DOMRect) => {
|
2021-10-06 09:53:27 +00:00
|
|
|
return {
|
|
|
|
position: 'fixed',
|
|
|
|
right: `${window.innerWidth - bounds.x + LEFT_RIGHT_OFFSET}px`
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-09-21 08:32:50 +00:00
|
|
|
const getRightAlignedStyle = (bounds: DOMRect) => {
|
2021-10-06 09:53:27 +00:00
|
|
|
return {
|
|
|
|
position: 'fixed',
|
|
|
|
left: `${bounds.x + bounds.width + LEFT_RIGHT_OFFSET}px`
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-09-21 08:32:50 +00:00
|
|
|
const getTopAlignedStyle = (bounds: DOMRect) => {
|
2021-10-06 09:53:27 +00:00
|
|
|
return {
|
|
|
|
position: 'fixed',
|
|
|
|
bottom: `${window.innerHeight - bounds.y + TOP_BOTTOM_OFFSET}px`
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-09-21 08:32:50 +00:00
|
|
|
const getBottomAlignedStyle = (bounds: DOMRect) => {
|
2021-10-06 09:53:27 +00:00
|
|
|
return {
|
|
|
|
position: 'fixed',
|
|
|
|
top: `${bounds.y + bounds.height + TOP_BOTTOM_OFFSET}px`
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-09-21 08:32:50 +00:00
|
|
|
const getLeftRightStartAlign = (bounds: DOMRect, size: DOMRectReadOnly) => {
|
2021-10-06 09:53:27 +00:00
|
|
|
return {
|
|
|
|
top: `${Math.min(bounds.y + 15, window.innerHeight - size.height - 20)}px`
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-09-21 08:32:50 +00:00
|
|
|
const getLeftRightMidAlign = (bounds: DOMRect, size: DOMRectReadOnly) => {
|
2021-10-06 09:53:27 +00:00
|
|
|
return {
|
|
|
|
bottom: `${window.innerHeight - bounds.y - bounds.height - (size.height / 2)}px`
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-09-21 08:32:50 +00:00
|
|
|
const getLeftRightEndAlign = (bounds: DOMRect, size: DOMRectReadOnly) => {
|
2021-10-06 09:53:27 +00:00
|
|
|
return {
|
|
|
|
bottom: `${Math.min(window.innerHeight - bounds.y - bounds.height, window.innerHeight - size.height)}px`
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-09-21 08:32:50 +00:00
|
|
|
const getTopBotStartAlign = (bounds: DOMRect) => {
|
2021-10-06 09:53:27 +00:00
|
|
|
return {
|
|
|
|
right: `${window.innerWidth - bounds.x + 10}px`
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-09-21 08:32:50 +00:00
|
|
|
const getTopBotMidAlign = (bounds: DOMRect, size: DOMRectReadOnly) => {
|
2021-10-06 09:53:27 +00:00
|
|
|
return {
|
|
|
|
right: `${window.innerWidth - bounds.x - (size.width / 2)}px`
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-09-21 08:32:50 +00:00
|
|
|
const getTopBotEndAlign = (bounds: DOMRect) => {
|
2021-10-06 09:53:27 +00:00
|
|
|
return {
|
|
|
|
left: `${bounds.x + bounds.width + 10}px`
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the trigger element's and the context menu's bounds/size info and
|
|
|
|
* computes the style to apply to the context menu to positioning it correctly
|
|
|
|
* in regards to the given position info.
|
|
|
|
*
|
|
|
|
* @param {DOMRect} triggerBounds -The bounds info of the trigger html element.
|
|
|
|
* @param {DOMRectReadOnly} dialogSize - The size info of the context menu.
|
|
|
|
* @param {string} position - The position of the context menu in regards to the trigger element.
|
|
|
|
*
|
|
|
|
* @returns {Object} = The style to apply to context menu for positioning it correctly.
|
|
|
|
*/
|
|
|
|
export const getContextMenuStyle = (triggerBounds: DOMRect,
|
|
|
|
dialogSize: DOMRectReadOnly,
|
|
|
|
position: string) => {
|
|
|
|
const parsed = position.split('-');
|
|
|
|
|
|
|
|
switch (parsed[0]) {
|
|
|
|
case 'top': {
|
|
|
|
let alignmentStyle = {};
|
|
|
|
|
|
|
|
if (parsed[1]) {
|
|
|
|
alignmentStyle = parsed[1] === 'start'
|
|
|
|
? getTopBotStartAlign(triggerBounds)
|
|
|
|
: getTopBotEndAlign(triggerBounds);
|
|
|
|
} else {
|
|
|
|
alignmentStyle = getTopBotMidAlign(triggerBounds, dialogSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
...getTopAlignedStyle(triggerBounds),
|
|
|
|
...alignmentStyle
|
|
|
|
};
|
|
|
|
}
|
|
|
|
case 'bottom': {
|
|
|
|
let alignmentStyle = {};
|
|
|
|
|
|
|
|
if (parsed[1]) {
|
|
|
|
alignmentStyle = parsed[1] === 'start'
|
|
|
|
? getTopBotStartAlign(triggerBounds)
|
|
|
|
: getTopBotEndAlign(triggerBounds);
|
|
|
|
} else {
|
|
|
|
alignmentStyle = getTopBotMidAlign(triggerBounds, dialogSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
...getBottomAlignedStyle(triggerBounds),
|
|
|
|
...alignmentStyle
|
|
|
|
};
|
|
|
|
}
|
|
|
|
case 'left': {
|
|
|
|
let alignmentStyle = {};
|
|
|
|
|
|
|
|
if (parsed[1]) {
|
|
|
|
alignmentStyle = parsed[1] === 'start'
|
|
|
|
? getLeftRightStartAlign(triggerBounds, dialogSize)
|
|
|
|
: getLeftRightEndAlign(triggerBounds, dialogSize);
|
|
|
|
} else {
|
|
|
|
alignmentStyle = getLeftRightMidAlign(triggerBounds, dialogSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
...getLeftAlignedStyle(triggerBounds),
|
|
|
|
...alignmentStyle
|
|
|
|
};
|
|
|
|
}
|
|
|
|
case 'right': {
|
|
|
|
let alignmentStyle = {};
|
|
|
|
|
|
|
|
if (parsed[1]) {
|
|
|
|
alignmentStyle = parsed[1] === 'start'
|
|
|
|
? getLeftRightStartAlign(triggerBounds, dialogSize)
|
|
|
|
: getLeftRightEndAlign(triggerBounds, dialogSize);
|
|
|
|
} else {
|
|
|
|
alignmentStyle = getLeftRightMidAlign(triggerBounds, dialogSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
...getRightAlignedStyle(triggerBounds),
|
|
|
|
...alignmentStyle
|
|
|
|
};
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
return {
|
|
|
|
...getLeftAlignedStyle(triggerBounds),
|
|
|
|
...getLeftRightEndAlign(triggerBounds, dialogSize)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|