Force Paystack checkout into the sheet mount on first insert.
Deploy Ladill Events / deploy (push) Successful in 1m15s
Deploy Ladill Events / deploy (push) Successful in 1m15s
Redirect first iframe append into the Ladill sheet body and keep absolute fill styles applied so checkout is not a second full-screen modal.
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
- publicKey (string, optional) — unused by resumeTransaction; kept for callers
|
- publicKey (string, optional) — unused by resumeTransaction; kept for callers
|
||||||
- returnUrl (string, optional) — where to go after Inline onSuccess (?reference=)
|
- returnUrl (string, optional) — where to go after Inline onSuccess (?reference=)
|
||||||
|
|
||||||
Paystack checkout.paystack.com cannot be iframed (X-Frame-Options: SAMEORIGIN).
|
checkout.paystack.com cannot be iframed (X-Frame-Options: SAMEORIGIN).
|
||||||
Primary path: Paystack Inline JS (PaystackPop.resumeTransaction) — in-page overlay,
|
Primary path: Paystack Inline JS (PaystackPop.resumeTransaction) — in-page overlay,
|
||||||
not a separate browser tab. Same-origin URLs (e.g. MoMo waiting) still use iframe.
|
not a separate browser tab. Same-origin URLs (e.g. MoMo waiting) still use iframe.
|
||||||
--}}
|
--}}
|
||||||
@@ -148,14 +148,139 @@
|
|||||||
setPaystackContainActive(false);
|
setPaystackContainActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paystack Inline defaults to a full-viewport modal (body append + position:fixed).
|
// Paystack Inline always body-appends a full-viewport modal (position:fixed 100%).
|
||||||
// We contain it inside our bottomsheet/modal mount so checkout loads where the
|
// Strategy:
|
||||||
// spinner is — not as a second modal on top of Ladill chrome.
|
// 1) On FIRST append only, put checkout iframe into our sheet mount (no later reparent
|
||||||
|
// — reparent after load reloads the frame and breaks Paystack).
|
||||||
|
// 2) Force position:absolute + fill mount (fixed+100% always paints the whole viewport
|
||||||
|
// even when the node is nested under the sheet).
|
||||||
|
// 3) Continuously re-apply styles (Paystack rewrites style on open/animate).
|
||||||
|
// 4) Hide Paystack's own dimmer; Ladill sheet owns backdrop + chrome.
|
||||||
var PAYSTACK_IFRAME_ALLOW = 'payment *; fullscreen *; clipboard-read *; clipboard-write *; publickey-credentials-get *';
|
var PAYSTACK_IFRAME_ALLOW = 'payment *; fullscreen *; clipboard-read *; clipboard-write *; publickey-credentials-get *';
|
||||||
var PAYSTACK_ALLOW_FEATURES = ['payment', 'fullscreen', 'clipboard-read', 'clipboard-write', 'publickey-credentials-get'];
|
var PAYSTACK_ALLOW_FEATURES = ['payment', 'fullscreen', 'clipboard-read', 'clipboard-write', 'publickey-credentials-get'];
|
||||||
|
var activeMountEl = null;
|
||||||
|
var activeBodyEl = null;
|
||||||
|
var pinRafId = 0;
|
||||||
|
var lastPinRect = null;
|
||||||
|
var nativeAppendChild = Node.prototype.appendChild;
|
||||||
|
var nativeInsertBefore = Node.prototype.insertBefore;
|
||||||
|
|
||||||
|
function isElementShown(el) {
|
||||||
|
if (!el || el.nodeType !== 1) return false;
|
||||||
|
if (el.getAttribute && el.getAttribute('aria-hidden') === 'true') return false;
|
||||||
|
var p = el;
|
||||||
|
while (p && p.nodeType === 1) {
|
||||||
|
try {
|
||||||
|
var s = window.getComputedStyle(p);
|
||||||
|
if (s.display === 'none' || s.visibility === 'hidden') return false;
|
||||||
|
} catch (e) {}
|
||||||
|
p = p.parentElement;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveOpenSheet() {
|
||||||
|
var sheets = document.querySelectorAll('[data-ladill-pay-sheet]');
|
||||||
|
var fallback = null;
|
||||||
|
for (var i = 0; i < sheets.length; i++) {
|
||||||
|
var sheet = sheets[i];
|
||||||
|
if (!fallback) fallback = sheet;
|
||||||
|
if (sheet.getAttribute('aria-hidden') !== 'true') return sheet;
|
||||||
|
}
|
||||||
|
for (var j = 0; j < sheets.length; j++) {
|
||||||
|
if (isElementShown(sheets[j])) return sheets[j];
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolvePaystackMount() {
|
||||||
|
var sheet = resolveOpenSheet();
|
||||||
|
if (sheet) {
|
||||||
|
var mount = sheet.querySelector('[data-ladill-pay-mount]');
|
||||||
|
if (mount) return mount;
|
||||||
|
var body = sheet.querySelector('[data-ladill-pay-body]');
|
||||||
|
if (body) return body;
|
||||||
|
}
|
||||||
|
return document.querySelector('[data-ladill-pay-mount]')
|
||||||
|
|| document.querySelector('[data-ladill-pay-body]');
|
||||||
|
}
|
||||||
|
|
||||||
function getPaystackMount() {
|
function getPaystackMount() {
|
||||||
return document.querySelector('[data-ladill-pay-mount]');
|
if (activeMountEl && activeMountEl.isConnected) return activeMountEl;
|
||||||
|
return resolvePaystackMount();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPaystackBody() {
|
||||||
|
if (activeBodyEl && activeBodyEl.isConnected) return activeBodyEl;
|
||||||
|
var mount = getPaystackMount();
|
||||||
|
if (mount) {
|
||||||
|
var body = mount.closest('[data-ladill-pay-body]');
|
||||||
|
if (body) return body;
|
||||||
|
}
|
||||||
|
var sheet = resolveOpenSheet();
|
||||||
|
return sheet ? sheet.querySelector('[data-ladill-pay-body]') : document.querySelector('[data-ladill-pay-body]');
|
||||||
|
}
|
||||||
|
|
||||||
|
function armPaystackMount() {
|
||||||
|
var sheet = resolveOpenSheet();
|
||||||
|
activeMountEl = sheet
|
||||||
|
? (sheet.querySelector('[data-ladill-pay-mount]') || sheet.querySelector('[data-ladill-pay-body]'))
|
||||||
|
: resolvePaystackMount();
|
||||||
|
activeBodyEl = sheet
|
||||||
|
? sheet.querySelector('[data-ladill-pay-body]')
|
||||||
|
: getPaystackBody();
|
||||||
|
// Keep the mount measurable while we pin (Alpine x-show can set display:none).
|
||||||
|
try {
|
||||||
|
if (activeMountEl) {
|
||||||
|
activeMountEl.style.setProperty('display', 'block', 'important');
|
||||||
|
activeMountEl.style.setProperty('visibility', 'visible', 'important');
|
||||||
|
activeMountEl.style.setProperty('pointer-events', 'none', 'important');
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
return activeMountEl;
|
||||||
|
}
|
||||||
|
|
||||||
|
function measurePinTarget() {
|
||||||
|
var el = getPaystackMount() || getPaystackBody();
|
||||||
|
if (!el) return null;
|
||||||
|
var rect = el.getBoundingClientRect();
|
||||||
|
if (rect.width >= 40 && rect.height >= 40) {
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
// Mount may still be display:none — fall back to the white body panel.
|
||||||
|
var body = getPaystackBody();
|
||||||
|
if (body && body !== el) {
|
||||||
|
rect = body.getBoundingClientRect();
|
||||||
|
if (rect.width >= 40 && rect.height >= 40) return rect;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function waitForPinTarget(timeoutMs) {
|
||||||
|
timeoutMs = timeoutMs || 1200;
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
var start = Date.now();
|
||||||
|
var tick = function () {
|
||||||
|
armPaystackMount();
|
||||||
|
var rect = measurePinTarget();
|
||||||
|
if (rect) {
|
||||||
|
syncPaystackMountBox();
|
||||||
|
resolve(rect);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Date.now() - start >= timeoutMs) {
|
||||||
|
syncPaystackMountBox();
|
||||||
|
resolve(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof requestAnimationFrame === 'function') {
|
||||||
|
requestAnimationFrame(tick);
|
||||||
|
} else {
|
||||||
|
setTimeout(tick, 16);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
tick();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPaystackCheckoutFrame(iframe) {
|
function isPaystackCheckoutFrame(iframe) {
|
||||||
@@ -213,12 +338,46 @@
|
|||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function styleContainedCheckout(iframe) {
|
function isCheckoutFrame(iframe) {
|
||||||
|
if (!iframe || !iframe.tagName || iframe.tagName.toUpperCase() !== 'IFRAME') return false;
|
||||||
|
var id = (iframe.id || '');
|
||||||
|
return id.indexOf('inline-checkout') === 0
|
||||||
|
|| id.indexOf('embed-checkout') === 0
|
||||||
|
|| iframe.hasAttribute('data-ladill-pay-contained');
|
||||||
|
}
|
||||||
|
|
||||||
|
function styleMountAsContainer(mount) {
|
||||||
|
if (!mount) return;
|
||||||
|
try {
|
||||||
|
// Create a fixed containing block so position:fixed descendants still
|
||||||
|
// cannot escape to the viewport (transform + isolation).
|
||||||
|
var s = mount.style;
|
||||||
|
s.setProperty('position', 'absolute', 'important');
|
||||||
|
s.setProperty('inset', '0', 'important');
|
||||||
|
s.setProperty('left', '0', 'important');
|
||||||
|
s.setProperty('top', '0', 'important');
|
||||||
|
s.setProperty('right', '0', 'important');
|
||||||
|
s.setProperty('bottom', '0', 'important');
|
||||||
|
s.setProperty('width', '100%', 'important');
|
||||||
|
s.setProperty('height', '100%', 'important');
|
||||||
|
s.setProperty('overflow', 'hidden', 'important');
|
||||||
|
s.setProperty('display', 'block', 'important');
|
||||||
|
s.setProperty('visibility', 'visible', 'important');
|
||||||
|
s.setProperty('background', '#fff', 'important');
|
||||||
|
s.setProperty('transform', 'translateZ(0)', 'important');
|
||||||
|
s.setProperty('isolation', 'isolate', 'important');
|
||||||
|
s.setProperty('contain', 'layout size', 'important');
|
||||||
|
s.setProperty('z-index', '1', 'important');
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function styleCheckoutInMount(iframe) {
|
||||||
if (!iframe) return;
|
if (!iframe) return;
|
||||||
try {
|
try {
|
||||||
iframe.setAttribute('data-ladill-pay-contained', '1');
|
iframe.setAttribute('data-ladill-pay-contained', '1');
|
||||||
// Force embed layout; Paystack sets position:fixed inline without !important.
|
iframe.setAttribute('data-ladill-pay-mode', 'mount');
|
||||||
var s = iframe.style;
|
var s = iframe.style;
|
||||||
|
// Absolute fill of mount — NOT position:fixed 100% (that always paints viewport).
|
||||||
s.setProperty('position', 'absolute', 'important');
|
s.setProperty('position', 'absolute', 'important');
|
||||||
s.setProperty('left', '0', 'important');
|
s.setProperty('left', '0', 'important');
|
||||||
s.setProperty('top', '0', 'important');
|
s.setProperty('top', '0', 'important');
|
||||||
@@ -226,20 +385,81 @@
|
|||||||
s.setProperty('bottom', '0', 'important');
|
s.setProperty('bottom', '0', 'important');
|
||||||
s.setProperty('width', '100%', 'important');
|
s.setProperty('width', '100%', 'important');
|
||||||
s.setProperty('height', '100%', 'important');
|
s.setProperty('height', '100%', 'important');
|
||||||
|
s.setProperty('max-width', 'none', 'important');
|
||||||
|
s.setProperty('max-height', 'none', 'important');
|
||||||
s.setProperty('margin', '0', 'important');
|
s.setProperty('margin', '0', 'important');
|
||||||
s.setProperty('padding', '0', 'important');
|
s.setProperty('padding', '0', 'important');
|
||||||
s.setProperty('border', '0', 'important');
|
s.setProperty('border', '0', 'important');
|
||||||
|
s.setProperty('border-radius', '0', 'important');
|
||||||
s.setProperty('z-index', '2', 'important');
|
s.setProperty('z-index', '2', 'important');
|
||||||
s.setProperty('visibility', 'visible', 'important');
|
s.setProperty('visibility', 'visible', 'important');
|
||||||
s.setProperty('display', 'block', 'important');
|
s.setProperty('display', 'block', 'important');
|
||||||
s.setProperty('background', 'transparent', 'important');
|
s.setProperty('opacity', '1', 'important');
|
||||||
s.setProperty('background-color', 'transparent', 'important');
|
s.setProperty('background', '#fff', 'important');
|
||||||
s.setProperty('max-width', 'none', 'important');
|
s.setProperty('background-color', '#fff', 'important');
|
||||||
s.setProperty('max-height', 'none', 'important');
|
s.setProperty('pointer-events', 'auto', 'important');
|
||||||
|
s.setProperty('color-scheme', 'light', 'important');
|
||||||
|
s.setProperty('transform', 'none', 'important');
|
||||||
applyIframePermissions(iframe);
|
applyIframePermissions(iframe);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function styleCheckoutPinnedToRect(iframe, rect) {
|
||||||
|
if (!iframe || !rect) return;
|
||||||
|
try {
|
||||||
|
iframe.setAttribute('data-ladill-pay-contained', '1');
|
||||||
|
iframe.setAttribute('data-ladill-pay-mode', 'pin');
|
||||||
|
var s = iframe.style;
|
||||||
|
var left = Math.max(0, Math.round(rect.left));
|
||||||
|
var top = Math.max(0, Math.round(rect.top));
|
||||||
|
var width = Math.max(0, Math.round(rect.width));
|
||||||
|
var height = Math.max(0, Math.round(rect.height));
|
||||||
|
// Direct pixels — CSS vars in setProperty are unreliable across browsers.
|
||||||
|
s.setProperty('position', 'fixed', 'important');
|
||||||
|
s.setProperty('left', left + 'px', 'important');
|
||||||
|
s.setProperty('top', top + 'px', 'important');
|
||||||
|
s.setProperty('right', 'auto', 'important');
|
||||||
|
s.setProperty('bottom', 'auto', 'important');
|
||||||
|
s.setProperty('width', width + 'px', 'important');
|
||||||
|
s.setProperty('height', height + 'px', 'important');
|
||||||
|
s.setProperty('max-width', 'none', 'important');
|
||||||
|
s.setProperty('max-height', 'none', 'important');
|
||||||
|
s.setProperty('margin', '0', 'important');
|
||||||
|
s.setProperty('padding', '0', 'important');
|
||||||
|
s.setProperty('border', '0', 'important');
|
||||||
|
s.setProperty('border-radius', '0', 'important');
|
||||||
|
s.setProperty('z-index', '10050', 'important');
|
||||||
|
s.setProperty('visibility', 'visible', 'important');
|
||||||
|
s.setProperty('display', 'block', 'important');
|
||||||
|
s.setProperty('opacity', '1', 'important');
|
||||||
|
s.setProperty('background', '#fff', 'important');
|
||||||
|
s.setProperty('background-color', '#fff', 'important');
|
||||||
|
s.setProperty('pointer-events', 'auto', 'important');
|
||||||
|
s.setProperty('color-scheme', 'light', 'important');
|
||||||
|
s.setProperty('transform', 'none', 'important');
|
||||||
|
applyIframePermissions(iframe);
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pinCheckoutIframe(iframe) {
|
||||||
|
if (!iframe || !window.__ladillContainPaystack) return;
|
||||||
|
var mount = getPaystackMount();
|
||||||
|
if (mount) {
|
||||||
|
styleMountAsContainer(mount);
|
||||||
|
// Prefer living inside the mount (absolute fill). Only first-append
|
||||||
|
// redirects into mount; if already elsewhere, pin with fixed+pixels.
|
||||||
|
if (iframe.parentNode === mount) {
|
||||||
|
styleCheckoutInMount(iframe);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var rect = measurePinTarget() || lastPinRect;
|
||||||
|
if (rect) {
|
||||||
|
lastPinRect = rect;
|
||||||
|
styleCheckoutPinnedToRect(iframe, rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function hidePaystackBackground(iframe) {
|
function hidePaystackBackground(iframe) {
|
||||||
if (!iframe) return;
|
if (!iframe) return;
|
||||||
try {
|
try {
|
||||||
@@ -249,6 +469,12 @@
|
|||||||
s.setProperty('visibility', 'hidden', 'important');
|
s.setProperty('visibility', 'hidden', 'important');
|
||||||
s.setProperty('pointer-events', 'none', 'important');
|
s.setProperty('pointer-events', 'none', 'important');
|
||||||
s.setProperty('opacity', '0', 'important');
|
s.setProperty('opacity', '0', 'important');
|
||||||
|
s.setProperty('z-index', '-1', 'important');
|
||||||
|
s.setProperty('width', '0', 'important');
|
||||||
|
s.setProperty('height', '0', 'important');
|
||||||
|
s.setProperty('left', '-9999px', 'important');
|
||||||
|
s.setProperty('top', '-9999px', 'important');
|
||||||
|
s.setProperty('position', 'fixed', 'important');
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,41 +484,28 @@
|
|||||||
hidePaystackBackground(iframe);
|
hidePaystackBackground(iframe);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!isPaystackCheckoutFrame(iframe) && !isPaystackIframe(iframe)) return;
|
if (!isCheckoutFrame(iframe) && !isPaystackCheckoutFrame(iframe)) {
|
||||||
if (isPaystackBackgroundFrame(iframe)) return;
|
if (isPaystackIframe(iframe)) applyIframePermissions(iframe);
|
||||||
|
|
||||||
var mount = getPaystackMount();
|
|
||||||
if (!mount) return;
|
|
||||||
|
|
||||||
// Prefer checkout frames; skip stray non-checkout paystack frames if unsure.
|
|
||||||
if (!isPaystackCheckoutFrame(iframe) && (iframe.id || '').indexOf('inline-') !== 0) {
|
|
||||||
applyIframePermissions(iframe);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
pinCheckoutIframe(iframe);
|
||||||
try {
|
|
||||||
if (iframe.parentNode !== mount) {
|
|
||||||
mount.appendChild(iframe);
|
|
||||||
}
|
|
||||||
styleContainedCheckout(iframe);
|
|
||||||
} catch (e) {
|
|
||||||
// If reparent fails mid-load, still try absolute restyle in place.
|
|
||||||
styleContainedCheckout(iframe);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensurePaystackContained(root) {
|
function ensurePaystackContained(root) {
|
||||||
if (!window.__ladillContainPaystack) return;
|
if (!window.__ladillContainPaystack) return;
|
||||||
try {
|
try {
|
||||||
var scope = root || document;
|
syncPaystackMountBox();
|
||||||
var nodes = scope.querySelectorAll ? scope.querySelectorAll('iframe') : [];
|
|
||||||
for (var i = 0; i < nodes.length; i++) {
|
|
||||||
containPaystackIframe(nodes[i]);
|
|
||||||
}
|
|
||||||
// Paystack may leave backgrounds on body outside scope walks.
|
|
||||||
var bgs = document.querySelectorAll('iframe[id^="inline-background"]');
|
var bgs = document.querySelectorAll('iframe[id^="inline-background"]');
|
||||||
for (var j = 0; j < bgs.length; j++) {
|
for (var j = 0; j < bgs.length; j++) hidePaystackBackground(bgs[j]);
|
||||||
hidePaystackBackground(bgs[j]);
|
|
||||||
|
var checks = document.querySelectorAll(
|
||||||
|
'iframe[id^="inline-checkout"], iframe[id^="embed-checkout"], iframe[data-ladill-pay-contained]'
|
||||||
|
);
|
||||||
|
for (var k = 0; k < checks.length; k++) pinCheckoutIframe(checks[k]);
|
||||||
|
|
||||||
|
if (root && root !== document && root.querySelectorAll) {
|
||||||
|
var nested = root.querySelectorAll('iframe');
|
||||||
|
for (var i = 0; i < nested.length; i++) containPaystackIframe(nested[i]);
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
@@ -303,9 +516,7 @@
|
|||||||
var nodes = scope.querySelectorAll ? scope.querySelectorAll('iframe') : [];
|
var nodes = scope.querySelectorAll ? scope.querySelectorAll('iframe') : [];
|
||||||
for (var i = 0; i < nodes.length; i++) {
|
for (var i = 0; i < nodes.length; i++) {
|
||||||
var iframe = nodes[i];
|
var iframe = nodes[i];
|
||||||
var src = '';
|
if (isPaystackIframe(iframe) || isCheckoutFrame(iframe)) {
|
||||||
try { src = (iframe.getAttribute('src') || '').trim(); } catch (e) {}
|
|
||||||
if (isPaystackIframe(iframe) || !src) {
|
|
||||||
applyIframePermissions(iframe);
|
applyIframePermissions(iframe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -315,10 +526,17 @@
|
|||||||
|
|
||||||
function syncPaystackMountBox() {
|
function syncPaystackMountBox() {
|
||||||
try {
|
try {
|
||||||
var mount = getPaystackMount();
|
if (!window.__ladillContainPaystack) return;
|
||||||
if (!mount || !window.__ladillContainPaystack) return;
|
var rect = measurePinTarget();
|
||||||
var rect = mount.getBoundingClientRect();
|
|
||||||
var root = document.documentElement;
|
var root = document.documentElement;
|
||||||
|
if (!rect) {
|
||||||
|
root.style.setProperty('--ladill-pay-left', '0px');
|
||||||
|
root.style.setProperty('--ladill-pay-top', '0px');
|
||||||
|
root.style.setProperty('--ladill-pay-width', '0px');
|
||||||
|
root.style.setProperty('--ladill-pay-height', '0px');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastPinRect = rect;
|
||||||
root.style.setProperty('--ladill-pay-left', Math.max(0, Math.round(rect.left)) + 'px');
|
root.style.setProperty('--ladill-pay-left', Math.max(0, Math.round(rect.left)) + 'px');
|
||||||
root.style.setProperty('--ladill-pay-top', Math.max(0, Math.round(rect.top)) + 'px');
|
root.style.setProperty('--ladill-pay-top', Math.max(0, Math.round(rect.top)) + 'px');
|
||||||
root.style.setProperty('--ladill-pay-width', Math.max(0, Math.round(rect.width)) + 'px');
|
root.style.setProperty('--ladill-pay-width', Math.max(0, Math.round(rect.width)) + 'px');
|
||||||
@@ -326,22 +544,78 @@
|
|||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function startPinLoop() {
|
||||||
|
stopPinLoop();
|
||||||
|
var tick = function () {
|
||||||
|
if (!window.__ladillContainPaystack) {
|
||||||
|
pinRafId = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ensurePaystackContained(document);
|
||||||
|
pinRafId = typeof requestAnimationFrame === 'function'
|
||||||
|
? requestAnimationFrame(tick)
|
||||||
|
: setTimeout(tick, 32);
|
||||||
|
};
|
||||||
|
tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopPinLoop() {
|
||||||
|
if (!pinRafId) return;
|
||||||
|
if (typeof cancelAnimationFrame === 'function') {
|
||||||
|
cancelAnimationFrame(pinRafId);
|
||||||
|
} else {
|
||||||
|
clearTimeout(pinRafId);
|
||||||
|
}
|
||||||
|
pinRafId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
function setPaystackContainActive(active) {
|
function setPaystackContainActive(active) {
|
||||||
window.__ladillContainPaystack = !!active;
|
window.__ladillContainPaystack = !!active;
|
||||||
try {
|
try {
|
||||||
document.documentElement.classList.toggle('ladill-pay-inline-active', !!active);
|
document.documentElement.classList.toggle('ladill-pay-inline-active', !!active);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
if (active) {
|
if (active) {
|
||||||
|
armPaystackMount();
|
||||||
|
styleMountAsContainer(getPaystackMount());
|
||||||
installIframeAllowHook();
|
installIframeAllowHook();
|
||||||
installAppendHook();
|
installAppendHook();
|
||||||
ensurePaystackContained(document);
|
ensurePaystackContained(document);
|
||||||
syncPaystackMountBox();
|
syncPaystackMountBox();
|
||||||
|
startPinLoop();
|
||||||
if (!window.__ladillPayMountResizeBound) {
|
if (!window.__ladillPayMountResizeBound) {
|
||||||
window.__ladillPayMountResizeBound = true;
|
window.__ladillPayMountResizeBound = true;
|
||||||
window.addEventListener('resize', syncPaystackMountBox, { passive: true });
|
window.addEventListener('resize', function () {
|
||||||
window.addEventListener('orientationchange', syncPaystackMountBox, { passive: true });
|
syncPaystackMountBox();
|
||||||
|
ensurePaystackContained(document);
|
||||||
|
}, { passive: true });
|
||||||
|
window.addEventListener('orientationchange', function () {
|
||||||
|
setTimeout(function () {
|
||||||
|
syncPaystackMountBox();
|
||||||
|
ensurePaystackContained(document);
|
||||||
|
}, 100);
|
||||||
|
}, { passive: true });
|
||||||
|
window.addEventListener('scroll', function () {
|
||||||
|
if (window.__ladillContainPaystack) {
|
||||||
|
syncPaystackMountBox();
|
||||||
|
ensurePaystackContained(document);
|
||||||
|
}
|
||||||
|
}, { passive: true, capture: true });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
stopPinLoop();
|
||||||
|
lastPinRect = null;
|
||||||
|
try {
|
||||||
|
if (activeMountEl) {
|
||||||
|
activeMountEl.style.removeProperty('display');
|
||||||
|
activeMountEl.style.removeProperty('visibility');
|
||||||
|
activeMountEl.style.removeProperty('pointer-events');
|
||||||
|
activeMountEl.style.removeProperty('transform');
|
||||||
|
activeMountEl.style.removeProperty('isolation');
|
||||||
|
activeMountEl.style.removeProperty('contain');
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
activeMountEl = null;
|
||||||
|
activeBodyEl = null;
|
||||||
try {
|
try {
|
||||||
var root = document.documentElement;
|
var root = document.documentElement;
|
||||||
root.style.removeProperty('--ladill-pay-left');
|
root.style.removeProperty('--ladill-pay-left');
|
||||||
@@ -373,48 +647,63 @@
|
|||||||
if (window.__ladillAppendHook) return;
|
if (window.__ladillAppendHook) return;
|
||||||
window.__ladillAppendHook = true;
|
window.__ladillAppendHook = true;
|
||||||
try {
|
try {
|
||||||
var origAppend = Node.prototype.appendChild;
|
|
||||||
Node.prototype.appendChild = function (child) {
|
Node.prototype.appendChild = function (child) {
|
||||||
try {
|
try {
|
||||||
if (window.__ladillContainPaystack && child && child.tagName === 'IFRAME') {
|
if (window.__ladillContainPaystack && child && child.tagName === 'IFRAME') {
|
||||||
if (isPaystackBackgroundFrame(child)) {
|
if (isPaystackBackgroundFrame(child)) {
|
||||||
var appendedBg = origAppend.call(this, child);
|
var bg = nativeAppendChild.call(this, child);
|
||||||
hidePaystackBackground(child);
|
hidePaystackBackground(child);
|
||||||
return appendedBg;
|
return bg;
|
||||||
}
|
}
|
||||||
if (isPaystackCheckoutFrame(child) || ((child.id || '').indexOf('inline-checkout') === 0)) {
|
if (isCheckoutFrame(child) || isPaystackCheckoutFrame(child)
|
||||||
|
|| (child.id || '').indexOf('inline-checkout') === 0
|
||||||
|
|| (child.id || '').indexOf('embed-checkout') === 0) {
|
||||||
var mount = getPaystackMount();
|
var mount = getPaystackMount();
|
||||||
if (mount) {
|
if (mount) {
|
||||||
var appended = origAppend.call(mount, child);
|
styleMountAsContainer(mount);
|
||||||
styleContainedCheckout(child);
|
// FIRST insert goes into mount — avoids later reparent reload.
|
||||||
return appended;
|
var mounted = nativeAppendChild.call(mount, child);
|
||||||
|
styleCheckoutInMount(child);
|
||||||
|
return mounted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
return origAppend.call(this, child);
|
var result = nativeAppendChild.call(this, child);
|
||||||
|
try {
|
||||||
|
if (window.__ladillContainPaystack && child && child.tagName === 'IFRAME') {
|
||||||
|
containPaystackIframe(child);
|
||||||
|
}
|
||||||
|
} catch (e2) {}
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
var origInsert = Node.prototype.insertBefore;
|
|
||||||
Node.prototype.insertBefore = function (child, ref) {
|
Node.prototype.insertBefore = function (child, ref) {
|
||||||
try {
|
try {
|
||||||
if (window.__ladillContainPaystack && child && child.tagName === 'IFRAME') {
|
if (window.__ladillContainPaystack && child && child.tagName === 'IFRAME') {
|
||||||
if (isPaystackBackgroundFrame(child)) {
|
if (isPaystackBackgroundFrame(child)) {
|
||||||
var insertedBg = origInsert.call(this, child, ref);
|
var bg = nativeInsertBefore.call(this, child, ref);
|
||||||
hidePaystackBackground(child);
|
hidePaystackBackground(child);
|
||||||
return insertedBg;
|
return bg;
|
||||||
}
|
}
|
||||||
if (isPaystackCheckoutFrame(child)) {
|
if (isCheckoutFrame(child) || isPaystackCheckoutFrame(child)) {
|
||||||
var mount = getPaystackMount();
|
var mount = getPaystackMount();
|
||||||
if (mount) {
|
if (mount) {
|
||||||
var inserted = origAppend.call(mount, child);
|
styleMountAsContainer(mount);
|
||||||
styleContainedCheckout(child);
|
var mounted = nativeAppendChild.call(mount, child);
|
||||||
return inserted;
|
styleCheckoutInMount(child);
|
||||||
|
return mounted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
return origInsert.call(this, child, ref);
|
var result = nativeInsertBefore.call(this, child, ref);
|
||||||
|
try {
|
||||||
|
if (window.__ladillContainPaystack && child && child.tagName === 'IFRAME') {
|
||||||
|
containPaystackIframe(child);
|
||||||
|
}
|
||||||
|
} catch (e2) {}
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
@@ -556,11 +845,17 @@
|
|||||||
this._activeCode = accessCode;
|
this._activeCode = accessCode;
|
||||||
this.launching = true;
|
this.launching = true;
|
||||||
this.error = '';
|
this.error = '';
|
||||||
// Arm containment before Paystack creates iframes so the first
|
// Wait for the bottomsheet/modal body to lay out, then open Paystack
|
||||||
// body.appendChild is redirected into our sheet mount.
|
// and pin its body iframe over that loading area (no reparent).
|
||||||
|
var start = function () {
|
||||||
|
if (token !== store._launchToken) return;
|
||||||
|
armPaystackMount();
|
||||||
setPaystackContainActive(true);
|
setPaystackContainActive(true);
|
||||||
watchPaystackIframes();
|
watchPaystackIframes();
|
||||||
loadInlineJs().then(function (PaystackPop) {
|
waitForPinTarget(1200).then(function () {
|
||||||
|
if (token !== store._launchToken) return;
|
||||||
|
return loadInlineJs();
|
||||||
|
}).then(function (PaystackPop) {
|
||||||
if (token !== store._launchToken) return;
|
if (token !== store._launchToken) return;
|
||||||
if (!PaystackPop) throw new Error('Paystack unavailable');
|
if (!PaystackPop) throw new Error('Paystack unavailable');
|
||||||
try {
|
try {
|
||||||
@@ -569,22 +864,25 @@
|
|||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
activePopup = null;
|
activePopup = null;
|
||||||
|
armPaystackMount();
|
||||||
setPaystackContainActive(true);
|
setPaystackContainActive(true);
|
||||||
|
syncPaystackMountBox();
|
||||||
|
// PaystackPop constructor appends iframes to document.body.
|
||||||
|
// We leave them there and pin checkout over our sheet body.
|
||||||
var popup = new PaystackPop();
|
var popup = new PaystackPop();
|
||||||
activePopup = popup;
|
activePopup = popup;
|
||||||
|
ensurePaystackContained(document);
|
||||||
popup.resumeTransaction(accessCode, {
|
popup.resumeTransaction(accessCode, {
|
||||||
onLoad: function () {
|
onLoad: function () {
|
||||||
if (token !== store._launchToken) return;
|
if (token !== store._launchToken) return;
|
||||||
store.launching = false;
|
store.launching = false;
|
||||||
ensurePaystackIframePermissions(document);
|
ensurePaystackIframePermissions(document);
|
||||||
ensurePaystackContained(document);
|
ensurePaystackContained(document);
|
||||||
// After Alpine hides the loading overlay, re-measure mount and re-pin iframe.
|
// Alpine swaps header/spinner; re-measure then re-pin.
|
||||||
setTimeout(function () {
|
setTimeout(function () { ensurePaystackContained(document); }, 0);
|
||||||
ensurePaystackContained(document);
|
setTimeout(function () { ensurePaystackContained(document); }, 50);
|
||||||
syncPaystackMountBox();
|
setTimeout(function () { ensurePaystackContained(document); }, 150);
|
||||||
}, 0);
|
setTimeout(function () { ensurePaystackContained(document); }, 400);
|
||||||
setTimeout(syncPaystackMountBox, 120);
|
|
||||||
setTimeout(syncPaystackMountBox, 400);
|
|
||||||
},
|
},
|
||||||
onSuccess: function (transaction) {
|
onSuccess: function (transaction) {
|
||||||
if (token !== store._launchToken) return;
|
if (token !== store._launchToken) return;
|
||||||
@@ -614,10 +912,10 @@
|
|||||||
store.error = (err && err.message) ? String(err.message) : 'Could not open secure payment.';
|
store.error = (err && err.message) ? String(err.message) : 'Could not open secure payment.';
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
// Paystack often inserts frames a tick after resumeTransaction.
|
|
||||||
setTimeout(function () { ensurePaystackContained(document); }, 0);
|
setTimeout(function () { ensurePaystackContained(document); }, 0);
|
||||||
setTimeout(function () { ensurePaystackContained(document); }, 50);
|
setTimeout(function () { ensurePaystackContained(document); }, 50);
|
||||||
setTimeout(function () { ensurePaystackContained(document); }, 200);
|
setTimeout(function () { ensurePaystackContained(document); }, 200);
|
||||||
|
setTimeout(function () { ensurePaystackContained(document); }, 500);
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
if (token !== store._launchToken) return;
|
if (token !== store._launchToken) return;
|
||||||
store.launching = false;
|
store.launching = false;
|
||||||
@@ -625,6 +923,12 @@
|
|||||||
setPaystackContainActive(false);
|
setPaystackContainActive(false);
|
||||||
store.error = (err && err.message) ? String(err.message) : 'Could not load payment script.';
|
store.error = (err && err.message) ? String(err.message) : 'Could not load payment script.';
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
if (typeof requestAnimationFrame === 'function') {
|
||||||
|
requestAnimationFrame(function () { requestAnimationFrame(start); });
|
||||||
|
} else {
|
||||||
|
setTimeout(start, 32);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -667,33 +971,52 @@
|
|||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
@endonce
|
@endonce
|
||||||
{{-- Override Paystack's full-viewport popup styles so checkout sits in our sheet mount. --}}
|
{{-- Keep Paystack checkout inside the Ladill sheet loading area. --}}
|
||||||
@once('ladill-paystack-contain-css')
|
@once('ladill-paystack-contain-css')
|
||||||
<style>
|
<style>
|
||||||
html.ladill-pay-inline-active iframe[id^="inline-background"] {
|
/* Hide Paystack's own full-screen dimmer — Ladill backdrop owns that. */
|
||||||
|
html.ladill-pay-inline-active iframe[id^="inline-background"],
|
||||||
|
iframe[data-ladill-pay-bg-hidden] {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
visibility: hidden !important;
|
visibility: hidden !important;
|
||||||
pointer-events: none !important;
|
pointer-events: none !important;
|
||||||
opacity: 0 !important;
|
opacity: 0 !important;
|
||||||
|
width: 0 !important;
|
||||||
|
height: 0 !important;
|
||||||
|
z-index: -1 !important;
|
||||||
|
left: -9999px !important;
|
||||||
|
top: -9999px !important;
|
||||||
|
position: fixed !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ladill-pay-mount] {
|
[data-ladill-pay-mount] {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
min-height: 12rem;
|
||||||
|
/* Containing block so fixed children cannot escape the sheet body. */
|
||||||
|
transform: translateZ(0);
|
||||||
|
isolation: isolate;
|
||||||
}
|
}
|
||||||
/* When Paystack is live the shell is transparent so only Paystack's own card shows. */
|
html.ladill-pay-inline-active [data-ladill-pay-mount] {
|
||||||
html.ladill-pay-inline-active [data-ladill-pay-panel][data-paystack-live="1"] {
|
display: block !important;
|
||||||
background: transparent !important;
|
visibility: visible !important;
|
||||||
box-shadow: none !important;
|
pointer-events: auto !important;
|
||||||
}
|
}
|
||||||
html.ladill-pay-inline-active [data-ladill-pay-panel][data-paystack-live="1"] [data-ladill-pay-mount] {
|
html.ladill-pay-inline-active [data-ladill-pay-panel] {
|
||||||
background: transparent !important;
|
/* Ensure panel is a stacking context above page content. */
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
/* Paystack draws its own modal chrome inside the iframe — fill the mount. */
|
html.ladill-pay-inline-active [data-ladill-pay-sheet] {
|
||||||
[data-ladill-pay-mount] iframe[data-ladill-pay-contained],
|
z-index: 9999 !important;
|
||||||
[data-ladill-pay-mount] iframe[id^="inline-checkout"],
|
}
|
||||||
[data-ladill-pay-mount] iframe[id^="embed-checkout"] {
|
|
||||||
|
/* Preferred: iframe lives inside the mount and fills it. */
|
||||||
|
html.ladill-pay-inline-active [data-ladill-pay-mount] iframe[id^="inline-checkout"],
|
||||||
|
html.ladill-pay-inline-active [data-ladill-pay-mount] iframe[id^="embed-checkout"],
|
||||||
|
html.ladill-pay-inline-active [data-ladill-pay-mount] iframe[data-ladill-pay-contained],
|
||||||
|
html.ladill-pay-inline-active iframe[data-ladill-pay-mode="mount"] {
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
left: 0 !important;
|
left: 0 !important;
|
||||||
top: 0 !important;
|
top: 0 !important;
|
||||||
@@ -710,26 +1033,43 @@
|
|||||||
z-index: 2 !important;
|
z-index: 2 !important;
|
||||||
visibility: visible !important;
|
visibility: visible !important;
|
||||||
display: block !important;
|
display: block !important;
|
||||||
background: transparent !important;
|
opacity: 1 !important;
|
||||||
|
background: #fff !important;
|
||||||
|
background-color: #fff !important;
|
||||||
color-scheme: light !important;
|
color-scheme: light !important;
|
||||||
|
pointer-events: auto !important;
|
||||||
|
transform: none !important;
|
||||||
}
|
}
|
||||||
/* If a Paystack frame escapes the mount, pin it over the mount box. */
|
|
||||||
|
/*
|
||||||
|
Fallback when the frame stays on body: pin with measured pixels.
|
||||||
|
Default 0×0 until JS measures the sheet body (never flash full viewport).
|
||||||
|
*/
|
||||||
html.ladill-pay-inline-active body > iframe[id^="inline-checkout"],
|
html.ladill-pay-inline-active body > iframe[id^="inline-checkout"],
|
||||||
html.ladill-pay-inline-active body > iframe[id^="embed-checkout"] {
|
html.ladill-pay-inline-active body > iframe[id^="embed-checkout"],
|
||||||
|
html.ladill-pay-inline-active iframe[data-ladill-pay-mode="pin"] {
|
||||||
position: fixed !important;
|
position: fixed !important;
|
||||||
left: var(--ladill-pay-left, 0) !important;
|
left: var(--ladill-pay-left, 0px) !important;
|
||||||
top: var(--ladill-pay-top, 0) !important;
|
top: var(--ladill-pay-top, 0px) !important;
|
||||||
width: var(--ladill-pay-width, 100%) !important;
|
right: auto !important;
|
||||||
height: var(--ladill-pay-height, 100%) !important;
|
bottom: auto !important;
|
||||||
|
width: var(--ladill-pay-width, 0px) !important;
|
||||||
|
height: var(--ladill-pay-height, 0px) !important;
|
||||||
max-width: none !important;
|
max-width: none !important;
|
||||||
max-height: none !important;
|
max-height: none !important;
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
border: 0 !important;
|
border: 0 !important;
|
||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
z-index: 10000 !important;
|
z-index: 10050 !important;
|
||||||
visibility: visible !important;
|
visibility: visible !important;
|
||||||
display: block !important;
|
display: block !important;
|
||||||
background: transparent !important;
|
opacity: 1 !important;
|
||||||
|
background: #fff !important;
|
||||||
|
background-color: #fff !important;
|
||||||
|
color-scheme: light !important;
|
||||||
|
pointer-events: auto !important;
|
||||||
|
transform: none !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@endonce
|
@endonce
|
||||||
@@ -779,10 +1119,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{--
|
{{--
|
||||||
ONE design everywhere (POS / Merchant / Mini / Give / Invoice / Events):
|
ONE surface everywhere (POS / Merchant / Mini / Give / Invoice / Events):
|
||||||
- Loading / error / same-origin: white bottomsheet (mobile) or modal (desktop)
|
- Mobile: bottom sheet
|
||||||
- Paystack Inline ready: transparent shell so Paystack's own card is the only surface
|
- Desktop: centered modal
|
||||||
on the dimmed backdrop (no second white frame / double modal)
|
- Paystack Inline fills the sheet body loading area (not a second full-screen modal)
|
||||||
--}}
|
--}}
|
||||||
<div data-ladill-pay-panel
|
<div data-ladill-pay-panel
|
||||||
x-show="showSheet"
|
x-show="showSheet"
|
||||||
@@ -792,30 +1132,15 @@
|
|||||||
x-transition:leave="transition duration-200 ease-in md:duration-150"
|
x-transition:leave="transition duration-200 ease-in md:duration-150"
|
||||||
x-transition:leave-start="translate-y-0 opacity-100 md:scale-100"
|
x-transition:leave-start="translate-y-0 opacity-100 md:scale-100"
|
||||||
x-transition:leave-end="translate-y-full opacity-0 md:translate-y-0 md:scale-95"
|
x-transition:leave-end="translate-y-full opacity-0 md:translate-y-0 md:scale-95"
|
||||||
class="relative flex w-full flex-col overflow-hidden"
|
class="relative flex w-full flex-col overflow-hidden rounded-t-2xl bg-white shadow-2xl md:rounded-2xl"
|
||||||
:data-paystack-live="($store.ladillPayCheckout && $store.ladillPayCheckout.inline && !$store.ladillPayCheckout.launching && !$store.ladillPayCheckout.error && !$store.ladillPayCheckout.frameable) ? '1' : '0'"
|
:data-paystack-live="($store.ladillPayCheckout && $store.ladillPayCheckout.inline && !$store.ladillPayCheckout.launching && !$store.ladillPayCheckout.error && !$store.ladillPayCheckout.frameable) ? '1' : '0'"
|
||||||
:class="($store.ladillPayCheckout && $store.ladillPayCheckout.inline && !$store.ladillPayCheckout.launching && !$store.ladillPayCheckout.error && !$store.ladillPayCheckout.frameable)
|
:class="($store.ladillPayCheckout && $store.ladillPayCheckout.inline && !$store.ladillPayCheckout.launching && !$store.ladillPayCheckout.error && !$store.ladillPayCheckout.frameable)
|
||||||
? 'max-w-none rounded-none bg-transparent shadow-none md:w-[min(100vw,720px)]'
|
? 'md:max-w-3xl'
|
||||||
: 'rounded-t-2xl bg-white shadow-2xl md:max-w-lg md:rounded-2xl'"
|
: 'md:max-w-lg'"
|
||||||
:style="($store.ladillPayCheckout && $store.ladillPayCheckout.inline && !$store.ladillPayCheckout.launching && !$store.ladillPayCheckout.error && !$store.ladillPayCheckout.frameable)
|
style="height: min(90dvh, 720px); max-height: 90dvh; padding-bottom: env(safe-area-inset-bottom, 0px)"
|
||||||
? 'height: min(90dvh, 640px); max-height: 90dvh; width: min(100vw, 720px); padding-bottom: 0;'
|
|
||||||
: 'height: min(90dvh, 720px); max-height: 90dvh; padding-bottom: env(safe-area-inset-bottom, 0px);'"
|
|
||||||
@click.stop>
|
@click.stop>
|
||||||
|
|
||||||
{{-- Floating close when Paystack owns the surface (Paystack has no host close for us) --}}
|
{{-- Full header while loading / error / same-origin; compact bar once Paystack fills the body --}}
|
||||||
<button type="button"
|
|
||||||
x-show="$store.ladillPayCheckout && $store.ladillPayCheckout.inline && !$store.ladillPayCheckout.launching && !$store.ladillPayCheckout.error && !$store.ladillPayCheckout.frameable"
|
|
||||||
@click="showSheet = false; window.LadillPayCheckout?.cancel?.()"
|
|
||||||
class="absolute right-3 top-3 z-30 flex h-9 w-9 items-center justify-center rounded-full bg-white/95 text-slate-600 shadow-md ring-1 ring-slate-200/80 backdrop-blur hover:bg-white hover:text-slate-900 md:right-0 md:-mr-12 md:top-0 md:bg-white"
|
|
||||||
style="top: max(0.75rem, env(safe-area-inset-top, 0px))"
|
|
||||||
data-ladill-pay-close-live
|
|
||||||
aria-label="Close">
|
|
||||||
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{{-- Standard POS header: loading, error, or same-origin waiting page --}}
|
|
||||||
<div x-show="!$store.ladillPayCheckout
|
<div x-show="!$store.ladillPayCheckout
|
||||||
|| $store.ladillPayCheckout.frameable
|
|| $store.ladillPayCheckout.frameable
|
||||||
|| $store.ladillPayCheckout.launching
|
|| $store.ladillPayCheckout.launching
|
||||||
@@ -845,26 +1170,42 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div x-show="$store.ladillPayCheckout
|
||||||
|
&& $store.ladillPayCheckout.inline
|
||||||
|
&& !$store.ladillPayCheckout.launching
|
||||||
|
&& !$store.ladillPayCheckout.error
|
||||||
|
&& !$store.ladillPayCheckout.frameable"
|
||||||
|
class="relative z-20 flex shrink-0 items-center justify-between border-b border-slate-100 px-3 pb-2 pt-3 md:px-4 md:pt-2"
|
||||||
|
style="padding-top: max(0.75rem, env(safe-area-inset-top, 0px))"
|
||||||
|
data-ladill-pay-header-minimal>
|
||||||
|
<div class="absolute left-1/2 top-2 h-1 w-10 -translate-x-1/2 rounded-full bg-slate-200 md:hidden" data-ladill-pay-handle aria-hidden="true"></div>
|
||||||
|
<p class="pl-1 text-xs font-medium text-slate-500">{{ $sheetTitle }}</p>
|
||||||
|
<button type="button"
|
||||||
|
data-ladill-pay-close-live
|
||||||
|
@click="showSheet = false; window.LadillPayCheckout?.cancel?.()"
|
||||||
|
class="shrink-0 rounded-full p-1.5 text-slate-400 transition hover:bg-slate-100 hover:text-slate-700"
|
||||||
|
aria-label="Close">
|
||||||
|
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{-- Body: spinner while starting; Paystack fills this when ready --}}
|
{{-- Body: spinner while starting; Paystack fills this when ready --}}
|
||||||
<div class="relative min-h-0 flex-1 overflow-hidden overscroll-contain"
|
<div class="relative min-h-0 flex-1 overflow-hidden overscroll-contain bg-white"
|
||||||
data-ladill-pay-body
|
data-ladill-pay-body
|
||||||
:class="($store.ladillPayCheckout && $store.ladillPayCheckout.inline && !$store.ladillPayCheckout.launching && !$store.ladillPayCheckout.error && !$store.ladillPayCheckout.frameable)
|
style="min-height: 22rem">
|
||||||
? 'bg-transparent'
|
|
||||||
: 'bg-white'"
|
|
||||||
style="min-height: 20rem">
|
|
||||||
<iframe x-show="$store.ladillPayCheckout && $store.ladillPayCheckout.frameable"
|
<iframe x-show="$store.ladillPayCheckout && $store.ladillPayCheckout.frameable"
|
||||||
:src="showSheet && $store.ladillPayCheckout && $store.ladillPayCheckout.frameable ? checkoutUrl : ''"
|
:src="showSheet && $store.ladillPayCheckout && $store.ladillPayCheckout.frameable ? checkoutUrl : ''"
|
||||||
class="absolute inset-0 h-full w-full border-0"
|
class="absolute inset-0 h-full w-full border-0"
|
||||||
allow="payment *; fullscreen *; clipboard-read *; clipboard-write *"
|
allow="payment *; fullscreen *; clipboard-read *; clipboard-write *"
|
||||||
title="{{ $iframeTitle }}"></iframe>
|
title="{{ $iframeTitle }}"></iframe>
|
||||||
|
|
||||||
|
{{-- Pin target for Paystack: keep in layout while inline checkout is active. --}}
|
||||||
<div x-show="!$store.ladillPayCheckout || !$store.ladillPayCheckout.frameable"
|
<div x-show="!$store.ladillPayCheckout || !$store.ladillPayCheckout.frameable"
|
||||||
data-ladill-pay-mount
|
data-ladill-pay-mount
|
||||||
id="ladill-paystack-mount"
|
class="absolute inset-0 bg-white"
|
||||||
class="absolute inset-0"
|
style="min-height: 12rem"
|
||||||
:class="($store.ladillPayCheckout && $store.ladillPayCheckout.inline && !$store.ladillPayCheckout.launching && !$store.ladillPayCheckout.error)
|
|
||||||
? 'bg-transparent'
|
|
||||||
: 'bg-white'"
|
|
||||||
aria-hidden="true"></div>
|
aria-hidden="true"></div>
|
||||||
|
|
||||||
<div x-show="(!$store.ladillPayCheckout || !$store.ladillPayCheckout.frameable)
|
<div x-show="(!$store.ladillPayCheckout || !$store.ladillPayCheckout.frameable)
|
||||||
|
|||||||
Reference in New Issue
Block a user