layerpro 3.0.1 → 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 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 `message()` globally.
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
- layerpro.popup.open({
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
- layerpro.popup.open({
137
+ popup.open({
113
138
  id: 'reactModal',
114
139
  name: 'React Modal',
115
140
  body: <MyComponent />, // React element
@@ -136,12 +161,13 @@ The `body` property accepts different content types:
136
161
 
137
162
  ```typescript
138
163
  {
139
- id: string, // Unique ID
164
+ id: string, // Unique ID (auto-generated as popup_1, popup_2, ... if omitted)
140
165
  body: any, // Content (text, HTML, or React)
141
166
  name: string, // Modal title
142
- icon: string, // Icon (HTML entity)
167
+ icon: string, // Icon glyph — HTML entity (e.g. "&#9888;") or an HTML
168
+ // string (e.g. '<i class="fa fa-star"></i>')
143
169
 
144
- // Dimensions
170
+ // Dimensions (defaults: width 340, height 220; minWidth 340, minHeight 220)
145
171
  width: number,
146
172
  height: number,
147
173
  minWidth: number,
@@ -149,25 +175,32 @@ The `body` property accepts different content types:
149
175
  maxWidth: number,
150
176
  maxHeight: number,
151
177
 
152
- // Position
178
+ // Remote content (same-origin only for security)
179
+ source: string, // URL to fetch HTML content from (same-origin enforced)
180
+
181
+ // Position (numbers are px; strings applied as-is, e.g. "10%")
153
182
  top: number | string,
154
183
  left: number | string,
155
184
  right: number | string,
156
185
  bottom: number | string,
186
+ center: boolean, // Center the popup in the viewport (adds a small
187
+ // cascade offset per open window so stacks don't overlap)
157
188
 
158
189
  // Animation
159
- fadeIn: number,
160
- fadeOut: number,
161
- timer: number,
190
+ fadeIn: number, // open fade duration (ms, default 100)
191
+ fadeOut: number, // close fade duration (ms, default 100)
192
+ timer: number, // auto-close after N ms
162
193
 
163
194
  // Features
164
- movable: boolean,
165
- resizable: boolean,
166
- maximize: boolean,
167
- iconize: boolean,
168
- dockable: boolean,
169
- close: boolean,
170
- raised: boolean,
195
+ movable: boolean, // draggable by the title bar
196
+ resizable: boolean, // resize handles
197
+ maximize: boolean, // double-click title bar to maximize
198
+ iconize: boolean, // allow minimize to dock
199
+ dockable: boolean, // show an icon in the dock bar
200
+ close: boolean, // show the close button
201
+ raised: boolean, // alias: modal — show a full-screen overlay that blocks
202
+ // pointer events to the page underneath
203
+ modal: boolean, // alias of raised
171
204
 
172
205
  // Buttons
173
206
  buttons: {
@@ -177,19 +210,99 @@ The `body` property accepts different content types:
177
210
  }
178
211
  ```
179
212
 
213
+ > **`raised` / `modal`** injects a full-viewport overlay (`popup_raised_<id>`) that
214
+ > intercepts every pointer event — the page underneath becomes unclickable until the
215
+ > popup closes. This is modal behavior; both names are accepted.
216
+
217
+ > **Duplicate id** — opening a popup whose `id` already exists brings that window to
218
+ > the front and refreshes its `body`/`buttons` instead of doing nothing.
219
+
220
+ ---
221
+
222
+ ## Global Overrides
223
+
224
+ Importing LayerPro replaces the native `alert`, `confirm`, and `prompt` globals with
225
+ callback-based versions, and adds a `message` global:
226
+
227
+ ```javascript
228
+ import "layerpro";
229
+
230
+ alert("Hello World!"); // LayerPro alert
231
+ confirm("Sure?", yes => {...}); // LayerPro confirm (callback, not a boolean return!)
232
+ prompt("Name?", name => {...}); // LayerPro prompt (callback, not a string return!)
233
+ message("Done!"); // LayerPro message
234
+ ```
235
+
236
+ > **⚠️ Important:** the overridden `confirm()` no longer returns a `boolean` and
237
+ > `prompt()` no longer returns a `string`. They are callback-based and return
238
+ > `undefined`. Any third-party code that does `if (confirm("..."))` will silently
239
+ > fall into the falsy branch. If your codebase depends on the native synchronous
240
+ > return values, call **`layerpro.noGlobals()`** right after importing LayerPro to
241
+ > restore the originals:
242
+ >
243
+ > ```javascript
244
+ > import "layerpro";
245
+ > layerpro.noGlobals(); // restores native alert/confirm/prompt, drops `message`
246
+ > ```
247
+
248
+ ---
249
+
250
+ ## Methods
251
+
252
+ | Method | Description |
253
+ |--------|-------------|
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 |
263
+ | `layerpro.noGlobals()` | Restore native `alert`/`confirm`/`prompt`; remove `message` |
264
+
265
+ ---
266
+
267
+ ## Styling & z-index
268
+
269
+ Popups live in a `#popup` container whose base z-index comes from the
270
+ `--popup-z-index` CSS variable (default `1000`). Apps with their own stacking
271
+ contexts can override it to shift the whole stack:
272
+
273
+ ```scss
274
+ :root { --popup-z-index: 100000; }
275
+ ```
276
+
277
+ The title bar, window surface, internal area, and body all read from CSS custom
278
+ properties, so theming needs no `!important` or `[class^=popup_…]` selectors:
279
+
280
+ | Variable | Applies to |
281
+ |----------|-----------|
282
+ | `--bar-background` | title bar |
283
+ | `--bar-selected-background` | active/selected title bar |
284
+ | `--bar-color` | title bar text |
285
+ | `--window-background` | popup surface |
286
+ | `--window-shadow` | popup shadow |
287
+ | `--window-border-radius` | popup border radius |
288
+ | `--internal-background` | body wrapper |
289
+ | `--body-color` | body text color |
290
+ | `--raised-background` | modal overlay |
291
+ | `--popup-z-index` | base z-index for the stack |
292
+
180
293
  ---
181
294
 
182
295
  ## Methods
183
296
 
184
297
  | Method | Description |
185
298
  |--------|-------------|
186
- | `layerpro.popup.open(props)` | Open a modal |
187
- | `layerpro.popup.close(id)` | Close a modal |
188
- | `layerpro.popup.center(id)` | Center modal |
189
- | `layerpro.popup.maximize(id)` | Maximize modal |
190
- | `layerpro.popup.iconize(id)` | Minimize to dock |
191
- | `layerpro.popup.movable(id)` | Enable drag |
192
- | `layerpro.popup.resizable(id)` | Enable resize |
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 |
193
306
 
194
307
  ---
195
308
 
@@ -199,6 +312,20 @@ Chrome 80+ • Firefox 75+ • Safari 13+ • Edge 80+
199
312
 
200
313
  ---
201
314
 
315
+ ## Security
316
+
317
+ LayerPro includes several security measures:
318
+
319
+ - **Same-origin fetch guard**: The `source` prop only accepts same-origin URLs. Cross-origin requests are rejected before any network call is made, preventing SSRF and data exfiltration.
320
+
321
+ - **HTML escaping**: All user-provided text content (button labels, body content, titles) is automatically escaped via `escapeHtml()` to prevent XSS. HTML entities like `<`, `>`, `&`, `"` are converted to their safe equivalents.
322
+
323
+ - **Content Security Policy friendly**: No inline scripts or `eval()` are used. React components are rendered via `createRoot()` with proper sanitization.
324
+
325
+ - **No global pollution option**: Call `layerpro.noGlobals()` after import to restore native `alert`, `confirm`, `prompt` and remove the `message` global if your codebase depends on synchronous return values.
326
+
327
+ ---
328
+
202
329
  ## Contributing
203
330
 
204
331
  LayerPro is **open source** and free for everyone. The current source is private,