layerpro 3.1.0 → 3.1.1
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.
- package/README.md +44 -19
- package/index.cjs +28 -26
- package/index.js +28 -26
- package/markdown/GUIDE.md +367 -367
- package/package.json +1 -1
- package/types/layerpro.d.ts +3 -0
package/README.md
CHANGED
|
@@ -66,7 +66,17 @@ Import LayerPro once in your app entry point:
|
|
|
66
66
|
import "layerpro";
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
That's it. Now you have `alert()`, `confirm()`, `prompt()`, and `
|
|
69
|
+
That's it. Now you have `alert()`, `confirm()`, `prompt()`, `message()`, and `popup()` globally available.
|
|
70
|
+
|
|
71
|
+
The `popup` alias is a shorthand for `layerpro.popup`:
|
|
72
|
+
|
|
73
|
+
```javascript
|
|
74
|
+
import "layerpro";
|
|
75
|
+
|
|
76
|
+
// Both work identically:
|
|
77
|
+
layerpro.popup.open({ id: 'myPopup', body: 'Hello World' });
|
|
78
|
+
popup.open({ id: 'myPopup', body: 'Hello World' });
|
|
79
|
+
```
|
|
70
80
|
|
|
71
81
|
---
|
|
72
82
|
|
|
@@ -90,8 +100,23 @@ message("Operation complete!");
|
|
|
90
100
|
|
|
91
101
|
### Custom Popups
|
|
92
102
|
|
|
103
|
+
You can use either `layerpro.popup.open(...)` or the shorthand `popup.open(...)`:
|
|
104
|
+
|
|
93
105
|
```javascript
|
|
94
|
-
|
|
106
|
+
popup.open({
|
|
107
|
+
id: 'myModal',
|
|
108
|
+
name: 'My Modal',
|
|
109
|
+
body: '<p>Your content here</p>',
|
|
110
|
+
width: 450,
|
|
111
|
+
height: 350,
|
|
112
|
+
buttons: {
|
|
113
|
+
confirm: { text: "OK", cb: () => {} },
|
|
114
|
+
cancel: { text: "Cancel", cb: () => {} }
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Or using the global alias:
|
|
119
|
+
popup.open({
|
|
95
120
|
id: 'myModal',
|
|
96
121
|
name: 'My Modal',
|
|
97
122
|
body: '<p>Your content here</p>',
|
|
@@ -109,7 +134,7 @@ layerpro.popup.open({
|
|
|
109
134
|
In a React environment, you can pass React components directly:
|
|
110
135
|
|
|
111
136
|
```jsx
|
|
112
|
-
|
|
137
|
+
popup.open({
|
|
113
138
|
id: 'reactModal',
|
|
114
139
|
name: 'React Modal',
|
|
115
140
|
body: <MyComponent />, // React element
|
|
@@ -226,15 +251,15 @@ message("Done!"); // LayerPro message
|
|
|
226
251
|
|
|
227
252
|
| Method | Description |
|
|
228
253
|
|--------|-------------|
|
|
229
|
-
| `
|
|
230
|
-
| `
|
|
231
|
-
| `
|
|
232
|
-
| `
|
|
233
|
-
| `
|
|
234
|
-
| `
|
|
235
|
-
| `
|
|
236
|
-
| `
|
|
237
|
-
| `
|
|
254
|
+
| `popup.open(props)` | Open a modal; returns the props. Re-opens a same-id window to front + refreshes body. |
|
|
255
|
+
| `popup.close(id)` | Close (and unmount) a modal. |
|
|
256
|
+
| `popup.center(id, offset?)` | Center a modal in the viewport; optional pixel offset |
|
|
257
|
+
| `popup.maximize(props)` | Toggle maximize (pure CSS) |
|
|
258
|
+
| `popup.iconize(id)` | Toggle minimize to the dock |
|
|
259
|
+
| `popup.index(id)` | Bring a modal to the front (select) |
|
|
260
|
+
| `popup.zIndex()` | Get the next z-index counter value |
|
|
261
|
+
| `popup.movable(props)` | Enable dragging |
|
|
262
|
+
| `popup.resizable(props)` | Enable resizing |
|
|
238
263
|
| `layerpro.noGlobals()` | Restore native `alert`/`confirm`/`prompt`; remove `message` |
|
|
239
264
|
|
|
240
265
|
---
|
|
@@ -271,13 +296,13 @@ properties, so theming needs no `!important` or `[class^=popup_…]` selectors:
|
|
|
271
296
|
|
|
272
297
|
| Method | Description |
|
|
273
298
|
|--------|-------------|
|
|
274
|
-
| `
|
|
275
|
-
| `
|
|
276
|
-
| `
|
|
277
|
-
| `
|
|
278
|
-
| `
|
|
279
|
-
| `
|
|
280
|
-
| `
|
|
299
|
+
| `popup.open(props)` | Open a modal |
|
|
300
|
+
| `popup.close(id)` | Close a modal |
|
|
301
|
+
| `popup.center(id)` | Center modal |
|
|
302
|
+
| `popup.maximize(id)` | Maximize modal |
|
|
303
|
+
| `popup.iconize(id)` | Minimize to dock |
|
|
304
|
+
| `popup.movable(id)` | Enable drag |
|
|
305
|
+
| `popup.resizable(id)` | Enable resize |
|
|
281
306
|
|
|
282
307
|
---
|
|
283
308
|
|
package/index.cjs
CHANGED
|
@@ -34,7 +34,7 @@ Object.defineProperty(i, "credits", {
|
|
|
34
34
|
configurable: !1
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
var n = new WeakMap, s = new WeakMap, p = e => "string" == typeof e ? document.querySelector(e) ?? document : e instanceof HTMLElement ? e : document, r = e => e ? e.split(/\s+/).filter(e => e.length > 0) : [], a = new Set([ "opacity", "zindex", "z-index", "fontweight", "font-weight", "lineheight", "line-height", "zoom", "flex", "flexgrow", "flex-grow", "flexshrink", "flex-shrink", "order", "gridcolumn", "grid-column", "gridrow", "grid-row", "columncount", "column-count", "fontsizeadjust", "font-size-adjust", "appearance" ]),
|
|
37
|
+
var n = new WeakMap, s = new WeakMap, p = e => "string" == typeof e ? document.querySelector(e) ?? document : e instanceof HTMLElement ? e : document, r = e => e ? e.split(/\s+/).filter(e => e.length > 0) : [], a = new Set([ "opacity", "zindex", "z-index", "fontweight", "font-weight", "lineheight", "line-height", "zoom", "flex", "flexgrow", "flex-grow", "flexshrink", "flex-shrink", "order", "gridcolumn", "grid-column", "gridrow", "grid-row", "columncount", "column-count", "fontsizeadjust", "font-size-adjust", "appearance" ]), l = (e, t) => "number" != typeof t || a.has(e.toLowerCase()) ? String(t) : `${t}px`, c = (e, t, o, i) => {
|
|
38
38
|
const s = e => o(e), p = i?.ns ? `${t}.${i.ns}` : t;
|
|
39
39
|
e.addEventListener(t, s, i);
|
|
40
40
|
let r = n.get(e);
|
|
@@ -76,7 +76,7 @@ var n = new WeakMap, s = new WeakMap, p = e => "string" == typeof e ? document.q
|
|
|
76
76
|
return this.el.textContent = e, this;
|
|
77
77
|
}
|
|
78
78
|
css(e, t) {
|
|
79
|
-
if ("object" == typeof e && null !== e) for (const [t, o] of Object.entries(e)) this.el.style.setProperty(t.replace(/[A-Z]/g, e => `-${e.toLowerCase()}`),
|
|
79
|
+
if ("object" == typeof e && null !== e) for (const [t, o] of Object.entries(e)) this.el.style.setProperty(t.replace(/[A-Z]/g, e => `-${e.toLowerCase()}`), l(t, o)); else this.el.style.setProperty(e.replace(/[A-Z]/g, e => `-${e.toLowerCase()}`), l(e, t));
|
|
80
80
|
return this;
|
|
81
81
|
}
|
|
82
82
|
addClass(e) {
|
|
@@ -125,7 +125,7 @@ var n = new WeakMap, s = new WeakMap, p = e => "string" == typeof e ? document.q
|
|
|
125
125
|
return this.el.style.display = "none" === this.el.style.display ? "" : "none", this;
|
|
126
126
|
}
|
|
127
127
|
on(e, t, o) {
|
|
128
|
-
return
|
|
128
|
+
return c(this.el, e, t, o), this;
|
|
129
129
|
}
|
|
130
130
|
off(e, t) {
|
|
131
131
|
return d(this.el, e, t), this;
|
|
@@ -189,7 +189,7 @@ var n = new WeakMap, s = new WeakMap, p = e => "string" == typeof e ? document.q
|
|
|
189
189
|
let n = 200, s = o;
|
|
190
190
|
"function" == typeof t ? s = t : n = t;
|
|
191
191
|
const p = Object.keys(e), r = {};
|
|
192
|
-
for (const t of p) r[t] =
|
|
192
|
+
for (const t of p) r[t] = l(t, e[t]);
|
|
193
193
|
return i.style.transition = "none", i.offsetWidth, i.style.transition = `${p.join(", ")} ${n}ms ease`,
|
|
194
194
|
Object.assign(i.style, r), this.finishTransition(n, () => {
|
|
195
195
|
i.style.transition = "", s?.();
|
|
@@ -223,14 +223,14 @@ var m = e => {
|
|
|
223
223
|
return new u(o);
|
|
224
224
|
}, b = {
|
|
225
225
|
on(e, t, o) {
|
|
226
|
-
|
|
226
|
+
c(document, e, t, o);
|
|
227
227
|
},
|
|
228
228
|
off(e, t) {
|
|
229
229
|
d(document, e, t);
|
|
230
230
|
}
|
|
231
231
|
}, _ = {
|
|
232
232
|
on(e, t, o) {
|
|
233
|
-
|
|
233
|
+
c(window, e, t, o);
|
|
234
234
|
},
|
|
235
235
|
off(e, t) {
|
|
236
236
|
d(window, e, t);
|
|
@@ -281,7 +281,7 @@ var m = e => {
|
|
|
281
281
|
});
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
|
-
}, k = () => "undefined" != typeof window && window.matchMedia("(max-width: 1024px)").matches,
|
|
284
|
+
}, k = () => "undefined" != typeof window && window.matchMedia("(max-width: 1024px)").matches, T = () => {
|
|
285
285
|
if (!0 === window.__FORCE_TOUCH_MODE__) return "touch";
|
|
286
286
|
const e = (() => {
|
|
287
287
|
if ("undefined" == typeof navigator) return !1;
|
|
@@ -289,12 +289,12 @@ var m = e => {
|
|
|
289
289
|
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(e);
|
|
290
290
|
})() || k();
|
|
291
291
|
return ("ontouchstart" in window || navigator.maxTouchPoints > 0) && e ? "touch" : "mouse";
|
|
292
|
-
},
|
|
292
|
+
}, $ = T(), E = !k(), C = null;
|
|
293
293
|
|
|
294
294
|
if ("undefined" != typeof window) {
|
|
295
295
|
const e = window.matchMedia("(max-width: 1024px)"), t = () => {
|
|
296
|
-
const e =
|
|
297
|
-
|
|
296
|
+
const e = T(), t = $, o = !k();
|
|
297
|
+
$ = e, E !== o && (E = o, C && C(e, t));
|
|
298
298
|
};
|
|
299
299
|
let o;
|
|
300
300
|
e.addListener ? e.addListener(t) : e.addEventListener("change", t), window.addEventListener("resize", () => {
|
|
@@ -302,10 +302,10 @@ if ("undefined" != typeof window) {
|
|
|
302
302
|
});
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
-
var L = e => void 0 !== e.clientX ? e.clientX : e.touches && e.touches.length > 0 ? e.touches[0].clientX : e.clientX, M = e => void 0 !== e.clientY ? e.clientY : e.touches && e.touches.length > 0 ? e.touches[0].clientY : e.clientY, S = 250, N = 150, O = !1, I = 1e3, A = !1,
|
|
305
|
+
var L = e => void 0 !== e.clientX ? e.clientX : e.touches && e.touches.length > 0 ? e.touches[0].clientX : e.clientX, M = e => void 0 !== e.clientY ? e.clientY : e.touches && e.touches.length > 0 ? e.touches[0].clientY : e.clientY, S = 250, N = 150, O = !1, I = 1e3, A = !1, P = 0, H = 0, j = 0, W = 0, R = 0, D = 0, q = 0, B = 0, X = 0, Y = new Map, U = new Map, K = () => h("body"), F = e => "object" == typeof e && null !== e ? e.id : e, Z = {
|
|
306
306
|
open: e => {
|
|
307
307
|
if (!e) return e;
|
|
308
|
-
e.id = e.id ?? "popup_" + ++
|
|
308
|
+
e.id = e.id ?? "popup_" + ++P, e.body = e.body ?? "", e.class = e.class ?? "", e.width = e.width ?? 340,
|
|
309
309
|
e.height = e.height ?? 220, e.minWidth = e.minWidth ?? 340, e.minHeight = e.minHeight ?? 220,
|
|
310
310
|
e.name = e.name ?? "popUp_" + e.id, e.source = e.source ?? null, e.icon = e.icon ?? null,
|
|
311
311
|
e.iconize = e.iconize ?? null, e.maximize = e.maximize ?? null, e.isMaximize = e.isMaximize ?? null,
|
|
@@ -565,21 +565,21 @@ var L = e => void 0 !== e.clientX ? e.clientX : e.touches && e.touches.length >
|
|
|
565
565
|
if (!1 === e.movable) return;
|
|
566
566
|
const t = F(e), o = String(t), i = h(".popup_overflow_" + t, "#popup"), n = i ? h(".popup_drag_" + t, i.el) : null, s = i ? h(".popup_body_" + t, i.el) : null;
|
|
567
567
|
i?.css("touch-action", "none");
|
|
568
|
-
let p = 0, r = 0, a = 0,
|
|
569
|
-
const
|
|
568
|
+
let p = 0, r = 0, a = 0, l = 0;
|
|
569
|
+
const c = e => {
|
|
570
570
|
e.preventDefault();
|
|
571
571
|
const t = L(e), o = M(e);
|
|
572
|
-
p = a - t, r =
|
|
572
|
+
p = a - t, r = l - o, a = t, l = o, Z.checkArea(e)[1] < Z.checkArea(e)[4] && 1 === Math.sign(Z.checkArea(e)[1]) && i?.css("top", i.el.offsetTop - r),
|
|
573
573
|
Z.checkArea(e)[0] < Z.checkArea(e)[5] && 1 === Math.sign(Z.checkArea(e)[0]) && i?.css("left", i.el.offsetLeft - p);
|
|
574
574
|
}, d = () => {
|
|
575
575
|
const e = {
|
|
576
576
|
passive: !1
|
|
577
577
|
};
|
|
578
|
-
document.removeEventListener("pointermove",
|
|
578
|
+
document.removeEventListener("pointermove", c, e), document.removeEventListener("pointerup", d, e),
|
|
579
579
|
Y.delete(o), s?.css("pointer-events", "auto"), Z.vfx(i, !0);
|
|
580
580
|
};
|
|
581
581
|
Y.set(o, {
|
|
582
|
-
move:
|
|
582
|
+
move: c,
|
|
583
583
|
up: d
|
|
584
584
|
});
|
|
585
585
|
n?.el.addEventListener("pointerdown", e => {
|
|
@@ -591,11 +591,11 @@ var L = e => void 0 !== e.clientX ? e.clientX : e.touches && e.touches.length >
|
|
|
591
591
|
layerpro.popup.maximize(e);
|
|
592
592
|
});
|
|
593
593
|
const u = e => {
|
|
594
|
-
a = L(e),
|
|
594
|
+
a = L(e), l = M(e);
|
|
595
595
|
const t = {
|
|
596
596
|
passive: !1
|
|
597
597
|
};
|
|
598
|
-
document.addEventListener("pointermove",
|
|
598
|
+
document.addEventListener("pointermove", c, t), document.addEventListener("pointerup", d, t);
|
|
599
599
|
};
|
|
600
600
|
},
|
|
601
601
|
resizable: e => {
|
|
@@ -622,25 +622,25 @@ var L = e => void 0 !== e.clientX ? e.clientX : e.touches && e.touches.length >
|
|
|
622
622
|
const p = L(e), r = M(e), a = [ p - _.scrollLeft(), r - _.scrollTop() ];
|
|
623
623
|
o.minWidth, K()?.css("pointer-events", "none"), n?.css("pointer-events", "none"),
|
|
624
624
|
Z.vfx(n, !1);
|
|
625
|
-
const
|
|
625
|
+
const l = e => {
|
|
626
626
|
Z.doRes(e, t);
|
|
627
|
-
},
|
|
627
|
+
}, c = () => {
|
|
628
628
|
Z.stopRes(t, s);
|
|
629
629
|
}, d = U.get(s) || {};
|
|
630
|
-
d.move =
|
|
630
|
+
d.move = l, d.up = c, U.set(s, d);
|
|
631
631
|
const f = {
|
|
632
632
|
passive: !1
|
|
633
633
|
};
|
|
634
|
-
document.addEventListener("pointermove",
|
|
635
|
-
|
|
634
|
+
document.addEventListener("pointermove", l, f), document.addEventListener("pointerup", c, f),
|
|
635
|
+
H = a[0], j = a[1], W = n?.width() ?? 0, R = n?.height() ?? 0, D = n?.position().left ?? 0,
|
|
636
636
|
q = n?.position().top ?? 0, B = q + R + 1, X = D + W + 1, O = t;
|
|
637
637
|
},
|
|
638
638
|
doRes: (e, t) => {
|
|
639
639
|
dispatchEvent(new Event("layerProResize"));
|
|
640
640
|
const o = t instanceof HTMLElement ? new u(t) : h(t), i = o?.parent(), n = L(e), s = M(e), p = [ n - _.scrollLeft(), s - _.scrollTop() ];
|
|
641
641
|
if (t === O) {
|
|
642
|
-
let t = W + p[0] -
|
|
643
|
-
const s = W - p[0] +
|
|
642
|
+
let t = W + p[0] - H, n = R + p[1] - j;
|
|
643
|
+
const s = W - p[0] + H, r = R - p[1] + j;
|
|
644
644
|
t <= 0 && (t = 0), n <= 0 && (n = 0), Z.checkArea(e)[1] < Z.checkArea(e)[4] && 1 === Math.sign(Z.checkArea(e)[1]) && o?.hasClass("resize_0") && (i && i.height() <= N && r > N && i.css({
|
|
645
645
|
height: Number(N + 1)
|
|
646
646
|
}), i && i.height() > N && N <= r && i.css({
|
|
@@ -744,6 +744,8 @@ Object.defineProperty(layerpro, "popup", {
|
|
|
744
744
|
value: Z,
|
|
745
745
|
writable: !1,
|
|
746
746
|
configurable: !1
|
|
747
|
+
}), globalThis.popup = Z, Object.defineProperty(window, "popup", {
|
|
748
|
+
enumerable: !1
|
|
747
749
|
});
|
|
748
750
|
|
|
749
751
|
var G = {
|
package/index.js
CHANGED
|
@@ -36,7 +36,7 @@ Object.defineProperty(i, "credits", {
|
|
|
36
36
|
configurable: !1
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
var n = new WeakMap, s = new WeakMap, p = e => "string" == typeof e ? document.querySelector(e) ?? document : e instanceof HTMLElement ? e : document, r = e => e ? e.split(/\s+/).filter(e => e.length > 0) : [], a = new Set([ "opacity", "zindex", "z-index", "fontweight", "font-weight", "lineheight", "line-height", "zoom", "flex", "flexgrow", "flex-grow", "flexshrink", "flex-shrink", "order", "gridcolumn", "grid-column", "gridrow", "grid-row", "columncount", "column-count", "fontsizeadjust", "font-size-adjust", "appearance" ]),
|
|
39
|
+
var n = new WeakMap, s = new WeakMap, p = e => "string" == typeof e ? document.querySelector(e) ?? document : e instanceof HTMLElement ? e : document, r = e => e ? e.split(/\s+/).filter(e => e.length > 0) : [], a = new Set([ "opacity", "zindex", "z-index", "fontweight", "font-weight", "lineheight", "line-height", "zoom", "flex", "flexgrow", "flex-grow", "flexshrink", "flex-shrink", "order", "gridcolumn", "grid-column", "gridrow", "grid-row", "columncount", "column-count", "fontsizeadjust", "font-size-adjust", "appearance" ]), l = (e, t) => "number" != typeof t || a.has(e.toLowerCase()) ? String(t) : `${t}px`, c = (e, t, o, i) => {
|
|
40
40
|
const s = e => o(e), p = i?.ns ? `${t}.${i.ns}` : t;
|
|
41
41
|
e.addEventListener(t, s, i);
|
|
42
42
|
let r = n.get(e);
|
|
@@ -78,7 +78,7 @@ var n = new WeakMap, s = new WeakMap, p = e => "string" == typeof e ? document.q
|
|
|
78
78
|
return this.el.textContent = e, this;
|
|
79
79
|
}
|
|
80
80
|
css(e, t) {
|
|
81
|
-
if ("object" == typeof e && null !== e) for (const [t, o] of Object.entries(e)) this.el.style.setProperty(t.replace(/[A-Z]/g, e => `-${e.toLowerCase()}`),
|
|
81
|
+
if ("object" == typeof e && null !== e) for (const [t, o] of Object.entries(e)) this.el.style.setProperty(t.replace(/[A-Z]/g, e => `-${e.toLowerCase()}`), l(t, o)); else this.el.style.setProperty(e.replace(/[A-Z]/g, e => `-${e.toLowerCase()}`), l(e, t));
|
|
82
82
|
return this;
|
|
83
83
|
}
|
|
84
84
|
addClass(e) {
|
|
@@ -127,7 +127,7 @@ var n = new WeakMap, s = new WeakMap, p = e => "string" == typeof e ? document.q
|
|
|
127
127
|
return this.el.style.display = "none" === this.el.style.display ? "" : "none", this;
|
|
128
128
|
}
|
|
129
129
|
on(e, t, o) {
|
|
130
|
-
return
|
|
130
|
+
return c(this.el, e, t, o), this;
|
|
131
131
|
}
|
|
132
132
|
off(e, t) {
|
|
133
133
|
return d(this.el, e, t), this;
|
|
@@ -191,7 +191,7 @@ var n = new WeakMap, s = new WeakMap, p = e => "string" == typeof e ? document.q
|
|
|
191
191
|
let n = 200, s = o;
|
|
192
192
|
"function" == typeof t ? s = t : n = t;
|
|
193
193
|
const p = Object.keys(e), r = {};
|
|
194
|
-
for (const t of p) r[t] =
|
|
194
|
+
for (const t of p) r[t] = l(t, e[t]);
|
|
195
195
|
return i.style.transition = "none", i.offsetWidth, i.style.transition = `${p.join(", ")} ${n}ms ease`,
|
|
196
196
|
Object.assign(i.style, r), this.finishTransition(n, () => {
|
|
197
197
|
i.style.transition = "", s?.();
|
|
@@ -225,14 +225,14 @@ var m = e => {
|
|
|
225
225
|
return new u(o);
|
|
226
226
|
}, b = {
|
|
227
227
|
on(e, t, o) {
|
|
228
|
-
|
|
228
|
+
c(document, e, t, o);
|
|
229
229
|
},
|
|
230
230
|
off(e, t) {
|
|
231
231
|
d(document, e, t);
|
|
232
232
|
}
|
|
233
233
|
}, _ = {
|
|
234
234
|
on(e, t, o) {
|
|
235
|
-
|
|
235
|
+
c(window, e, t, o);
|
|
236
236
|
},
|
|
237
237
|
off(e, t) {
|
|
238
238
|
d(window, e, t);
|
|
@@ -283,7 +283,7 @@ var m = e => {
|
|
|
283
283
|
});
|
|
284
284
|
}
|
|
285
285
|
}
|
|
286
|
-
}, k = () => "undefined" != typeof window && window.matchMedia("(max-width: 1024px)").matches,
|
|
286
|
+
}, k = () => "undefined" != typeof window && window.matchMedia("(max-width: 1024px)").matches, T = () => {
|
|
287
287
|
if (!0 === window.__FORCE_TOUCH_MODE__) return "touch";
|
|
288
288
|
const e = (() => {
|
|
289
289
|
if ("undefined" == typeof navigator) return !1;
|
|
@@ -291,12 +291,12 @@ var m = e => {
|
|
|
291
291
|
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(e);
|
|
292
292
|
})() || k();
|
|
293
293
|
return ("ontouchstart" in window || navigator.maxTouchPoints > 0) && e ? "touch" : "mouse";
|
|
294
|
-
},
|
|
294
|
+
}, $ = T(), E = !k(), C = null;
|
|
295
295
|
|
|
296
296
|
if ("undefined" != typeof window) {
|
|
297
297
|
const e = window.matchMedia("(max-width: 1024px)"), t = () => {
|
|
298
|
-
const e =
|
|
299
|
-
|
|
298
|
+
const e = T(), t = $, o = !k();
|
|
299
|
+
$ = e, E !== o && (E = o, C && C(e, t));
|
|
300
300
|
};
|
|
301
301
|
let o;
|
|
302
302
|
e.addListener ? e.addListener(t) : e.addEventListener("change", t), window.addEventListener("resize", () => {
|
|
@@ -304,10 +304,10 @@ if ("undefined" != typeof window) {
|
|
|
304
304
|
});
|
|
305
305
|
}
|
|
306
306
|
|
|
307
|
-
var L = e => void 0 !== e.clientX ? e.clientX : e.touches && e.touches.length > 0 ? e.touches[0].clientX : e.clientX, M = e => void 0 !== e.clientY ? e.clientY : e.touches && e.touches.length > 0 ? e.touches[0].clientY : e.clientY, S = 250, N = 150, O = !1, I = 1e3, A = !1,
|
|
307
|
+
var L = e => void 0 !== e.clientX ? e.clientX : e.touches && e.touches.length > 0 ? e.touches[0].clientX : e.clientX, M = e => void 0 !== e.clientY ? e.clientY : e.touches && e.touches.length > 0 ? e.touches[0].clientY : e.clientY, S = 250, N = 150, O = !1, I = 1e3, A = !1, P = 0, H = 0, j = 0, W = 0, R = 0, D = 0, q = 0, B = 0, X = 0, Y = new Map, U = new Map, K = () => h("body"), F = e => "object" == typeof e && null !== e ? e.id : e, Z = {
|
|
308
308
|
open: e => {
|
|
309
309
|
if (!e) return e;
|
|
310
|
-
e.id = e.id ?? "popup_" + ++
|
|
310
|
+
e.id = e.id ?? "popup_" + ++P, e.body = e.body ?? "", e.class = e.class ?? "", e.width = e.width ?? 340,
|
|
311
311
|
e.height = e.height ?? 220, e.minWidth = e.minWidth ?? 340, e.minHeight = e.minHeight ?? 220,
|
|
312
312
|
e.name = e.name ?? "popUp_" + e.id, e.source = e.source ?? null, e.icon = e.icon ?? null,
|
|
313
313
|
e.iconize = e.iconize ?? null, e.maximize = e.maximize ?? null, e.isMaximize = e.isMaximize ?? null,
|
|
@@ -567,21 +567,21 @@ var L = e => void 0 !== e.clientX ? e.clientX : e.touches && e.touches.length >
|
|
|
567
567
|
if (!1 === e.movable) return;
|
|
568
568
|
const t = F(e), o = String(t), i = h(".popup_overflow_" + t, "#popup"), n = i ? h(".popup_drag_" + t, i.el) : null, s = i ? h(".popup_body_" + t, i.el) : null;
|
|
569
569
|
i?.css("touch-action", "none");
|
|
570
|
-
let p = 0, r = 0, a = 0,
|
|
571
|
-
const
|
|
570
|
+
let p = 0, r = 0, a = 0, l = 0;
|
|
571
|
+
const c = e => {
|
|
572
572
|
e.preventDefault();
|
|
573
573
|
const t = L(e), o = M(e);
|
|
574
|
-
p = a - t, r =
|
|
574
|
+
p = a - t, r = l - o, a = t, l = o, Z.checkArea(e)[1] < Z.checkArea(e)[4] && 1 === Math.sign(Z.checkArea(e)[1]) && i?.css("top", i.el.offsetTop - r),
|
|
575
575
|
Z.checkArea(e)[0] < Z.checkArea(e)[5] && 1 === Math.sign(Z.checkArea(e)[0]) && i?.css("left", i.el.offsetLeft - p);
|
|
576
576
|
}, d = () => {
|
|
577
577
|
const e = {
|
|
578
578
|
passive: !1
|
|
579
579
|
};
|
|
580
|
-
document.removeEventListener("pointermove",
|
|
580
|
+
document.removeEventListener("pointermove", c, e), document.removeEventListener("pointerup", d, e),
|
|
581
581
|
Y.delete(o), s?.css("pointer-events", "auto"), Z.vfx(i, !0);
|
|
582
582
|
};
|
|
583
583
|
Y.set(o, {
|
|
584
|
-
move:
|
|
584
|
+
move: c,
|
|
585
585
|
up: d
|
|
586
586
|
});
|
|
587
587
|
n?.el.addEventListener("pointerdown", e => {
|
|
@@ -593,11 +593,11 @@ var L = e => void 0 !== e.clientX ? e.clientX : e.touches && e.touches.length >
|
|
|
593
593
|
layerpro.popup.maximize(e);
|
|
594
594
|
});
|
|
595
595
|
const u = e => {
|
|
596
|
-
a = L(e),
|
|
596
|
+
a = L(e), l = M(e);
|
|
597
597
|
const t = {
|
|
598
598
|
passive: !1
|
|
599
599
|
};
|
|
600
|
-
document.addEventListener("pointermove",
|
|
600
|
+
document.addEventListener("pointermove", c, t), document.addEventListener("pointerup", d, t);
|
|
601
601
|
};
|
|
602
602
|
},
|
|
603
603
|
resizable: e => {
|
|
@@ -624,25 +624,25 @@ var L = e => void 0 !== e.clientX ? e.clientX : e.touches && e.touches.length >
|
|
|
624
624
|
const p = L(e), r = M(e), a = [ p - _.scrollLeft(), r - _.scrollTop() ];
|
|
625
625
|
o.minWidth, K()?.css("pointer-events", "none"), n?.css("pointer-events", "none"),
|
|
626
626
|
Z.vfx(n, !1);
|
|
627
|
-
const
|
|
627
|
+
const l = e => {
|
|
628
628
|
Z.doRes(e, t);
|
|
629
|
-
},
|
|
629
|
+
}, c = () => {
|
|
630
630
|
Z.stopRes(t, s);
|
|
631
631
|
}, d = U.get(s) || {};
|
|
632
|
-
d.move =
|
|
632
|
+
d.move = l, d.up = c, U.set(s, d);
|
|
633
633
|
const f = {
|
|
634
634
|
passive: !1
|
|
635
635
|
};
|
|
636
|
-
document.addEventListener("pointermove",
|
|
637
|
-
|
|
636
|
+
document.addEventListener("pointermove", l, f), document.addEventListener("pointerup", c, f),
|
|
637
|
+
H = a[0], j = a[1], W = n?.width() ?? 0, R = n?.height() ?? 0, D = n?.position().left ?? 0,
|
|
638
638
|
q = n?.position().top ?? 0, B = q + R + 1, X = D + W + 1, O = t;
|
|
639
639
|
},
|
|
640
640
|
doRes: (e, t) => {
|
|
641
641
|
dispatchEvent(new Event("layerProResize"));
|
|
642
642
|
const o = t instanceof HTMLElement ? new u(t) : h(t), i = o?.parent(), n = L(e), s = M(e), p = [ n - _.scrollLeft(), s - _.scrollTop() ];
|
|
643
643
|
if (t === O) {
|
|
644
|
-
let t = W + p[0] -
|
|
645
|
-
const s = W - p[0] +
|
|
644
|
+
let t = W + p[0] - H, n = R + p[1] - j;
|
|
645
|
+
const s = W - p[0] + H, r = R - p[1] + j;
|
|
646
646
|
t <= 0 && (t = 0), n <= 0 && (n = 0), Z.checkArea(e)[1] < Z.checkArea(e)[4] && 1 === Math.sign(Z.checkArea(e)[1]) && o?.hasClass("resize_0") && (i && i.height() <= N && r > N && i.css({
|
|
647
647
|
height: Number(N + 1)
|
|
648
648
|
}), i && i.height() > N && N <= r && i.css({
|
|
@@ -746,6 +746,8 @@ Object.defineProperty(layerpro, "popup", {
|
|
|
746
746
|
value: Z,
|
|
747
747
|
writable: !1,
|
|
748
748
|
configurable: !1
|
|
749
|
+
}), globalThis.popup = Z, Object.defineProperty(window, "popup", {
|
|
750
|
+
enumerable: !1
|
|
749
751
|
});
|
|
750
752
|
|
|
751
753
|
var G = {
|
package/markdown/GUIDE.md
CHANGED
|
@@ -1,367 +1,367 @@
|
|
|
1
|
-
# LayerPro Guide
|
|
2
|
-
|
|
3
|
-
> A practical, example-driven guide to LayerPro — the real custom modals
|
|
4
|
-
> (alert, confirm, prompt, message) and advanced popups for the browser.
|
|
5
|
-
|
|
6
|
-
LayerPro is **dependency-free**: it no longer uses jQuery. All DOM work is done
|
|
7
|
-
with small, chainable vanilla helpers. React and react-dom are the only
|
|
8
|
-
external runtime dependencies, and they are used **only** to render the modal
|
|
9
|
-
body when you pass a React element.
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Table of Contents
|
|
14
|
-
|
|
15
|
-
1. [Installation](#installation)
|
|
16
|
-
2. [Quick Start](#quick-start)
|
|
17
|
-
3. [Basic Modals](#basic-modals)
|
|
18
|
-
4. [Custom Popups](#custom-popups)
|
|
19
|
-
5. [Options Reference](#options-reference)
|
|
20
|
-
6. [Dock & Taskbar](#dock--taskbar)
|
|
21
|
-
7. [Maximize & Minimize](#maximize--minimize)
|
|
22
|
-
8. [Dragging & Resizing](#dragging--resizing)
|
|
23
|
-
9. [React Body](#react-body)
|
|
24
|
-
10. [Selection & z-index](#selection--z-index)
|
|
25
|
-
11. [API Methods](#api-methods)
|
|
26
|
-
12. [Notes & Migration](#notes--migration)
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Installation
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
npm install layerpro
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Or drop it straight into HTML (UMD build):
|
|
37
|
-
|
|
38
|
-
```html
|
|
39
|
-
<script src="https://cdn.jsdelivr.net/npm/layerpro"></script>
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## Quick Start
|
|
45
|
-
|
|
46
|
-
Import LayerPro once at your app entry point. It overrides the global
|
|
47
|
-
`alert`, `confirm`, `prompt`, and exposes `message` and `layerpro`:
|
|
48
|
-
|
|
49
|
-
```javascript
|
|
50
|
-
import "layerpro";
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
That single import is enough — `window.layerpro` becomes available and the
|
|
54
|
-
global `alert`/`confirm`/`prompt` are replaced, and a `message` global is added.
|
|
55
|
-
|
|
56
|
-
> **⚠️ Global override contract:** the overridden `confirm()` no longer returns a
|
|
57
|
-
> `boolean` and `prompt()` no longer returns a `string` — they are callback-based
|
|
58
|
-
> and return `undefined`. If your codebase (or a third-party dependency) relies on
|
|
59
|
-
> the native synchronous return values, call `layerpro.noGlobals()` right after
|
|
60
|
-
> importing to restore the originals:
|
|
61
|
-
>
|
|
62
|
-
> ```javascript
|
|
63
|
-
> import "layerpro";
|
|
64
|
-
> layerpro.noGlobals(); // restores native alert/confirm/prompt, drops `message`
|
|
65
|
-
> ```
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
|
|
69
|
-
## Basic Modals
|
|
70
|
-
|
|
71
|
-
```javascript
|
|
72
|
-
// Simple alert
|
|
73
|
-
alert("Hello World!");
|
|
74
|
-
|
|
75
|
-
// Confirm with YES / NO callbacks
|
|
76
|
-
confirm(
|
|
77
|
-
"Are you sure?",
|
|
78
|
-
() => console.debug("User clicked YES"),
|
|
79
|
-
() => console.debug("User clicked NO")
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
// Prompt with the typed value
|
|
83
|
-
prompt("What is your name?", (name) => {
|
|
84
|
-
console.debug("User entered:", name);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// Plain message (auto-styled info box)
|
|
88
|
-
message("Operation complete!", () => console.debug("message closed"));
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
> The global functions keep the same signatures you already know, so legacy
|
|
92
|
-
> code keeps working.
|
|
93
|
-
|
|
94
|
-
---
|
|
95
|
-
|
|
96
|
-
## Custom Popups
|
|
97
|
-
|
|
98
|
-
Use `layerpro.popup.open(props)` for full control.
|
|
99
|
-
|
|
100
|
-
```javascript
|
|
101
|
-
layerpro.popup.open({
|
|
102
|
-
id: "myModal",
|
|
103
|
-
name: "My Modal",
|
|
104
|
-
body: "<p>Your <b>content</b> here</p>",
|
|
105
|
-
width: 450,
|
|
106
|
-
height: 350,
|
|
107
|
-
movable: true,
|
|
108
|
-
resizable: true,
|
|
109
|
-
maximize: true,
|
|
110
|
-
iconize: true,
|
|
111
|
-
dockable: true,
|
|
112
|
-
close: true,
|
|
113
|
-
buttons: {
|
|
114
|
-
confirm: { text: "OK", cb: () => layerpro.popup.close("myModal") },
|
|
115
|
-
cancel: { text: "Cancel", cb: () => layerpro.popup.close("myModal") }
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### The `body` parameter
|
|
121
|
-
|
|
122
|
-
| Type | Example |
|
|
123
|
-
|------|---------|
|
|
124
|
-
| Plain text | `body: "Hello"` |
|
|
125
|
-
| HTML string | `body: "<p>Hello</p>"` |
|
|
126
|
-
| React element | `body: <MyComponent />` |
|
|
127
|
-
|
|
128
|
-
> In React, always pass an **element** (`<Component />`), never a call
|
|
129
|
-
> (`Component()`).
|
|
130
|
-
|
|
131
|
-
---
|
|
132
|
-
|
|
133
|
-
## Options Reference
|
|
134
|
-
|
|
135
|
-
```typescript
|
|
136
|
-
{
|
|
137
|
-
id: string, // Unique id (auto-generated as popup_1, popup_2, … if omitted)
|
|
138
|
-
body: any, // text | HTML string | HTMLElement | React element
|
|
139
|
-
name: string, // Title shown in the bar
|
|
140
|
-
icon: string, // Icon glyph (HTML entity, e.g. "⚠") or HTML string
|
|
141
|
-
// (e.g. '<i class="fa fa-star"></i>')
|
|
142
|
-
class: string, // Extra CSS class on the window
|
|
143
|
-
|
|
144
|
-
// Dimensions (defaults: width 340, height 220; minWidth 340, minHeight 220)
|
|
145
|
-
width?: number | string,
|
|
146
|
-
height?: number | string,
|
|
147
|
-
minWidth?: number,
|
|
148
|
-
minHeight?: number,
|
|
149
|
-
maxWidth?: number,
|
|
150
|
-
maxHeight?: number,
|
|
151
|
-
|
|
152
|
-
// Position (numbers are px; strings are applied as-is, e.g. "10%")
|
|
153
|
-
top?: number | string,
|
|
154
|
-
left?: number | string,
|
|
155
|
-
right?: number | string,
|
|
156
|
-
bottom?: number | string,
|
|
157
|
-
center?: boolean, // Center in the viewport (adds a small cascade
|
|
158
|
-
// offset per open window so stacks don't overlap)
|
|
159
|
-
|
|
160
|
-
// Timing
|
|
161
|
-
fadeIn?: number, // open fade duration (ms, default 100)
|
|
162
|
-
fadeOut?: number, // close fade duration (ms, default 100)
|
|
163
|
-
timer?: number, // auto-close after N ms
|
|
164
|
-
|
|
165
|
-
// Behavior flags
|
|
166
|
-
movable?: boolean, // draggable by the title bar
|
|
167
|
-
resizable?: boolean, // resize handles
|
|
168
|
-
maximize?: boolean, // double-click title bar to maximize
|
|
169
|
-
iconize?: boolean, // allow minimize to dock
|
|
170
|
-
dockable?: boolean, // show an icon in the dock bar
|
|
171
|
-
close?: boolean, // show the close button
|
|
172
|
-
raised?: boolean, // alias: modal — show a full-screen overlay that
|
|
173
|
-
modal?: boolean, // blocks pointer events to the page underneath
|
|
174
|
-
}
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
If `top/left/right/bottom` are all `0` (or unset) the popup is auto-centered.
|
|
178
|
-
Pass `center: true` to force centering regardless of the position props.
|
|
179
|
-
|
|
180
|
-
> **`raised` / `modal`** injects a full-viewport overlay (`popup_raised_<id>`)
|
|
181
|
-
> that intercepts every pointer event — the page underneath becomes unclickable
|
|
182
|
-
> until the popup closes. This is modal behavior; both names are accepted.
|
|
183
|
-
|
|
184
|
-
> **Duplicate id** — opening a popup whose `id` already exists brings that window
|
|
185
|
-
> to the front and refreshes its `body`/`buttons` instead of doing nothing.
|
|
186
|
-
|
|
187
|
-
---
|
|
188
|
-
|
|
189
|
-
## Dock & Taskbar
|
|
190
|
-
|
|
191
|
-
When `dockable` and `iconize` are enabled, a minimized popup becomes an icon in
|
|
192
|
-
the bottom dock bar — exactly like an OS taskbar:
|
|
193
|
-
|
|
194
|
-
```javascript
|
|
195
|
-
layerpro.popup.open({
|
|
196
|
-
id: "editor",
|
|
197
|
-
name: "Editor",
|
|
198
|
-
body: "<p>Edit something…</p>",
|
|
199
|
-
dockable: true,
|
|
200
|
-
iconize: true
|
|
201
|
-
});
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
**Dock interactions (taskbar style):**
|
|
205
|
-
|
|
206
|
-
- Click a dock icon of a **minimized** popup → it is restored and focused.
|
|
207
|
-
- Click a dock icon of a popup that is open but **not focused** → it is brought
|
|
208
|
-
to the front.
|
|
209
|
-
- Click a dock icon of the **focused** popup → it is minimized back to the dock.
|
|
210
|
-
|
|
211
|
-
The close `✕` on the dock icon closes the popup completely.
|
|
212
|
-
|
|
213
|
-
---
|
|
214
|
-
|
|
215
|
-
## Maximize & Minimize
|
|
216
|
-
|
|
217
|
-
Maximize is implemented with **pure CSS** (`position: fixed` + `inset`), so the
|
|
218
|
-
popup fills the viewport and follows window resizing automatically — no JS
|
|
219
|
-
resize listeners are involved.
|
|
220
|
-
|
|
221
|
-
```javascript
|
|
222
|
-
layerpro.popup.open({
|
|
223
|
-
id: "viewer",
|
|
224
|
-
name: "Viewer",
|
|
225
|
-
body: "<p>Big content</p>",
|
|
226
|
-
maximize: true,
|
|
227
|
-
iconize: true
|
|
228
|
-
});
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
- **Double-click the title bar** → toggle maximize / restore.
|
|
232
|
-
- **Click the dock icon** of a maximized popup → restore it.
|
|
233
|
-
|
|
234
|
-
Because maximize is CSS-driven, resizing the browser window keeps the maximized
|
|
235
|
-
popup perfectly aligned with no lag.
|
|
236
|
-
|
|
237
|
-
---
|
|
238
|
-
|
|
239
|
-
## Dragging & Resizing
|
|
240
|
-
|
|
241
|
-
Dragging and resizing are **instant**: the CSS `transition` is disabled on the
|
|
242
|
-
popup while you drag a resize handle, so the popup tracks the pointer with no
|
|
243
|
-
lag (especially on the bottom edge).
|
|
244
|
-
|
|
245
|
-
```javascript
|
|
246
|
-
layerpro.popup.open({
|
|
247
|
-
id: "panel",
|
|
248
|
-
name: "Panel",
|
|
249
|
-
body: "<p>Move and resize me</p>",
|
|
250
|
-
movable: true,
|
|
251
|
-
resizable: true
|
|
252
|
-
});
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
- Drag the **title bar** to move.
|
|
256
|
-
- Drag the **edges/corners** to resize.
|
|
257
|
-
- These interactions are disabled automatically while a popup is maximized.
|
|
258
|
-
|
|
259
|
-
---
|
|
260
|
-
|
|
261
|
-
## React Body
|
|
262
|
-
|
|
263
|
-
Pass a React element as `body` and LayerPro mounts it with `react-dom`
|
|
264
|
-
`createRoot` inside the modal:
|
|
265
|
-
|
|
266
|
-
```jsx
|
|
267
|
-
import { useState } from "react";
|
|
268
|
-
|
|
269
|
-
function Counter() {
|
|
270
|
-
const [n, setN] = useState(0);
|
|
271
|
-
return <button onClick={() => setN(n + 1)}>Clicked {n} times</button>;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
layerpro.popup.open({
|
|
275
|
-
id: "reactModal",
|
|
276
|
-
name: "React Modal",
|
|
277
|
-
body: <Counter />,
|
|
278
|
-
width: 400,
|
|
279
|
-
height: 300
|
|
280
|
-
});
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
React state, effects, and context all work normally inside the body.
|
|
284
|
-
|
|
285
|
-
---
|
|
286
|
-
|
|
287
|
-
## Selection & z-index
|
|
288
|
-
|
|
289
|
-
Clicking anywhere on a popup (the body **or** the title bar) brings it to the
|
|
290
|
-
front and gives it the `zHigh` highlight. The dock icon is also marked as
|
|
291
|
-
selected. z-index values are unitless (set as raw numbers, never `px`).
|
|
292
|
-
|
|
293
|
-
```javascript
|
|
294
|
-
// Bring a popup to the front programmatically
|
|
295
|
-
layerpro.popup.index({ id: "myModal" });
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
---
|
|
299
|
-
|
|
300
|
-
## API Methods
|
|
301
|
-
|
|
302
|
-
| Method | Description |
|
|
303
|
-
|--------|-------------|
|
|
304
|
-
| `layerpro.popup.open(props)` | Open a modal; returns the props. Re-opening a same-id window brings it to front + refreshes body |
|
|
305
|
-
| `layerpro.popup.close(id)` | Close (and unmount) a modal |
|
|
306
|
-
| `layerpro.popup.center(id, offset?)` | Center a modal in the viewport; optional pixel offset |
|
|
307
|
-
| `layerpro.popup.maximize(props)` | Toggle maximize (pure CSS) |
|
|
308
|
-
| `layerpro.popup.iconize(id)` | Toggle minimize to the dock |
|
|
309
|
-
| `layerpro.popup.index(id)` | Bring a modal to the front (select) |
|
|
310
|
-
| `layerpro.popup.zIndex()` | Get the next z-index counter value |
|
|
311
|
-
| `layerpro.popup.movable(props)` | Enable dragging |
|
|
312
|
-
| `layerpro.popup.resizable(props)` | Enable resizing |
|
|
313
|
-
| `layerpro.popup.store(element)` | Store a reference (placeholder/extensibility) |
|
|
314
|
-
| `layerpro.popup.cleanupEvents(id)` | Remove dock/button/esc listeners |
|
|
315
|
-
| `layerpro.popup.unmount(id)` | Unmount the React root (memory cleanup) |
|
|
316
|
-
| `layerpro.noGlobals()` | Restore native `alert`/`confirm`/`prompt`; remove `message` |
|
|
317
|
-
|
|
318
|
-
---
|
|
319
|
-
|
|
320
|
-
## Styling & z-index
|
|
321
|
-
|
|
322
|
-
Popup z-index starts from the `--popup-z-index` CSS variable (default `1000`).
|
|
323
|
-
Apps with their own stacking contexts (e.g. a tooltip at `z-index: 100000`) can
|
|
324
|
-
shift the whole stack by overriding the variable:
|
|
325
|
-
|
|
326
|
-
```scss
|
|
327
|
-
:root { --popup-z-index: 100000; }
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
The title bar, window surface, internal area, and body all read from CSS custom
|
|
331
|
-
properties, so theming needs no `!important` and no `[class^=popup_…]` selectors:
|
|
332
|
-
|
|
333
|
-
| Variable | Applies to |
|
|
334
|
-
|----------|-----------|
|
|
335
|
-
| `--bar-background` | title bar |
|
|
336
|
-
| `--bar-selected-background` | active/selected title bar |
|
|
337
|
-
| `--bar-color` | title bar text |
|
|
338
|
-
| `--window-background` | popup surface |
|
|
339
|
-
| `--window-shadow` | popup shadow |
|
|
340
|
-
| `--window-border-radius` | popup border radius |
|
|
341
|
-
| `--internal-background` | body wrapper |
|
|
342
|
-
| `--body-color` | body text color |
|
|
343
|
-
| `--raised-background` | modal overlay |
|
|
344
|
-
| `--popup-z-index` (in root.scss) | base z-index for the stack |
|
|
345
|
-
|
|
346
|
-
Stable class names (`.popup_bar`, `.popup_window`, `.popup_overflow`,
|
|
347
|
-
`.popup_internal`, `.popup_body`, `.popup_drag`, `.popup_icon`, `.popup_option`,
|
|
348
|
-
`.popup_raised`) are emitted alongside the per-id classes so themes can target
|
|
349
|
-
elements without attribute selectors.
|
|
350
|
-
|
|
351
|
-
---
|
|
352
|
-
|
|
353
|
-
## Notes & Migration
|
|
354
|
-
|
|
355
|
-
- **jQuery removed.** LayerPro no longer depends on jQuery. All DOM access uses
|
|
356
|
-
the internal `core/dom.ts` vanilla helper (`lp`, `lpAll`, `lpCreate`, `lpDoc`,
|
|
357
|
-
`lpWin`). Public behavior is unchanged.
|
|
358
|
-
- **React is external.** `react` and `react-dom` must be provided by the host
|
|
359
|
-
app and are used only to render the modal body.
|
|
360
|
-
- **Instant resize / maximize.** Transitions are disabled during resize, and
|
|
361
|
-
maximize is CSS-only, for a snappy, lag-free feel.
|
|
362
|
-
- **Vanilla pages still work.** No framework is required unless you pass a React
|
|
363
|
-
body.
|
|
364
|
-
|
|
365
|
-
---
|
|
366
|
-
|
|
367
|
-
© [Dario Passariello](https://dario.passariello.ca/) — MIT License
|
|
1
|
+
# LayerPro Guide
|
|
2
|
+
|
|
3
|
+
> A practical, example-driven guide to LayerPro — the real custom modals
|
|
4
|
+
> (alert, confirm, prompt, message) and advanced popups for the browser.
|
|
5
|
+
|
|
6
|
+
LayerPro is **dependency-free**: it no longer uses jQuery. All DOM work is done
|
|
7
|
+
with small, chainable vanilla helpers. React and react-dom are the only
|
|
8
|
+
external runtime dependencies, and they are used **only** to render the modal
|
|
9
|
+
body when you pass a React element.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Table of Contents
|
|
14
|
+
|
|
15
|
+
1. [Installation](#installation)
|
|
16
|
+
2. [Quick Start](#quick-start)
|
|
17
|
+
3. [Basic Modals](#basic-modals)
|
|
18
|
+
4. [Custom Popups](#custom-popups)
|
|
19
|
+
5. [Options Reference](#options-reference)
|
|
20
|
+
6. [Dock & Taskbar](#dock--taskbar)
|
|
21
|
+
7. [Maximize & Minimize](#maximize--minimize)
|
|
22
|
+
8. [Dragging & Resizing](#dragging--resizing)
|
|
23
|
+
9. [React Body](#react-body)
|
|
24
|
+
10. [Selection & z-index](#selection--z-index)
|
|
25
|
+
11. [API Methods](#api-methods)
|
|
26
|
+
12. [Notes & Migration](#notes--migration)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install layerpro
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or drop it straight into HTML (UMD build):
|
|
37
|
+
|
|
38
|
+
```html
|
|
39
|
+
<script src="https://cdn.jsdelivr.net/npm/layerpro"></script>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
Import LayerPro once at your app entry point. It overrides the global
|
|
47
|
+
`alert`, `confirm`, `prompt`, and exposes `message` and `layerpro`:
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
import "layerpro";
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
That single import is enough — `window.layerpro` becomes available and the
|
|
54
|
+
global `alert`/`confirm`/`prompt` are replaced, and a `message` global is added.
|
|
55
|
+
|
|
56
|
+
> **⚠️ Global override contract:** the overridden `confirm()` no longer returns a
|
|
57
|
+
> `boolean` and `prompt()` no longer returns a `string` — they are callback-based
|
|
58
|
+
> and return `undefined`. If your codebase (or a third-party dependency) relies on
|
|
59
|
+
> the native synchronous return values, call `layerpro.noGlobals()` right after
|
|
60
|
+
> importing to restore the originals:
|
|
61
|
+
>
|
|
62
|
+
> ```javascript
|
|
63
|
+
> import "layerpro";
|
|
64
|
+
> layerpro.noGlobals(); // restores native alert/confirm/prompt, drops `message`
|
|
65
|
+
> ```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Basic Modals
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
// Simple alert
|
|
73
|
+
alert("Hello World!");
|
|
74
|
+
|
|
75
|
+
// Confirm with YES / NO callbacks
|
|
76
|
+
confirm(
|
|
77
|
+
"Are you sure?",
|
|
78
|
+
() => console.debug("User clicked YES"),
|
|
79
|
+
() => console.debug("User clicked NO")
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// Prompt with the typed value
|
|
83
|
+
prompt("What is your name?", (name) => {
|
|
84
|
+
console.debug("User entered:", name);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Plain message (auto-styled info box)
|
|
88
|
+
message("Operation complete!", () => console.debug("message closed"));
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
> The global functions keep the same signatures you already know, so legacy
|
|
92
|
+
> code keeps working.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Custom Popups
|
|
97
|
+
|
|
98
|
+
Use `layerpro.popup.open(props)` for full control.
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
layerpro.popup.open({
|
|
102
|
+
id: "myModal",
|
|
103
|
+
name: "My Modal",
|
|
104
|
+
body: "<p>Your <b>content</b> here</p>",
|
|
105
|
+
width: 450,
|
|
106
|
+
height: 350,
|
|
107
|
+
movable: true,
|
|
108
|
+
resizable: true,
|
|
109
|
+
maximize: true,
|
|
110
|
+
iconize: true,
|
|
111
|
+
dockable: true,
|
|
112
|
+
close: true,
|
|
113
|
+
buttons: {
|
|
114
|
+
confirm: { text: "OK", cb: () => layerpro.popup.close("myModal") },
|
|
115
|
+
cancel: { text: "Cancel", cb: () => layerpro.popup.close("myModal") }
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### The `body` parameter
|
|
121
|
+
|
|
122
|
+
| Type | Example |
|
|
123
|
+
|------|---------|
|
|
124
|
+
| Plain text | `body: "Hello"` |
|
|
125
|
+
| HTML string | `body: "<p>Hello</p>"` |
|
|
126
|
+
| React element | `body: <MyComponent />` |
|
|
127
|
+
|
|
128
|
+
> In React, always pass an **element** (`<Component />`), never a call
|
|
129
|
+
> (`Component()`).
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Options Reference
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
{
|
|
137
|
+
id: string, // Unique id (auto-generated as popup_1, popup_2, … if omitted)
|
|
138
|
+
body: any, // text | HTML string | HTMLElement | React element
|
|
139
|
+
name: string, // Title shown in the bar
|
|
140
|
+
icon: string, // Icon glyph (HTML entity, e.g. "⚠") or HTML string
|
|
141
|
+
// (e.g. '<i class="fa fa-star"></i>')
|
|
142
|
+
class: string, // Extra CSS class on the window
|
|
143
|
+
|
|
144
|
+
// Dimensions (defaults: width 340, height 220; minWidth 340, minHeight 220)
|
|
145
|
+
width?: number | string,
|
|
146
|
+
height?: number | string,
|
|
147
|
+
minWidth?: number,
|
|
148
|
+
minHeight?: number,
|
|
149
|
+
maxWidth?: number,
|
|
150
|
+
maxHeight?: number,
|
|
151
|
+
|
|
152
|
+
// Position (numbers are px; strings are applied as-is, e.g. "10%")
|
|
153
|
+
top?: number | string,
|
|
154
|
+
left?: number | string,
|
|
155
|
+
right?: number | string,
|
|
156
|
+
bottom?: number | string,
|
|
157
|
+
center?: boolean, // Center in the viewport (adds a small cascade
|
|
158
|
+
// offset per open window so stacks don't overlap)
|
|
159
|
+
|
|
160
|
+
// Timing
|
|
161
|
+
fadeIn?: number, // open fade duration (ms, default 100)
|
|
162
|
+
fadeOut?: number, // close fade duration (ms, default 100)
|
|
163
|
+
timer?: number, // auto-close after N ms
|
|
164
|
+
|
|
165
|
+
// Behavior flags
|
|
166
|
+
movable?: boolean, // draggable by the title bar
|
|
167
|
+
resizable?: boolean, // resize handles
|
|
168
|
+
maximize?: boolean, // double-click title bar to maximize
|
|
169
|
+
iconize?: boolean, // allow minimize to dock
|
|
170
|
+
dockable?: boolean, // show an icon in the dock bar
|
|
171
|
+
close?: boolean, // show the close button
|
|
172
|
+
raised?: boolean, // alias: modal — show a full-screen overlay that
|
|
173
|
+
modal?: boolean, // blocks pointer events to the page underneath
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
If `top/left/right/bottom` are all `0` (or unset) the popup is auto-centered.
|
|
178
|
+
Pass `center: true` to force centering regardless of the position props.
|
|
179
|
+
|
|
180
|
+
> **`raised` / `modal`** injects a full-viewport overlay (`popup_raised_<id>`)
|
|
181
|
+
> that intercepts every pointer event — the page underneath becomes unclickable
|
|
182
|
+
> until the popup closes. This is modal behavior; both names are accepted.
|
|
183
|
+
|
|
184
|
+
> **Duplicate id** — opening a popup whose `id` already exists brings that window
|
|
185
|
+
> to the front and refreshes its `body`/`buttons` instead of doing nothing.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Dock & Taskbar
|
|
190
|
+
|
|
191
|
+
When `dockable` and `iconize` are enabled, a minimized popup becomes an icon in
|
|
192
|
+
the bottom dock bar — exactly like an OS taskbar:
|
|
193
|
+
|
|
194
|
+
```javascript
|
|
195
|
+
layerpro.popup.open({
|
|
196
|
+
id: "editor",
|
|
197
|
+
name: "Editor",
|
|
198
|
+
body: "<p>Edit something…</p>",
|
|
199
|
+
dockable: true,
|
|
200
|
+
iconize: true
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Dock interactions (taskbar style):**
|
|
205
|
+
|
|
206
|
+
- Click a dock icon of a **minimized** popup → it is restored and focused.
|
|
207
|
+
- Click a dock icon of a popup that is open but **not focused** → it is brought
|
|
208
|
+
to the front.
|
|
209
|
+
- Click a dock icon of the **focused** popup → it is minimized back to the dock.
|
|
210
|
+
|
|
211
|
+
The close `✕` on the dock icon closes the popup completely.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Maximize & Minimize
|
|
216
|
+
|
|
217
|
+
Maximize is implemented with **pure CSS** (`position: fixed` + `inset`), so the
|
|
218
|
+
popup fills the viewport and follows window resizing automatically — no JS
|
|
219
|
+
resize listeners are involved.
|
|
220
|
+
|
|
221
|
+
```javascript
|
|
222
|
+
layerpro.popup.open({
|
|
223
|
+
id: "viewer",
|
|
224
|
+
name: "Viewer",
|
|
225
|
+
body: "<p>Big content</p>",
|
|
226
|
+
maximize: true,
|
|
227
|
+
iconize: true
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
- **Double-click the title bar** → toggle maximize / restore.
|
|
232
|
+
- **Click the dock icon** of a maximized popup → restore it.
|
|
233
|
+
|
|
234
|
+
Because maximize is CSS-driven, resizing the browser window keeps the maximized
|
|
235
|
+
popup perfectly aligned with no lag.
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Dragging & Resizing
|
|
240
|
+
|
|
241
|
+
Dragging and resizing are **instant**: the CSS `transition` is disabled on the
|
|
242
|
+
popup while you drag a resize handle, so the popup tracks the pointer with no
|
|
243
|
+
lag (especially on the bottom edge).
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
layerpro.popup.open({
|
|
247
|
+
id: "panel",
|
|
248
|
+
name: "Panel",
|
|
249
|
+
body: "<p>Move and resize me</p>",
|
|
250
|
+
movable: true,
|
|
251
|
+
resizable: true
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
- Drag the **title bar** to move.
|
|
256
|
+
- Drag the **edges/corners** to resize.
|
|
257
|
+
- These interactions are disabled automatically while a popup is maximized.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## React Body
|
|
262
|
+
|
|
263
|
+
Pass a React element as `body` and LayerPro mounts it with `react-dom`
|
|
264
|
+
`createRoot` inside the modal:
|
|
265
|
+
|
|
266
|
+
```jsx
|
|
267
|
+
import { useState } from "react";
|
|
268
|
+
|
|
269
|
+
function Counter() {
|
|
270
|
+
const [n, setN] = useState(0);
|
|
271
|
+
return <button onClick={() => setN(n + 1)}>Clicked {n} times</button>;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
layerpro.popup.open({
|
|
275
|
+
id: "reactModal",
|
|
276
|
+
name: "React Modal",
|
|
277
|
+
body: <Counter />,
|
|
278
|
+
width: 400,
|
|
279
|
+
height: 300
|
|
280
|
+
});
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
React state, effects, and context all work normally inside the body.
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Selection & z-index
|
|
288
|
+
|
|
289
|
+
Clicking anywhere on a popup (the body **or** the title bar) brings it to the
|
|
290
|
+
front and gives it the `zHigh` highlight. The dock icon is also marked as
|
|
291
|
+
selected. z-index values are unitless (set as raw numbers, never `px`).
|
|
292
|
+
|
|
293
|
+
```javascript
|
|
294
|
+
// Bring a popup to the front programmatically
|
|
295
|
+
layerpro.popup.index({ id: "myModal" });
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## API Methods
|
|
301
|
+
|
|
302
|
+
| Method | Description |
|
|
303
|
+
|--------|-------------|
|
|
304
|
+
| `layerpro.popup.open(props)` | Open a modal; returns the props. Re-opening a same-id window brings it to front + refreshes body |
|
|
305
|
+
| `layerpro.popup.close(id)` | Close (and unmount) a modal |
|
|
306
|
+
| `layerpro.popup.center(id, offset?)` | Center a modal in the viewport; optional pixel offset |
|
|
307
|
+
| `layerpro.popup.maximize(props)` | Toggle maximize (pure CSS) |
|
|
308
|
+
| `layerpro.popup.iconize(id)` | Toggle minimize to the dock |
|
|
309
|
+
| `layerpro.popup.index(id)` | Bring a modal to the front (select) |
|
|
310
|
+
| `layerpro.popup.zIndex()` | Get the next z-index counter value |
|
|
311
|
+
| `layerpro.popup.movable(props)` | Enable dragging |
|
|
312
|
+
| `layerpro.popup.resizable(props)` | Enable resizing |
|
|
313
|
+
| `layerpro.popup.store(element)` | Store a reference (placeholder/extensibility) |
|
|
314
|
+
| `layerpro.popup.cleanupEvents(id)` | Remove dock/button/esc listeners |
|
|
315
|
+
| `layerpro.popup.unmount(id)` | Unmount the React root (memory cleanup) |
|
|
316
|
+
| `layerpro.noGlobals()` | Restore native `alert`/`confirm`/`prompt`; remove `message` |
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Styling & z-index
|
|
321
|
+
|
|
322
|
+
Popup z-index starts from the `--popup-z-index` CSS variable (default `1000`).
|
|
323
|
+
Apps with their own stacking contexts (e.g. a tooltip at `z-index: 100000`) can
|
|
324
|
+
shift the whole stack by overriding the variable:
|
|
325
|
+
|
|
326
|
+
```scss
|
|
327
|
+
:root { --popup-z-index: 100000; }
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
The title bar, window surface, internal area, and body all read from CSS custom
|
|
331
|
+
properties, so theming needs no `!important` and no `[class^=popup_…]` selectors:
|
|
332
|
+
|
|
333
|
+
| Variable | Applies to |
|
|
334
|
+
|----------|-----------|
|
|
335
|
+
| `--bar-background` | title bar |
|
|
336
|
+
| `--bar-selected-background` | active/selected title bar |
|
|
337
|
+
| `--bar-color` | title bar text |
|
|
338
|
+
| `--window-background` | popup surface |
|
|
339
|
+
| `--window-shadow` | popup shadow |
|
|
340
|
+
| `--window-border-radius` | popup border radius |
|
|
341
|
+
| `--internal-background` | body wrapper |
|
|
342
|
+
| `--body-color` | body text color |
|
|
343
|
+
| `--raised-background` | modal overlay |
|
|
344
|
+
| `--popup-z-index` (in root.scss) | base z-index for the stack |
|
|
345
|
+
|
|
346
|
+
Stable class names (`.popup_bar`, `.popup_window`, `.popup_overflow`,
|
|
347
|
+
`.popup_internal`, `.popup_body`, `.popup_drag`, `.popup_icon`, `.popup_option`,
|
|
348
|
+
`.popup_raised`) are emitted alongside the per-id classes so themes can target
|
|
349
|
+
elements without attribute selectors.
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## Notes & Migration
|
|
354
|
+
|
|
355
|
+
- **jQuery removed.** LayerPro no longer depends on jQuery. All DOM access uses
|
|
356
|
+
the internal `core/dom.ts` vanilla helper (`lp`, `lpAll`, `lpCreate`, `lpDoc`,
|
|
357
|
+
`lpWin`). Public behavior is unchanged.
|
|
358
|
+
- **React is external.** `react` and `react-dom` must be provided by the host
|
|
359
|
+
app and are used only to render the modal body.
|
|
360
|
+
- **Instant resize / maximize.** Transitions are disabled during resize, and
|
|
361
|
+
maximize is CSS-only, for a snappy, lag-free feel.
|
|
362
|
+
- **Vanilla pages still work.** No framework is required unless you pass a React
|
|
363
|
+
body.
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
© [Dario Passariello](https://dario.passariello.ca/) — MIT License
|
package/package.json
CHANGED