fix(mobile): move modals to document.body to escape panel DOM constraints
Fix mobile modal positioning by moving modals to document.body on first use. Root cause: Modals were nested inside .rpg-panel which has 'transform' in its transition property (line 40 of style.css). This creates a containing block that constrains position:fixed children to the panel viewport instead of the document viewport, causing modals to be cut off on mobile. Changes: 1. confirmDialog.js - Modified showConfirmDialog() and showAlertDialog(): - Check if modal is already in document.body container - Create 'document-body-modals' container at body level (once) - Move modal to body container to escape panel constraints - Container has pointer-events: none to pass clicks through - Individual modals have pointer-events: auto to receive clicks 2. style.css - Added pointer-events: auto to .rpg-modal: - Ensures clicks work when modal is in pointer-events: none container Result: - Modals now render over entire SillyTavern viewport - Properly centered with full z-index stacking - No longer constrained by panel's transform/stacking context - Works correctly on both desktop and mobile
This commit is contained in:
@@ -31,6 +31,28 @@ export function showConfirmDialog(options) {
|
|||||||
|
|
||||||
// Get modal elements
|
// Get modal elements
|
||||||
const modal = document.getElementById('rpg-confirm-dialog');
|
const modal = document.getElementById('rpg-confirm-dialog');
|
||||||
|
|
||||||
|
if (!modal) {
|
||||||
|
console.error('[ConfirmDialog] Modal not found');
|
||||||
|
return resolve(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CRITICAL: Move modal to document.body on first use to escape panel constraints
|
||||||
|
// The panel has transform in its transition which creates a containing block,
|
||||||
|
// constraining position:fixed children to the panel instead of viewport
|
||||||
|
if (modal.parentElement?.id !== 'document-body-modals') {
|
||||||
|
// Create container for modals at body level (only once)
|
||||||
|
let bodyModalsContainer = document.getElementById('document-body-modals');
|
||||||
|
if (!bodyModalsContainer) {
|
||||||
|
bodyModalsContainer = document.createElement('div');
|
||||||
|
bodyModalsContainer.id = 'document-body-modals';
|
||||||
|
bodyModalsContainer.style.cssText = 'position: fixed; inset: 0; pointer-events: none; z-index: 10000;';
|
||||||
|
document.body.appendChild(bodyModalsContainer);
|
||||||
|
}
|
||||||
|
bodyModalsContainer.appendChild(modal);
|
||||||
|
console.log('[ConfirmDialog] Moved modal to document.body to escape panel constraints');
|
||||||
|
}
|
||||||
|
|
||||||
const modalContent = modal.querySelector('.rpg-confirm-content');
|
const modalContent = modal.querySelector('.rpg-confirm-content');
|
||||||
const icon = document.getElementById('rpg-confirm-icon');
|
const icon = document.getElementById('rpg-confirm-icon');
|
||||||
const titleEl = document.getElementById('rpg-confirm-title');
|
const titleEl = document.getElementById('rpg-confirm-title');
|
||||||
@@ -39,11 +61,6 @@ export function showConfirmDialog(options) {
|
|||||||
const cancelBtn = document.getElementById('rpg-confirm-cancel');
|
const cancelBtn = document.getElementById('rpg-confirm-cancel');
|
||||||
const closeBtn = modal.querySelector('.rpg-confirm-close');
|
const closeBtn = modal.querySelector('.rpg-confirm-close');
|
||||||
|
|
||||||
if (!modal) {
|
|
||||||
console.error('[ConfirmDialog] Modal not found');
|
|
||||||
return resolve(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set icon based on variant
|
// Set icon based on variant
|
||||||
const iconMap = {
|
const iconMap = {
|
||||||
danger: 'fa-solid fa-triangle-exclamation',
|
danger: 'fa-solid fa-triangle-exclamation',
|
||||||
@@ -139,6 +156,28 @@ export function showAlertDialog(options) {
|
|||||||
|
|
||||||
// Get modal elements
|
// Get modal elements
|
||||||
const modal = document.getElementById('rpg-confirm-dialog');
|
const modal = document.getElementById('rpg-confirm-dialog');
|
||||||
|
|
||||||
|
if (!modal) {
|
||||||
|
console.error('[ConfirmDialog] Modal not found');
|
||||||
|
return resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
// CRITICAL: Move modal to document.body on first use to escape panel constraints
|
||||||
|
// The panel has transform in its transition which creates a containing block,
|
||||||
|
// constraining position:fixed children to the panel instead of viewport
|
||||||
|
if (modal.parentElement?.id !== 'document-body-modals') {
|
||||||
|
// Create container for modals at body level (only once)
|
||||||
|
let bodyModalsContainer = document.getElementById('document-body-modals');
|
||||||
|
if (!bodyModalsContainer) {
|
||||||
|
bodyModalsContainer = document.createElement('div');
|
||||||
|
bodyModalsContainer.id = 'document-body-modals';
|
||||||
|
bodyModalsContainer.style.cssText = 'position: fixed; inset: 0; pointer-events: none; z-index: 10000;';
|
||||||
|
document.body.appendChild(bodyModalsContainer);
|
||||||
|
}
|
||||||
|
bodyModalsContainer.appendChild(modal);
|
||||||
|
console.log('[ConfirmDialog] Moved modal to document.body to escape panel constraints');
|
||||||
|
}
|
||||||
|
|
||||||
const modalContent = modal.querySelector('.rpg-confirm-content');
|
const modalContent = modal.querySelector('.rpg-confirm-content');
|
||||||
const icon = document.getElementById('rpg-confirm-icon');
|
const icon = document.getElementById('rpg-confirm-icon');
|
||||||
const titleEl = document.getElementById('rpg-confirm-title');
|
const titleEl = document.getElementById('rpg-confirm-title');
|
||||||
@@ -147,11 +186,6 @@ export function showAlertDialog(options) {
|
|||||||
const cancelBtn = document.getElementById('rpg-confirm-cancel');
|
const cancelBtn = document.getElementById('rpg-confirm-cancel');
|
||||||
const closeBtn = modal.querySelector('.rpg-confirm-close');
|
const closeBtn = modal.querySelector('.rpg-confirm-close');
|
||||||
|
|
||||||
if (!modal) {
|
|
||||||
console.error('[ConfirmDialog] Modal not found');
|
|
||||||
return resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set icon based on variant
|
// Set icon based on variant
|
||||||
const iconMap = {
|
const iconMap = {
|
||||||
danger: 'fa-solid fa-triangle-exclamation',
|
danger: 'fa-solid fa-triangle-exclamation',
|
||||||
|
|||||||
@@ -1441,6 +1441,7 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 1rem; /* Ensure content doesn't touch screen edges on mobile */
|
padding: 1rem; /* Ensure content doesn't touch screen edges on mobile */
|
||||||
|
pointer-events: auto; /* Ensure clicks work when moved to body container */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Modal Content Container */
|
/* Modal Content Container */
|
||||||
|
|||||||
Reference in New Issue
Block a user