mirror of
https://github.com/sbuffkin/hexmaker.git
synced 2026-07-22 14:30:24 +00:00
fix: pin HexEditorModal to viewport on open (1.2.3)
makeDraggable previously used position: absolute with top/left 50%, which relies on the nearest positioned ancestor being .modal-container. Any plugin or theme that establishes a CSS containing block on an ancestor (via transform/will-change/filter/contain) silently re-roots the modal against that inner element, so it opens partway off-screen — as reported in hexmaker#26. Switch to position: fixed and compute the centered top/left in JS against window.innerWidth/innerHeight, clamped 8px inside the viewport. position: fixed bypasses most ancestor-containing-block issues; the JS clamp catches the remaining edge cases (transformed ancestors that also hijack fixed positioning). Drag listeners now bind to modalEl.ownerDocument so dragging works correctly inside popout windows.
This commit is contained in:
parent
ce869324fc
commit
d12cf38ceb
5 changed files with 35 additions and 17 deletions
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "hexmaker",
|
||||
"name": "Hexmap World Creator",
|
||||
"version": "1.2.2",
|
||||
"version": "1.2.3",
|
||||
"minAppVersion": "1.12.0",
|
||||
"description": "Create a hex map and a guidebook level wiki for your setting with minimal fuss. Hex crawl worldbuilding toolbox. System agnostic, ready for any TRPG you care to run in it.",
|
||||
"author": "morkdev",
|
||||
|
|
|
|||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "hexmaker-plugin",
|
||||
"version": "1.2.2",
|
||||
"version": "1.2.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "hexmaker-plugin",
|
||||
"version": "1.2.2",
|
||||
"version": "1.2.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minisearch": "^7.2.0"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "hexmaker-plugin",
|
||||
"version": "1.2.2",
|
||||
"version": "1.2.3",
|
||||
"description": "A plugin to power hex crawl worldbuilding and running.",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -12,13 +12,30 @@ export class HexmakerModal extends Modal {
|
|||
if (modalEl.dataset.draggable) return;
|
||||
modalEl.dataset.draggable = "1";
|
||||
modalEl.addClass("duckmage-editor-modal-drag");
|
||||
modalEl.setCssProps({
|
||||
position: 'absolute',
|
||||
left: '50%',
|
||||
top: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
margin: '0',
|
||||
});
|
||||
|
||||
// position: fixed so the containing block is the viewport rather than
|
||||
// the nearest transform/filter/will-change ancestor. Other plugins or
|
||||
// themes can establish a containing block on a `.modal-container` ancestor
|
||||
// (issue #26 — a third-party plugin re-rooted position:absolute away from
|
||||
// the viewport, landing the modal partway off-screen).
|
||||
modalEl.setCssProps({ position: 'fixed', margin: '0' });
|
||||
|
||||
const doc = modalEl.ownerDocument;
|
||||
const win = doc.defaultView ?? window;
|
||||
|
||||
// Clamp the centered position so the modal can never open off-screen,
|
||||
// even if a transformed ancestor still establishes a containing block
|
||||
// for fixed positioning.
|
||||
const PADDING = 8;
|
||||
const centerInViewport = () => {
|
||||
const r = modalEl.getBoundingClientRect();
|
||||
const maxLeft = Math.max(PADDING, win.innerWidth - r.width - PADDING);
|
||||
const maxTop = Math.max(PADDING, win.innerHeight - r.height - PADDING);
|
||||
const left = Math.min(Math.max((win.innerWidth - r.width) / 2, PADDING), maxLeft);
|
||||
const top = Math.min(Math.max((win.innerHeight - r.height) / 2, PADDING), maxTop);
|
||||
modalEl.setCssProps({ left: `${left}px`, top: `${top}px` });
|
||||
};
|
||||
win.requestAnimationFrame(centerInViewport);
|
||||
|
||||
modalEl.addEventListener("mousedown", (e: MouseEvent) => {
|
||||
const modalContent = modalEl.querySelector<HTMLElement>(".modal-content");
|
||||
|
|
@ -27,18 +44,18 @@ export class HexmakerModal extends Modal {
|
|||
|
||||
e.preventDefault();
|
||||
const r = modalEl.getBoundingClientRect();
|
||||
modalEl.setCssProps({ transform: 'none', left: `${r.left}px`, top: `${r.top}px` });
|
||||
modalEl.setCssProps({ left: `${r.left}px`, top: `${r.top}px` });
|
||||
const sx = e.clientX, sy = e.clientY;
|
||||
const ox = r.left, oy = r.top;
|
||||
const onMove = (ev: MouseEvent) => {
|
||||
modalEl.setCssProps({ left: `${ox + ev.clientX - sx}px`, top: `${oy + ev.clientY - sy}px` });
|
||||
};
|
||||
const onUp = () => {
|
||||
activeDocument.removeEventListener("mousemove", onMove);
|
||||
activeDocument.removeEventListener("mouseup", onUp);
|
||||
doc.removeEventListener("mousemove", onMove);
|
||||
doc.removeEventListener("mouseup", onUp);
|
||||
};
|
||||
activeDocument.addEventListener("mousemove", onMove);
|
||||
activeDocument.addEventListener("mouseup", onUp);
|
||||
doc.addEventListener("mousemove", onMove);
|
||||
doc.addEventListener("mouseup", onUp);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,6 @@
|
|||
"1.1.15": "1.12.0",
|
||||
"1.2.0": "1.12.0",
|
||||
"1.2.1": "1.12.0",
|
||||
"1.2.2": "1.12.0"
|
||||
"1.2.2": "1.12.0",
|
||||
"1.2.3": "1.12.0"
|
||||
}
|
||||
Loading…
Reference in a new issue