Headless CMS and Content Managment Hub
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

243 lines
6.8 KiB

/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Types } from './types';
export type AnchorX =
'center' |
'left-to-right' |
'left-to-left' |
'right-to-left' |
'right-to-right';
export type AnchorY =
'bottom-to-bottom' |
'bottom-to-top' |
'center' |
'top-to-bottom' |
'top-to-top';
export type RelativePosition = SimplePosition | [AnchorX, AnchorY];
export type SimplePosition =
'bottom-center' |
'bottom-left' |
'bottom-right' |
'left-bottom' |
'left-center' |
'left-top' |
'right-bottom' |
'right-center' |
'right-top' |
'top-center' |
'top-left' |
'top-right';
export function computeAnchors(value: RelativePosition): [AnchorX, AnchorY] {
if (Types.isArray(value)) {
return value;
}
switch (value) {
case 'bottom-center':
return ['center', 'top-to-bottom'];
case 'bottom-left':
return ['left-to-left', 'top-to-bottom'];
case 'bottom-right':
return ['right-to-right', 'top-to-bottom'];
case 'left-bottom':
return ['right-to-left', 'bottom-to-bottom'];
case 'left-center':
return ['right-to-left', 'center'];
case 'left-top':
return ['right-to-left', 'top-to-top'];
case 'right-bottom':
return ['left-to-right', 'bottom-to-bottom'];
case 'right-center':
return ['left-to-right', 'center'];
case 'right-top':
return ['left-to-right', 'top-to-top'];
case 'top-center':
return ['center', 'bottom-to-top'];
case 'top-left':
return ['left-to-left', 'bottom-to-top'];
case 'top-right':
return ['right-to-right', 'bottom-to-top'];
default:
return ['center', 'center'];
}
}
export type PositionResult = {
height?: number;
maxHeight: number;
maxWidth: number;
width?: number;
x: number;
y: number;
};
export type PositionRequest = {
adjust?: boolean;
anchorX: AnchorX;
anchorY: AnchorY;
clientHeight: number;
clientWidth: number;
computeHeight?: boolean;
computeWidth?: boolean;
modalRect: DOMRect;
offsetX?: number;
offsetY?: number;
spaceX?: number;
spaceY?: number;
targetRect: DOMRect;
};
export function positionModal(request: PositionRequest): PositionResult {
const {
adjust,
anchorX,
anchorY,
clientHeight,
clientWidth,
computeHeight,
computeWidth,
modalRect,
offsetX,
offsetY,
spaceX,
spaceY,
targetRect,
} = request;
const actualOffsetX = offsetX || 0;
const actualOffsetY = offsetY || 0;
let height = 0;
let maxHeight = 0;
let maxWidth = 0;
let width = 0;
let x = 0;
let y = 0;
switch (anchorY) {
case 'center':
y = targetRect.top + targetRect.height * 0.5 - modalRect.height * 0.5;
break;
case 'top-to-top': {
y = targetRect.top + actualOffsetY;
break;
}
case 'top-to-bottom': {
y = targetRect.bottom + actualOffsetY;
maxHeight = clientHeight - y;
if (modalRect.height <= maxHeight) {
// Unset maxHeight if we have enough space.
maxHeight = 0;
} else if (adjust) {
// Find a position at the other side of the rect (top).
const candidate = targetRect.top - modalRect.height - actualOffsetY;
if (candidate > 0) {
y = candidate;
// Reset space to zero (full space), because we fix only if we have the space.
maxHeight = 0;
}
}
break;
}
case 'bottom-to-bottom': {
y = targetRect.bottom - modalRect.height - actualOffsetY;
break;
}
case 'bottom-to-top': {
y = targetRect.top - modalRect.height - actualOffsetY;
maxHeight = targetRect.top - actualOffsetY;
if (modalRect.height <= maxHeight) {
// Unset maxHeight if we have enough space.
maxHeight = 0;
} else if (adjust) {
// Find a position at the other side of the rect (bottom).
const candidate = targetRect.bottom + actualOffsetY;
if (candidate + modalRect.height < clientHeight) {
y = candidate;
// Reset space to zero (full space), because we fix only if we have the space.
maxHeight = 0;
}
}
break;
}
}
switch (anchorX) {
case 'center':
x = targetRect.left + targetRect.width * 0.5 - modalRect.width * 0.5;
break;
case 'left-to-left': {
x = targetRect.left + actualOffsetX;
break;
}
case 'left-to-right': {
x = targetRect.right + actualOffsetX;
maxWidth = clientWidth - x;
if (modalRect.width <= maxWidth) {
// Unset maxWidth if we have enough space.
maxWidth = 0;
} else if (adjust) {
// Find a position at the other side of the rect (left).
const candidate = targetRect.left - modalRect.width - actualOffsetX;
if (candidate > 0) {
x = candidate;
// Reset space to zero (full space), because we fix only if we have the space.
maxWidth = 0;
}
}
break;
}
case 'right-to-right': {
x = targetRect.right - modalRect.width - actualOffsetX;
break;
}
case 'right-to-left': {
x = targetRect.left - modalRect.width - actualOffsetX;
maxWidth = targetRect.left - actualOffsetX;
if (modalRect.width <= maxWidth) {
// Unset maxWidth if we have enough space.
maxWidth = 0;
} else if (adjust) {
// Find a position at the other side of the rect (right).
const candidate = targetRect.right + actualOffsetX;
if (candidate + modalRect.width < clientWidth) {
x = candidate;
// Reset space to zero (full space), because we fix only if we have the space.
maxWidth = 0;
}
}
break;
}
}
if (computeWidth) {
width = targetRect.width + 2 * (spaceX || 0);
}
if (computeHeight) {
height = targetRect.height + 2 * (spaceY || 0);
}
return { x, y, maxWidth, maxHeight, width, height };
}