File size: 5,522 Bytes
b8874fd f86a242 b8874fd 9d9dd89 f86a242 8480986 9d9dd89 8480986 9d9dd89 d6b7277 9d9dd89 b8874fd 9d9dd89 b8874fd 9d9dd89 b8874fd f86a242 9d9dd89 f86a242 9d9dd89 b8874fd f86a242 9d9dd89 b8874fd f86a242 9d9dd89 f86a242 9d9dd89 f86a242 8480986 f86a242 68ab4bd f86a242 68ab4bd f86a242 68ab4bd f86a242 68ab4bd f86a242 68ab4bd f86a242 68ab4bd f86a242 68ab4bd 8e19ba1 f86a242 8e19ba1 f86a242 8e19ba1 f86a242 8e19ba1 f86a242 8e19ba1 f86a242 68ab4bd 9d9dd89 b8874fd d6b7277 b8874fd 9d9dd89 b8874fd 9d9dd89 f86a242 b8874fd 9d9dd89 b8874fd 9d9dd89 b8874fd 9d9dd89 b8874fd 9d9dd89 b8874fd 9d9dd89 b8874fd 9d9dd89 b8874fd 9d9dd89 b8874fd d6b7277 9d9dd89 b8874fd 9d9dd89 d6b7277 9d9dd89 b8874fd 9d9dd89 b8874fd 9d9dd89 b8874fd |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
import { bringInView } from "./utils";
import { STAGE_PADDING } from "./stage";
export type Side = "top" | "right" | "bottom" | "left";
export type Alignment = "start" | "center" | "end";
const POPOVER_OFFSET = 10;
export type Popover = {
title?: string;
description: string;
side?: Side;
align?: Alignment;
};
type PopoverDOM = {
wrapper: HTMLElement;
arrow: HTMLElement;
title: HTMLElement;
description: HTMLElement;
footer: HTMLElement;
previousButton: HTMLElement;
nextButton: HTMLElement;
closeButton: HTMLElement;
footerButtons: HTMLElement;
};
let popover: PopoverDOM | undefined;
export function renderPopover(element: Element) {
if (!popover) {
popover = createPopover();
document.body.appendChild(popover.wrapper);
}
// Reset the popover position
const popoverWrapper = popover.wrapper;
popoverWrapper.style.display = "block";
popoverWrapper.style.left = "";
popoverWrapper.style.top = "";
popoverWrapper.style.bottom = "";
popoverWrapper.style.right = "";
// Reset the classes responsible for the arrow position
const popoverArrow = popover.arrow;
popoverArrow.className = "driver-popover-arrow";
repositionPopover(element);
bringInView(popoverWrapper);
}
function getPopoverDimensions() {
if (!popover?.wrapper) {
return;
}
const boundingClientRect = popover.wrapper.getBoundingClientRect();
return {
width: boundingClientRect.width + STAGE_PADDING + POPOVER_OFFSET,
height: boundingClientRect.height + STAGE_PADDING + POPOVER_OFFSET,
realWidth: boundingClientRect.width,
realHeight: boundingClientRect.height,
};
}
export function repositionPopover(element: Element) {
if (!popover) {
return;
}
const requiredAlignment: Alignment = "start";
const popoverPadding = STAGE_PADDING;
const popoverDimensions = getPopoverDimensions();
const popoverArrowDimensions = popover.arrow.getBoundingClientRect();
const elementDimensions = element.getBoundingClientRect();
const topValue = elementDimensions.top - popoverDimensions!.height;
const isTopOptimal = topValue >= 0;
const bottomValue = window.innerHeight - (elementDimensions.bottom + popoverDimensions!.height);
const isBottomOptimal = bottomValue >= 0;
const leftValue = elementDimensions.left - popoverDimensions!.width;
const isLeftOptimal = leftValue >= 0;
const rightValue = window.innerWidth - (elementDimensions.right + popoverDimensions!.width);
const isRightOptimal = rightValue >= 0;
const noneOptimal = !isTopOptimal && !isBottomOptimal && !isLeftOptimal && !isRightOptimal;
if (noneOptimal) {
const leftValue = window.innerWidth / 2 - popoverDimensions?.realWidth! / 2;
const bottomValue = 10;
popover.wrapper.style.left = `${leftValue}px`;
popover.wrapper.style.right = `auto`;
popover.wrapper.style.bottom = `${bottomValue}px`;
popover.wrapper.style.top = `auto`;
popover.arrow.classList.add("driver-popover-arrow-none");
return;
}
if (isTopOptimal) {
const topToSet = Math.min(topValue, window.innerHeight - popoverDimensions.height - popoverArrowDimensions.width);
let leftToSet = 0;
if (requiredAlignment === "start") {
leftToSet = Math.max(
Math.min(
elementDimensions.left - popoverPadding,
window.innerWidth - popoverDimensions.width - popoverArrowDimensions.width
),
popoverArrowDimensions.width
);
}
// popover.arrow.classList.add("driver-popover-arrow-bottom");
popover.wrapper.style.top = `${topToSet}px`;
popover.wrapper.style.left = `${leftToSet}px`;
popover.wrapper.style.bottom = `auto`;
popover.wrapper.style.right = "auto";
}
}
function createPopover(): PopoverDOM {
const wrapper = document.createElement("div");
wrapper.classList.add("driver-popover");
const arrow = document.createElement("div");
arrow.classList.add("driver-popover-arrow");
const title = document.createElement("div");
title.classList.add("driver-popover-title");
title.innerText = "Popover Title";
const description = document.createElement("div");
description.classList.add("driver-popover-description");
description.innerText = "Popover description is here";
const footer = document.createElement("div");
footer.classList.add("driver-popover-footer");
const closeButton = document.createElement("button");
closeButton.classList.add("driver-popover-close-btn");
closeButton.innerText = "Close";
const footerButtons = document.createElement("span");
footerButtons.classList.add("driver-popover-footer-btns");
const previousButton = document.createElement("button");
previousButton.classList.add("driver-popover-prev-btn");
previousButton.innerHTML = "← Previous";
const nextButton = document.createElement("button");
nextButton.classList.add("driver-popover-next-btn");
nextButton.innerHTML = "Next →";
footerButtons.appendChild(previousButton);
footerButtons.appendChild(nextButton);
footer.appendChild(closeButton);
footer.appendChild(footerButtons);
wrapper.appendChild(arrow);
wrapper.appendChild(title);
wrapper.appendChild(description);
wrapper.appendChild(footer);
return {
wrapper,
arrow,
title,
description,
footer,
previousButton,
nextButton,
closeButton,
footerButtons,
};
}
export function destroyPopover() {
if (!popover) {
return;
}
popover.wrapper.parentElement?.removeChild(popover.wrapper);
popover = undefined;
}
|