Skip to content

Commit a95e00e

Browse files
authored
Merge pull request #15 from tebexjaames/7870812034-modal-close-options
7870812034 Add modal close options
2 parents 414a525 + ae32b65 commit a95e00e

22 files changed

+1829
-979
lines changed

.github/workflows/pr.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ name: PR
55
on:
66
# Triggers the workflow on push or pull request events but only for the master branch
77
pull_request:
8-
types: [opened, reopened]
8+
types: [opened, reopened, synchronize]
99

1010
jobs:
1111
test-and-build:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ node_modules*
99

1010
tsconfig.vitest-temp.json
1111
coverage
12+
__screenshots__
1213
.env
1314
.dev.vars
1415

dist/tebex.cjs

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,10 @@
418418
* @internal
419419
*/
420420
const transitionEnd = async (el) => new Promise((resolve) => {
421-
if (!getComputedStyle(el).transition)
421+
const style = getComputedStyle(el);
422+
if (!style.transition)
423+
resolve();
424+
if (parseFloat(style.transitionDuration) === 0)
422425
resolve();
423426
const done = () => {
424427
el.removeEventListener("transitionend", done);
@@ -12425,8 +12428,24 @@
1242512428

1242612429
var styles$1 = ".tebex-js-lightbox{all:unset;zoom:1;forced-color-adjust:none;position:fixed;left:0;top:0;width:100vw;height:100vh;z-index:var(--tebex-js-z-index,9999999);background:var(--tebex-js-lightbox-bg,rgba(0,0,0,.8));opacity:0;transition-property:opacity;transition-duration:var(--tebex-js-duration,.4s);transition-timing-function:var(--tebex-js-timing,ease);will-change:opacity;display:flex;justify-content:center;align-items:center;user-select:none;-webkit-user-select:none;-moz-user-select:none;}.tebex-js-lightbox--visible{opacity:1;}.tebex-js-lightbox__holder{display:block;border:0;overflow:hidden;border-radius:5px;}.tebex-js-lightbox__holder > div{display:block!important;}";
1242712430

12431+
var _Lightbox_onClickOutside, _Lightbox_onKeyPress;
1242812432
class Lightbox {
1242912433
constructor() {
12434+
this.clickOutsideHandler = null;
12435+
this.escKeyHandler = null;
12436+
_Lightbox_onClickOutside.set(this, (e) => {
12437+
if (!this.clickOutsideHandler)
12438+
return;
12439+
// @ts-expect-error: e.target type isn't necessarily Element
12440+
if (!this.holder.contains(e.target))
12441+
this.clickOutsideHandler(e);
12442+
});
12443+
_Lightbox_onKeyPress.set(this, (e) => {
12444+
if (!this.escKeyHandler)
12445+
return;
12446+
if (e.key === "Escape")
12447+
this.escKeyHandler(e);
12448+
});
1243012449
assert(isEnvBrowser());
1243112450
this.body = document.body;
1243212451
const stylesheet = createElement("style");
@@ -12444,18 +12463,27 @@
1244412463
await nextFrame();
1244512464
this.root.classList.add("tebex-js-lightbox--visible");
1244612465
await transitionEnd(this.root);
12466+
this.body.addEventListener("click", __classPrivateFieldGet(this, _Lightbox_onClickOutside, "f"));
12467+
this.body.addEventListener("keydown", __classPrivateFieldGet(this, _Lightbox_onKeyPress, "f"));
1244712468
}
1244812469
async hide() {
12470+
this.body.removeEventListener("click", __classPrivateFieldGet(this, _Lightbox_onClickOutside, "f"));
12471+
this.body.removeEventListener("keydown", __classPrivateFieldGet(this, _Lightbox_onKeyPress, "f"));
1244912472
this.root.classList.remove("tebex-js-lightbox--visible");
1245012473
await nextFrame();
1245112474
await transitionEnd(this.root);
1245212475
this.body.removeChild(this.root);
1245312476
}
1245412477
destroy() {
12455-
if (this.root.parentNode)
12456-
this.body.removeChild(this.root);
12478+
if (!this.root.parentNode)
12479+
return;
12480+
this.body.removeEventListener("click", __classPrivateFieldGet(this, _Lightbox_onClickOutside, "f"));
12481+
this.body.removeEventListener("keydown", __classPrivateFieldGet(this, _Lightbox_onKeyPress, "f"));
12482+
this.root.classList.remove("tebex-js-lightbox--visible");
12483+
this.body.removeChild(this.root);
1245712484
}
1245812485
}
12486+
_Lightbox_onClickOutside = new WeakMap(), _Lightbox_onKeyPress = new WeakMap();
1245912487

1246012488
var styles = "html,body{width:100px;height:100px;overflow:hidden;}.tebex-js-spinner{position:fixed;max-height:60vmin;max-width:60vmin;height:40px;width:40px;top:50%;left:50%;box-sizing:border-box;border:3px solid rgba(0,0,0,.2);border-top-color:#FFF;border-radius:100%;animation:tebex-js-spinner-rotation .7s infinite linear;}@keyframes tebex-js-spinner-rotation{from{transform:translateX(-50%) translateY(-50%) rotate(0deg);}to{transform:translateX(-50%) translateY(-50%) rotate(359deg);}}";
1246112489

@@ -12470,7 +12498,7 @@
1247012498
return html;
1247112499
};
1247212500

12473-
var _Checkout_instances, _Checkout_didRender, _Checkout_onRender, _Checkout_showLightbox, _Checkout_buildComponent, _Checkout_renderComponent;
12501+
var _Checkout_instances, _Checkout_didRender, _Checkout_onRender, _Checkout_onRequestLightboxClose, _Checkout_showLightbox, _Checkout_buildComponent, _Checkout_renderComponent;
1247412502
const DEFAULT_WIDTH = "800px";
1247512503
const DEFAULT_HEIGHT = "760px";
1247612504
const THEME_NAMES = [
@@ -12499,15 +12527,21 @@
1249912527
this.locale = null;
1250012528
this.theme = "default";
1250112529
this.colors = [];
12502-
this.endpoint = "https://pay.tebex.io";
12530+
this.closeOnClickOutside = false;
12531+
this.closeOnEsc = false;
1250312532
this.popupOnMobile = false;
12533+
this.endpoint = "https://pay.tebex.io";
1250412534
this.isOpen = false;
1250512535
this.emitter = createNanoEvents();
1250612536
this.lightbox = null;
1250712537
this.component = null;
1250812538
this.zoid = null;
1250912539
_Checkout_didRender.set(this, false);
1251012540
_Checkout_onRender.set(this, void 0);
12541+
_Checkout_onRequestLightboxClose.set(this, async () => {
12542+
if (this.isOpen)
12543+
await this.close();
12544+
});
1251112545
}
1251212546
/**
1251312547
* Configure the Tebex checkout settings.
@@ -12517,8 +12551,10 @@
1251712551
this.locale = options.locale ?? null;
1251812552
this.theme = options.theme ?? this.theme;
1251912553
this.colors = options.colors ?? this.colors;
12520-
this.endpoint = options.endpoint ?? this.endpoint;
12554+
this.closeOnClickOutside = options.closeOnClickOutside ?? this.closeOnClickOutside;
12555+
this.closeOnEsc = options.closeOnEsc ?? this.closeOnEsc;
1252112556
this.popupOnMobile = options.popupOnMobile ?? this.popupOnMobile;
12557+
this.endpoint = options.endpoint ?? this.endpoint;
1252212558
assert(!isNullOrUndefined(this.ident), "ident option is required");
1252312559
assert(THEME_NAMES.includes(this.theme), `invalid theme option "${this.theme}"`);
1252412560
for (let { color, name } of this.colors) {
@@ -12603,9 +12639,13 @@
1260312639
});
1260412640
}
1260512641
}
12606-
_Checkout_didRender = new WeakMap(), _Checkout_onRender = new WeakMap(), _Checkout_instances = new WeakSet(), _Checkout_showLightbox = async function _Checkout_showLightbox() {
12642+
_Checkout_didRender = new WeakMap(), _Checkout_onRender = new WeakMap(), _Checkout_onRequestLightboxClose = new WeakMap(), _Checkout_instances = new WeakSet(), _Checkout_showLightbox = async function _Checkout_showLightbox() {
1260712643
if (!this.lightbox)
1260812644
this.lightbox = new Lightbox();
12645+
if (this.closeOnClickOutside)
12646+
this.lightbox.clickOutsideHandler = __classPrivateFieldGet(this, _Checkout_onRequestLightboxClose, "f");
12647+
if (this.closeOnEsc)
12648+
this.lightbox.escKeyHandler = __classPrivateFieldGet(this, _Checkout_onRequestLightboxClose, "f");
1260912649
await this.lightbox.show();
1261012650
await __classPrivateFieldGet(this, _Checkout_instances, "m", _Checkout_renderComponent).call(this, this.lightbox.holder, false);
1261112651
this.isOpen = true;
@@ -12636,6 +12676,8 @@
1263612676
this.zoid = this.component({
1263712677
locale: this.locale,
1263812678
colors: this.colors,
12679+
closeOnClickOutside: this.closeOnClickOutside,
12680+
closeOnEsc: this.closeOnEsc,
1263912681
theme: this.theme,
1264012682
onOpenWindow: (url) => {
1264112683
window.open(url);
@@ -12659,7 +12701,7 @@
1265912701
origin: url.origin,
1266012702
path: url.pathname,
1266112703
params: url.search,
12662-
version: "1.4.0",
12704+
version: "1.5.0",
1266312705
});
1266412706
await this.zoid.renderTo(window, container, popup ? "popup" : "iframe");
1266512707
__classPrivateFieldSet(this, _Checkout_didRender, true, "f");
@@ -12815,6 +12857,8 @@
1281512857
locale: getAttribute(this, "locale"),
1281612858
theme: getAttribute(this, "theme"),
1281712859
colors: colors,
12860+
closeOnClickOutside: getAttribute(this, "close-on-click-outside") !== null,
12861+
closeOnEsc: getAttribute(this, "close-on-esc") !== null,
1281812862
popupOnMobile: getAttribute(this, "popup-on-mobile") !== null,
1281912863
endpoint: getAttribute(this, "endpoint"),
1282012864
});
@@ -12862,7 +12906,7 @@
1286212906
/**
1286312907
* Current Tebex.js package version
1286412908
*/
12865-
const version = "1.4.0";
12909+
const version = "1.5.0";
1286612910
/**
1286712911
* Tebex checkout API
1286812912
*/

dist/tebex.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/tebex.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/tebex.mjs

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,10 @@ const nextFrame = async () => new Promise((resolve) => {
412412
* @internal
413413
*/
414414
const transitionEnd = async (el) => new Promise((resolve) => {
415-
if (!getComputedStyle(el).transition)
415+
const style = getComputedStyle(el);
416+
if (!style.transition)
417+
resolve();
418+
if (parseFloat(style.transitionDuration) === 0)
416419
resolve();
417420
const done = () => {
418421
el.removeEventListener("transitionend", done);
@@ -12419,8 +12422,24 @@ let createNanoEvents = () => ({
1241912422

1242012423
var styles$1 = ".tebex-js-lightbox{all:unset;zoom:1;forced-color-adjust:none;position:fixed;left:0;top:0;width:100vw;height:100vh;z-index:var(--tebex-js-z-index,9999999);background:var(--tebex-js-lightbox-bg,rgba(0,0,0,.8));opacity:0;transition-property:opacity;transition-duration:var(--tebex-js-duration,.4s);transition-timing-function:var(--tebex-js-timing,ease);will-change:opacity;display:flex;justify-content:center;align-items:center;user-select:none;-webkit-user-select:none;-moz-user-select:none;}.tebex-js-lightbox--visible{opacity:1;}.tebex-js-lightbox__holder{display:block;border:0;overflow:hidden;border-radius:5px;}.tebex-js-lightbox__holder > div{display:block!important;}";
1242112424

12425+
var _Lightbox_onClickOutside, _Lightbox_onKeyPress;
1242212426
class Lightbox {
1242312427
constructor() {
12428+
this.clickOutsideHandler = null;
12429+
this.escKeyHandler = null;
12430+
_Lightbox_onClickOutside.set(this, (e) => {
12431+
if (!this.clickOutsideHandler)
12432+
return;
12433+
// @ts-expect-error: e.target type isn't necessarily Element
12434+
if (!this.holder.contains(e.target))
12435+
this.clickOutsideHandler(e);
12436+
});
12437+
_Lightbox_onKeyPress.set(this, (e) => {
12438+
if (!this.escKeyHandler)
12439+
return;
12440+
if (e.key === "Escape")
12441+
this.escKeyHandler(e);
12442+
});
1242412443
assert(isEnvBrowser());
1242512444
this.body = document.body;
1242612445
const stylesheet = createElement("style");
@@ -12438,18 +12457,27 @@ class Lightbox {
1243812457
await nextFrame();
1243912458
this.root.classList.add("tebex-js-lightbox--visible");
1244012459
await transitionEnd(this.root);
12460+
this.body.addEventListener("click", __classPrivateFieldGet(this, _Lightbox_onClickOutside, "f"));
12461+
this.body.addEventListener("keydown", __classPrivateFieldGet(this, _Lightbox_onKeyPress, "f"));
1244112462
}
1244212463
async hide() {
12464+
this.body.removeEventListener("click", __classPrivateFieldGet(this, _Lightbox_onClickOutside, "f"));
12465+
this.body.removeEventListener("keydown", __classPrivateFieldGet(this, _Lightbox_onKeyPress, "f"));
1244312466
this.root.classList.remove("tebex-js-lightbox--visible");
1244412467
await nextFrame();
1244512468
await transitionEnd(this.root);
1244612469
this.body.removeChild(this.root);
1244712470
}
1244812471
destroy() {
12449-
if (this.root.parentNode)
12450-
this.body.removeChild(this.root);
12472+
if (!this.root.parentNode)
12473+
return;
12474+
this.body.removeEventListener("click", __classPrivateFieldGet(this, _Lightbox_onClickOutside, "f"));
12475+
this.body.removeEventListener("keydown", __classPrivateFieldGet(this, _Lightbox_onKeyPress, "f"));
12476+
this.root.classList.remove("tebex-js-lightbox--visible");
12477+
this.body.removeChild(this.root);
1245112478
}
1245212479
}
12480+
_Lightbox_onClickOutside = new WeakMap(), _Lightbox_onKeyPress = new WeakMap();
1245312481

1245412482
var styles = "html,body{width:100px;height:100px;overflow:hidden;}.tebex-js-spinner{position:fixed;max-height:60vmin;max-width:60vmin;height:40px;width:40px;top:50%;left:50%;box-sizing:border-box;border:3px solid rgba(0,0,0,.2);border-top-color:#FFF;border-radius:100%;animation:tebex-js-spinner-rotation .7s infinite linear;}@keyframes tebex-js-spinner-rotation{from{transform:translateX(-50%) translateY(-50%) rotate(0deg);}to{transform:translateX(-50%) translateY(-50%) rotate(359deg);}}";
1245512483

@@ -12464,7 +12492,7 @@ const spinnerRender = ({ doc, props }) => {
1246412492
return html;
1246512493
};
1246612494

12467-
var _Checkout_instances, _Checkout_didRender, _Checkout_onRender, _Checkout_showLightbox, _Checkout_buildComponent, _Checkout_renderComponent;
12495+
var _Checkout_instances, _Checkout_didRender, _Checkout_onRender, _Checkout_onRequestLightboxClose, _Checkout_showLightbox, _Checkout_buildComponent, _Checkout_renderComponent;
1246812496
const DEFAULT_WIDTH = "800px";
1246912497
const DEFAULT_HEIGHT = "760px";
1247012498
const THEME_NAMES = [
@@ -12493,15 +12521,21 @@ class Checkout {
1249312521
this.locale = null;
1249412522
this.theme = "default";
1249512523
this.colors = [];
12496-
this.endpoint = "https://pay.tebex.io";
12524+
this.closeOnClickOutside = false;
12525+
this.closeOnEsc = false;
1249712526
this.popupOnMobile = false;
12527+
this.endpoint = "https://pay.tebex.io";
1249812528
this.isOpen = false;
1249912529
this.emitter = createNanoEvents();
1250012530
this.lightbox = null;
1250112531
this.component = null;
1250212532
this.zoid = null;
1250312533
_Checkout_didRender.set(this, false);
1250412534
_Checkout_onRender.set(this, void 0);
12535+
_Checkout_onRequestLightboxClose.set(this, async () => {
12536+
if (this.isOpen)
12537+
await this.close();
12538+
});
1250512539
}
1250612540
/**
1250712541
* Configure the Tebex checkout settings.
@@ -12511,8 +12545,10 @@ class Checkout {
1251112545
this.locale = options.locale ?? null;
1251212546
this.theme = options.theme ?? this.theme;
1251312547
this.colors = options.colors ?? this.colors;
12514-
this.endpoint = options.endpoint ?? this.endpoint;
12548+
this.closeOnClickOutside = options.closeOnClickOutside ?? this.closeOnClickOutside;
12549+
this.closeOnEsc = options.closeOnEsc ?? this.closeOnEsc;
1251512550
this.popupOnMobile = options.popupOnMobile ?? this.popupOnMobile;
12551+
this.endpoint = options.endpoint ?? this.endpoint;
1251612552
assert(!isNullOrUndefined(this.ident), "ident option is required");
1251712553
assert(THEME_NAMES.includes(this.theme), `invalid theme option "${this.theme}"`);
1251812554
for (let { color, name } of this.colors) {
@@ -12597,9 +12633,13 @@ class Checkout {
1259712633
});
1259812634
}
1259912635
}
12600-
_Checkout_didRender = new WeakMap(), _Checkout_onRender = new WeakMap(), _Checkout_instances = new WeakSet(), _Checkout_showLightbox = async function _Checkout_showLightbox() {
12636+
_Checkout_didRender = new WeakMap(), _Checkout_onRender = new WeakMap(), _Checkout_onRequestLightboxClose = new WeakMap(), _Checkout_instances = new WeakSet(), _Checkout_showLightbox = async function _Checkout_showLightbox() {
1260112637
if (!this.lightbox)
1260212638
this.lightbox = new Lightbox();
12639+
if (this.closeOnClickOutside)
12640+
this.lightbox.clickOutsideHandler = __classPrivateFieldGet(this, _Checkout_onRequestLightboxClose, "f");
12641+
if (this.closeOnEsc)
12642+
this.lightbox.escKeyHandler = __classPrivateFieldGet(this, _Checkout_onRequestLightboxClose, "f");
1260312643
await this.lightbox.show();
1260412644
await __classPrivateFieldGet(this, _Checkout_instances, "m", _Checkout_renderComponent).call(this, this.lightbox.holder, false);
1260512645
this.isOpen = true;
@@ -12630,6 +12670,8 @@ _Checkout_didRender = new WeakMap(), _Checkout_onRender = new WeakMap(), _Checko
1263012670
this.zoid = this.component({
1263112671
locale: this.locale,
1263212672
colors: this.colors,
12673+
closeOnClickOutside: this.closeOnClickOutside,
12674+
closeOnEsc: this.closeOnEsc,
1263312675
theme: this.theme,
1263412676
onOpenWindow: (url) => {
1263512677
window.open(url);
@@ -12653,7 +12695,7 @@ _Checkout_didRender = new WeakMap(), _Checkout_onRender = new WeakMap(), _Checko
1265312695
origin: url.origin,
1265412696
path: url.pathname,
1265512697
params: url.search,
12656-
version: "1.4.0",
12698+
version: "1.5.0",
1265712699
});
1265812700
await this.zoid.renderTo(window, container, popup ? "popup" : "iframe");
1265912701
__classPrivateFieldSet(this, _Checkout_didRender, true, "f");
@@ -12809,6 +12851,8 @@ _TebexCheckout_attachClickHandlers = new WeakMap(), _TebexCheckout_instances = n
1280912851
locale: getAttribute(this, "locale"),
1281012852
theme: getAttribute(this, "theme"),
1281112853
colors: colors,
12854+
closeOnClickOutside: getAttribute(this, "close-on-click-outside") !== null,
12855+
closeOnEsc: getAttribute(this, "close-on-esc") !== null,
1281212856
popupOnMobile: getAttribute(this, "popup-on-mobile") !== null,
1281312857
endpoint: getAttribute(this, "endpoint"),
1281412858
});
@@ -12856,7 +12900,7 @@ if (isEnvBrowser())
1285612900
/**
1285712901
* Current Tebex.js package version
1285812902
*/
12859-
const version = "1.4.0";
12903+
const version = "1.5.0";
1286012904
/**
1286112905
* Tebex checkout API
1286212906
*/

dist/types/checkout.d.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@ export type CheckoutOptions = {
2626
* @default []
2727
*/
2828
colors?: CheckoutColorDefinition[];
29+
/**
30+
* Whether to close the Tebex.js popup when the user clicks outside of the modal.
31+
* @default false
32+
*/
33+
closeOnClickOutside?: boolean;
34+
/**
35+
* Whether to close the Tebex.js popup when the user presses the Escape key.
36+
* @default false
37+
*/
38+
closeOnEsc?: boolean;
2939
/**
3040
* Whether to still display a popup on mobile or not. If `false` or undefined, then calling `launch()` will open a new window on mobile devices.
3141
* @default false
@@ -72,8 +82,10 @@ export default class Checkout {
7282
locale: string;
7383
theme: CheckoutTheme;
7484
colors: CheckoutColorDefinition[];
75-
endpoint: string;
85+
closeOnClickOutside: boolean;
86+
closeOnEsc: boolean;
7687
popupOnMobile: boolean;
88+
endpoint: string;
7789
isOpen: boolean;
7890
emitter: import("nanoevents").Emitter<{
7991
open: () => void;

dist/types/lightbox.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1+
export type LightboxClickOutsideHandler = (e: MouseEvent) => void;
2+
export type LightboxEscKeyHandler = (e: KeyboardEvent) => void;
13
export declare class Lightbox {
4+
#private;
25
body: HTMLElement;
36
root: HTMLElement;
47
holder: HTMLElement;
8+
clickOutsideHandler: LightboxClickOutsideHandler | null;
9+
escKeyHandler: LightboxEscKeyHandler | null;
510
constructor();
611
render(): any;
712
show(): Promise<void>;

0 commit comments

Comments
 (0)