mytril
Version:
Mytril Svelte library component for rapidly building modern websites based on Svelte and Sveltekit
149 lines (148 loc) • 7.13 kB
JavaScript
import { innerWidth, innerHeight } from 'svelte/reactivity/window';
export function getPositions() {
// state
const axis = $state({
x: 0,
y: 0,
location: null
});
return {
get values() {
return axis;
},
update(activator, element, location, centered, type, avoidCollisions) {
if (!activator || !element)
return;
const elementRect = element.getBoundingClientRect();
if (!(activator instanceof HTMLElement)) {
if (activator.clientX + elementRect.width > innerWidth.current) {
axis.x = activator.clientX - elementRect.width;
}
else {
axis.x = activator.clientX;
}
if (activator.clientY + elementRect.height > innerHeight.current) {
axis.y = activator.clientY - elementRect.height;
}
else {
axis.y = activator.clientY;
}
}
else if (activator instanceof HTMLElement) {
const activatorRect = activator.getBoundingClientRect();
const spacing = type === 'tooltip' ? 6 : 0;
const _activator = activatorRect.y + activatorRect.height;
const _element = elementRect.height + spacing;
if (location === 'top' || location === 'bottom') {
if (avoidCollisions) {
if (location === 'top') {
if (activatorRect.y - _element < 0) {
axis.y = activatorRect.bottom + spacing;
axis.location = 'bottom';
}
else {
axis.y = activatorRect.top - _element;
axis.location = 'top';
}
}
else {
if (_activator + _element > innerHeight.current) {
axis.y = activatorRect.top - _element;
axis.location = 'top';
}
else {
axis.y = activatorRect.bottom + spacing;
axis.location = 'bottom';
}
}
}
else {
if (location === 'top') {
axis.y = activatorRect.top - _element;
axis.location = 'top';
}
else {
axis.y = activatorRect.bottom + spacing;
axis.location = 'bottom';
}
}
if (centered &&
activatorRect.left - (elementRect.width - activatorRect.width) / 2 > 0 &&
activatorRect.left + elementRect.width < innerWidth.current) {
axis.x = activatorRect.left - (elementRect.width - activatorRect.width) / 2;
}
else if (activatorRect.left + elementRect.width > innerWidth.current) {
axis.x = activatorRect.left - (elementRect.width - activatorRect.width);
}
else {
axis.x = activatorRect.left;
}
}
else if (location === 'left' || location === 'right') {
if (avoidCollisions) {
if (location === 'left' && !(activatorRect.left - elementRect.width < 0)) {
axis.x = activatorRect.left - (elementRect.width + spacing);
axis.location = 'left';
}
else {
if (activatorRect.left + activatorRect.width + elementRect.width + spacing >
innerWidth.current) {
axis.x = activatorRect.left - (elementRect.width + spacing);
axis.location = 'left';
}
else {
axis.x = activatorRect.left + activatorRect.width + spacing;
axis.location = 'right';
}
}
}
else {
if (location === 'left') {
axis.x = activatorRect.left - (elementRect.width + spacing);
axis.location = 'left';
}
else {
axis.x = activatorRect.left + activatorRect.width + spacing;
axis.location = 'right';
}
}
if (centered &&
activatorRect.top - (elementRect.height - activatorRect.height) / 2 > 0 &&
activatorRect.top + elementRect.height < innerHeight.current) {
axis.y = activatorRect.top - (elementRect.height - activatorRect.height) / 2;
}
else if (activatorRect.y + elementRect.height > innerHeight.current) {
axis.y = activatorRect.y - elementRect.height + activatorRect.height;
}
else {
axis.y = activatorRect.y;
}
}
else {
if (centered &&
activatorRect.left - (elementRect.width - activatorRect.width) / 2 > 0 &&
activatorRect.left + elementRect.width < innerWidth.current) {
axis.x = activatorRect.left - (elementRect.width - activatorRect.width) / 2;
}
else if (activatorRect.left + elementRect.width > innerWidth.current) {
axis.x = activatorRect.left - (elementRect.width - activatorRect.width);
}
else {
axis.x = activatorRect.left;
}
if (centered &&
activatorRect.top - (elementRect.height - activatorRect.height) / 2 > 0 &&
activatorRect.top + elementRect.height < innerHeight.current) {
axis.y = activatorRect.top - (elementRect.height - activatorRect.height) / 2;
}
else if (activatorRect.bottom + elementRect.height > innerHeight.current) {
axis.y = activatorRect.top - elementRect.height;
}
else {
axis.y = activatorRect.bottom;
}
}
}
}
};
}