@alliance-droid/status-feedback-system 1.3.6 → 1.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -70,13 +70,46 @@
|
|
|
70
70
|
|
|
71
71
|
let formOpen = $state(false);
|
|
72
72
|
let formPopoverEl: HTMLDivElement | undefined = $state();
|
|
73
|
+
let formOriginalParent: HTMLElement | null = null;
|
|
74
|
+
let formPortalTarget: HTMLElement | null = null;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Find the topmost open modal dialog.
|
|
78
|
+
* showModal() makes everything outside the dialog inert — including
|
|
79
|
+
* top-layer popovers that aren't descendants of the dialog.
|
|
80
|
+
*/
|
|
81
|
+
function findOpenModalDialog(): HTMLDialogElement | null {
|
|
82
|
+
const dialogs = document.querySelectorAll<HTMLDialogElement>('dialog[open]');
|
|
83
|
+
for (const d of dialogs) {
|
|
84
|
+
if (d.open) return d;
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
73
88
|
|
|
74
89
|
// Promote form modal to the browser's top layer when opened
|
|
90
|
+
// Portal into any open modal dialog to escape inertness
|
|
75
91
|
$effect(() => {
|
|
76
|
-
if (formOpen && formPopoverEl
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
92
|
+
if (formOpen && formPopoverEl) {
|
|
93
|
+
// Portal into modal dialog if one is open
|
|
94
|
+
const modalDialog = findOpenModalDialog();
|
|
95
|
+
if (modalDialog && formPopoverEl.parentElement !== modalDialog) {
|
|
96
|
+
formOriginalParent = formPopoverEl.parentElement;
|
|
97
|
+
formPortalTarget = modalDialog;
|
|
98
|
+
modalDialog.appendChild(formPopoverEl);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (typeof formPopoverEl.showPopover === 'function') {
|
|
102
|
+
try { formPopoverEl.showPopover(); } catch { /* fallback to z-index */ }
|
|
103
|
+
}
|
|
104
|
+
} else if (!formOpen && formPopoverEl) {
|
|
105
|
+
if (typeof formPopoverEl.hidePopover === 'function') {
|
|
106
|
+
try { formPopoverEl.hidePopover(); } catch { /* already hidden */ }
|
|
107
|
+
}
|
|
108
|
+
// Move back to original parent
|
|
109
|
+
if (formPortalTarget && formOriginalParent) {
|
|
110
|
+
try { formOriginalParent.appendChild(formPopoverEl); } catch { /* already moved */ }
|
|
111
|
+
formPortalTarget = null;
|
|
112
|
+
}
|
|
80
113
|
}
|
|
81
114
|
});
|
|
82
115
|
let formType = $state<'bug' | 'feature'>('bug');
|
|
@@ -8,18 +8,53 @@
|
|
|
8
8
|
onViewBoard?: () => void;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
import { onMount } from 'svelte';
|
|
11
|
+
import { onMount, onDestroy } from 'svelte';
|
|
12
12
|
|
|
13
13
|
let { x, y, boardUrl, onReportBug, onRequestFeature, onViewBoard }: Props = $props();
|
|
14
14
|
|
|
15
15
|
let popoverEl: HTMLDivElement | undefined = $state();
|
|
16
|
+
let originalParent: HTMLElement | null = null;
|
|
17
|
+
let portalTarget: HTMLElement | null = null;
|
|
16
18
|
|
|
17
19
|
let adjustedX = $derived(Math.min(x, (typeof window !== 'undefined' ? window.innerWidth : 800) - 200));
|
|
18
20
|
let adjustedY = $derived(Math.min(y, (typeof window !== 'undefined' ? window.innerHeight : 600) - 160));
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Find the topmost open modal dialog.
|
|
24
|
+
* showModal() makes everything outside the dialog inert — including
|
|
25
|
+
* top-layer popovers that aren't descendants of the dialog.
|
|
26
|
+
* By portalling into the dialog, our menu becomes a descendant and
|
|
27
|
+
* escapes the inertness.
|
|
28
|
+
*/
|
|
29
|
+
function findOpenModalDialog(): HTMLDialogElement | null {
|
|
30
|
+
const dialogs = document.querySelectorAll<HTMLDialogElement>('dialog[open]');
|
|
31
|
+
// showModal() sets the `modal` property — filter for true modals
|
|
32
|
+
for (const d of dialogs) {
|
|
33
|
+
// A dialog opened with showModal() will have a non-null ::backdrop
|
|
34
|
+
// and will be in the top layer. We can detect this via the "open"
|
|
35
|
+
// attribute + checking if it has modal behavior (no direct API,
|
|
36
|
+
// but modal dialogs block interaction with the rest of the page).
|
|
37
|
+
// The simplest reliable check: modal dialogs have returnValue capability
|
|
38
|
+
// and are in the top layer. In practice, all open dialogs we care about
|
|
39
|
+
// are modal since our Modal component always uses showModal().
|
|
40
|
+
if (d.open) return d;
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
21
45
|
onMount(() => {
|
|
22
|
-
if (popoverEl
|
|
46
|
+
if (!popoverEl) return;
|
|
47
|
+
|
|
48
|
+
// If a modal dialog is open, portal into it to escape inertness
|
|
49
|
+
const modalDialog = findOpenModalDialog();
|
|
50
|
+
if (modalDialog) {
|
|
51
|
+
originalParent = popoverEl.parentElement;
|
|
52
|
+
portalTarget = modalDialog;
|
|
53
|
+
modalDialog.appendChild(popoverEl);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Show the popover to promote it to the top layer
|
|
57
|
+
if (typeof popoverEl.showPopover === 'function') {
|
|
23
58
|
try {
|
|
24
59
|
popoverEl.showPopover();
|
|
25
60
|
} catch {
|
|
@@ -28,6 +63,20 @@
|
|
|
28
63
|
}
|
|
29
64
|
});
|
|
30
65
|
|
|
66
|
+
onDestroy(() => {
|
|
67
|
+
// Move the element back before Svelte tries to clean up
|
|
68
|
+
if (popoverEl && portalTarget && originalParent) {
|
|
69
|
+
try {
|
|
70
|
+
if (typeof popoverEl.hidePopover === 'function') {
|
|
71
|
+
popoverEl.hidePopover();
|
|
72
|
+
}
|
|
73
|
+
originalParent.appendChild(popoverEl);
|
|
74
|
+
} catch {
|
|
75
|
+
// Element may already be removed
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
31
80
|
function handleKeydown(e: KeyboardEvent) {
|
|
32
81
|
const menu = (e.currentTarget as HTMLElement);
|
|
33
82
|
const items = menu.querySelectorAll<HTMLElement>('[role="menuitem"]');
|
package/package.json
CHANGED