@lemonadejs/modal 5.0.0 → 5.2.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.
Files changed (4) hide show
  1. package/README.md +218 -217
  2. package/dist/index.d.ts +20 -8
  3. package/dist/index.js +253 -206
  4. package/package.json +21 -21
package/README.md CHANGED
@@ -1,217 +1,218 @@
1
- # LemonadeJS Modal
2
-
3
- [Official website and documentation is here](https://lemonadejs.net/components/modal)
4
-
5
- Compatible with Vanilla JavaScript, LemonadeJS, React, Vue or Angular.
6
-
7
- The LemonadeJS JavaScript Modal is a responsive and reactive component that creates floating modals. With its flexible settings, users can easily configure draggability, closability, and resizability according to their needs.
8
-
9
- ## Features
10
-
11
- - Lightweight: The JavaScript Modal is only about 4 KBytes;
12
- - Reactive: Any changes to the underlying data are automatically applied to the HTML, making it easy to keep your grid up-to-date;
13
- - Integration: It can be used as a standalone library or integrated with any modern framework;
14
-
15
- ## Getting Started
16
-
17
- You can install using NPM or using directly from a CDN.
18
-
19
- ### npm Installation
20
-
21
- To install it in your project using npm, run the following command:
22
-
23
- ```bash
24
- $ npm install @lemonadejs/modal
25
- ```
26
-
27
- ### CDN
28
-
29
- To use modal via a CDN, include the following script tags in your HTML file:
30
-
31
- ```html
32
- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
33
- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/index.min.js"></script>
34
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/style.min.css" />
35
- ```
36
-
37
- ### Usage
38
-
39
- Declarative - Quick example with Lemonade
40
-
41
- ```javascript
42
- import lemonade from 'lemonadejs'
43
- import Modal from '@lemonadejs/modal';
44
- import '@lemonadejs/modal/dist/style.css';
45
-
46
- export default function App() {
47
- const self = this;
48
-
49
- self.toggle = function () {
50
- self.modalRef.closed = !self.modalRef.closed
51
- }
52
-
53
- return `<>
54
- <Modal :center="true" :width="400" :height="200" title="My window modal" :ref="self.modalRef">
55
- <div style="display: flex; flex-direction: column; justify-content: center; padding: 10px;">
56
- <p>Quick example!</p>
57
- <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor...</div>
58
- </div>
59
- </Modal>
60
- <input type="button" value="Toggle Modal" id="button" onclick="self.toggle" />
61
- </>`
62
- }
63
- ```
64
-
65
- Quick example with React
66
-
67
- ```jsx
68
- import React, { useRef } from 'react';
69
- import Modal from '@lemonadejs/modal/dist/react';
70
- import '@lemonadejs/modal/dist/style.css';
71
-
72
- export default function App() {
73
- const modal = useRef();
74
-
75
- const toggle = () => {
76
- modal.current.closed = !modal.current.closed;
77
- };
78
-
79
- return (
80
- <div>
81
- <Modal center={true} width={400} height={200} title="My window modal" ref={modal}>
82
- <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', padding: '10px' }}>
83
- <p>Quick example!</p>
84
- <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor...</div>
85
- </div>
86
- </Modal>
87
- <input type="button" value="Toggle Modal" id="button" onClick={toggle} />
88
- </div>
89
- );
90
- }
91
- ```
92
-
93
- Quick example with Vue
94
-
95
- ```vue
96
- <template>
97
- <Modal ref='modal' :center="true" :width="400" :height="200" title="My window modal" >
98
- <div style="display: flex; flex-direction: column; justify-content: center; padding: 10px;">
99
- <p>Quick example!</p>
100
- <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor...</div>
101
- </div>
102
- </Modal>
103
- <input type="button" value="Toggle Modal" id="button" @click="toggleModal" />
104
- </template>
105
- <script>
106
- import Modal from '@lemonadejs/modal/dist/vue';
107
- import '@lemonadejs/modal/dist/style.css'
108
-
109
- export default {
110
- name: 'App',
111
- components: {
112
- Modal,
113
- },
114
- methods: {
115
- toggleModal() {
116
- console.log(this.$refs.modal);
117
- this.$refs.modal.current.closed = !this.$refs.modal.current.closed;
118
- }
119
- }
120
- };
121
- </script>
122
- ```
123
-
124
- Programmatically - Quick example with Javascript
125
-
126
- ```html
127
- <html>
128
- <script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
129
- <script src="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/index.min.js"></script>
130
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/style.min.css" />
131
-
132
- <div id="root">
133
- <div style="display: flex; flex-direction: column; justify-content: center; padding: 10px;">
134
- <p>Quick example!</p>
135
- <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor...</div>
136
- </div>
137
- </div>
138
- <input type="button" value="Toggle Modal" id="button" />
139
-
140
- <script>
141
- const modal = Modal(document.getElementById("root"), {
142
- width: 400,
143
- height: 200,
144
- title: "My window modal",
145
- closed: true,
146
- center: true,
147
- });
148
- button.addEventListener('click', () => {
149
- console.log(modal.closed)
150
- modal.closed = !modal.closed;
151
- });
152
- </script>
153
- </html>
154
- ```
155
-
156
- ### Configuration
157
-
158
- You can configure things such as position, size, and functionalities.
159
-
160
- ### Settings
161
-
162
- | Attribute | Type | Description |
163
- |--------------|---------|----------------------------------------------------------------------------|
164
- | title? | String | The header title of the modal. If empty, the header will be not displayed. |
165
- | height? | Number | The height of the modal in pixels. |
166
- | width? | Number | The width of the modal in pixels. |
167
- | top? | Number | The vertical position of the modal within its window in pixels. |
168
- | left? | Number | The horizontal position of the modal within its window in pixels. |
169
- | draggable? | Boolean | Determines if the modal can be dragged. `Default: false`. |
170
- | resizable? | Boolean | Determines if the modal can be resized. `Default: false`. |
171
- | closed? | Boolean | Controls the open and close state of the modal. `Default: false`. |
172
- | closable? | Boolean | Disables the ability to close the modal. `Default: false`. |
173
- | center? | Boolean | Enables rendering the modal in the center of its window. `Default: false`. |
174
- | url? | String | The URL from which to fetch and render content. |
175
- | auto-close? | Boolean | Close the modal when it loses the focus. `Default: false`. |
176
- | auto-adjust? | Boolean | Ensures modal will be visible on screen. `Default: false`. |
177
- | backdrop? | Boolean | Enables the backdrop when the modal is opened. |
178
- | minimizable? | Boolean | Modal can be minimized. `Default: false`. |
179
- | minimized? | Boolean | Current minimized state of the modal. |
180
- | position? | String | Modal is automatic align during initialization. |
181
- | title? | String | Title of the modal. |
182
- | responsive? | Boolean | Enables responsive mode. `Default: true`. |
183
- | layers? | Boolean | Bring to front on focus. |
184
- | focus? | Boolean | Focus on the modal when open it. `Default: true`. |
185
- | overflow? | Boolean | Create scroll when the content is larger than the modal. `Default: false`. |
186
-
187
-
188
- ### Events
189
-
190
- | Event | Description |
191
- |-----------|------------------------------------------|
192
- | onload? | When the modal is ready. |
193
- | onclose? | Called when modal closes. |
194
- | onopen? | Called when modal opens. |
195
- | onresize? | When the user resize the modal. |
196
- | onmove? | When the user change the modal position. |
197
-
198
-
199
- ## License
200
-
201
- The LemonadeJS Modal is released under the MIT.
202
-
203
-
204
- ## Changelog
205
-
206
- ### 3.1.1
207
-
208
- - Added new events: `onmove` and `onresize`.
209
-
210
- ### 3.1.0
211
-
212
- - Close modal using the keyboard by pressing `Shift + Tab` on the icon.
213
-
214
- ## Other Tools
215
-
216
- - [jSuites](https://jsuites.net/docs)
217
- - [Jspreadsheet Data Grid](https://jspreadsheet.com)
1
+ # LemonadeJS Modal
2
+
3
+ [Official website and documentation is here](https://lemonadejs.com/plugins/modal)
4
+
5
+ Compatible with Vanilla JavaScript, LemonadeJS, React, VueJS or Angular.
6
+
7
+ The LemonadeJS JavaScript Modal is a responsive and reactive component that creates floating modals. With its flexible settings, users can easily configure draggability, closability, and resizability according to their needs.
8
+
9
+ ## Features
10
+
11
+ - Lightweight: The JavaScript Modal is only about 4 KBytes;
12
+ - Reactive: Any changes to the underlying data are automatically applied to the HTML, making it easy to keep your grid up-to-date;
13
+ - Integration: It can be used as a standalone library or integrated with any modern framework;
14
+
15
+ ## Getting Started
16
+
17
+ You can install using NPM or using directly from a CDN.
18
+
19
+ ### npm Installation
20
+
21
+ To install it in your project using npm, run the following command:
22
+
23
+ ```bash
24
+ $ npm install @lemonadejs/modal
25
+ ```
26
+
27
+ ### CDN
28
+
29
+ To use modal via a CDN, include the following script tags in your HTML file:
30
+
31
+ ```html
32
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
33
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/index.min.js"></script>
34
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/style.min.css" />
35
+ ```
36
+
37
+ ### Usage
38
+
39
+ DeclarativeQuick example with Lemonade
40
+
41
+ ```javascript
42
+ import Modal from '@lemonadejs/modal';
43
+ import '@lemonadejs/modal/dist/style.css';
44
+
45
+ export default function App() {
46
+ const toggle = () => {
47
+ this.modal.closed = !this.modal.closed;
48
+ };
49
+
50
+ return (render) => render`<>
51
+ <Modal :center="true" :width="400" :height="200" title="My window modal" :ref="self.modal">
52
+ <div style="display: flex; flex-direction: column; justify-content: center; padding: 10px;">
53
+ <p>Quick example!</p>
54
+ <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor...</div>
55
+ </div>
56
+ </Modal>
57
+ <input type="button" value="Toggle Modal" onclick="${toggle}" />
58
+ </>`;
59
+ }
60
+ ```
61
+
62
+ Quick example with React
63
+
64
+ ```jsx
65
+ import React, { useRef } from 'react';
66
+ import Modal from '@lemonadejs/modal/dist/react';
67
+ import '@lemonadejs/modal/dist/style.css';
68
+
69
+ export default function App() {
70
+ const modal = useRef();
71
+
72
+ const toggle = () => {
73
+ modal.current.closed = !modal.current.closed;
74
+ };
75
+
76
+ return (
77
+ <div>
78
+ <Modal center={true} width={400} height={200} title="My window modal" ref={modal}>
79
+ <div
80
+ style={{
81
+ display: 'flex',
82
+ flexDirection: 'column',
83
+ justifyContent: 'center',
84
+ padding: '10px',
85
+ }}
86
+ >
87
+ <p>Quick example!</p>
88
+ <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor...</div>
89
+ </div>
90
+ </Modal>
91
+ <input type="button" value="Toggle Modal" id="button" onClick={toggle} />
92
+ </div>
93
+ );
94
+ }
95
+ ```
96
+
97
+ Quick example with Vue
98
+
99
+ ```vue
100
+ <template>
101
+ <Modal ref="modal" :center="true" :width="400" :height="200" title="My window modal">
102
+ <div style="display: flex; flex-direction: column; justify-content: center; padding: 10px;">
103
+ <p>Quick example!</p>
104
+ <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor...</div>
105
+ </div>
106
+ </Modal>
107
+ <input type="button" value="Toggle Modal" id="button" @click="toggleModal" />
108
+ </template>
109
+ <script>
110
+ import Modal from '@lemonadejs/modal/dist/vue';
111
+ import '@lemonadejs/modal/dist/style.css';
112
+
113
+ export default {
114
+ name: 'App',
115
+ components: {
116
+ Modal,
117
+ },
118
+ methods: {
119
+ toggleModal() {
120
+ console.log(this.$refs.modal);
121
+ this.$refs.modal.current.closed = !this.$refs.modal.current.closed;
122
+ },
123
+ },
124
+ };
125
+ </script>
126
+ ```
127
+
128
+ Programmatically - Quick example with Javascript
129
+
130
+ ```html
131
+ <html>
132
+ <script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
133
+ <script src="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/index.min.js"></script>
134
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/modal/dist/style.min.css" />
135
+
136
+ <div id="root">
137
+ <div style="display: flex; flex-direction: column; justify-content: center; padding: 10px;">
138
+ <p>Quick example!</p>
139
+ <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor...</div>
140
+ </div>
141
+ </div>
142
+ <input type="button" value="Toggle Modal" id="button" />
143
+
144
+ <script>
145
+ const modal = Modal(document.getElementById('root'), {
146
+ width: 400,
147
+ height: 200,
148
+ title: 'My window modal',
149
+ closed: true,
150
+ center: true,
151
+ });
152
+ button.addEventListener('click', () => {
153
+ console.log(modal.closed);
154
+ modal.closed = !modal.closed;
155
+ });
156
+ </script>
157
+ </html>
158
+ ```
159
+
160
+ ### Configuration
161
+
162
+ You can configure things such as position, size, and functionalities.
163
+
164
+ ### Settings
165
+
166
+ | Attribute | Type | Description |
167
+ | ------------ | ------- | -------------------------------------------------------------------------- |
168
+ | title? | String | The header title of the modal. If empty, the header will be not displayed. |
169
+ | height? | Number | The height of the modal in pixels. |
170
+ | width? | Number | The width of the modal in pixels. |
171
+ | top? | Number | The vertical position of the modal within its window in pixels. |
172
+ | left? | Number | The horizontal position of the modal within its window in pixels. |
173
+ | draggable? | Boolean | Determines if the modal can be dragged. `Default: false`. |
174
+ | resizable? | Boolean | Determines if the modal can be resized. `Default: false`. |
175
+ | closed? | Boolean | Controls the open and close state of the modal. `Default: false`. |
176
+ | closable? | Boolean | Disables the ability to close the modal. `Default: false`. |
177
+ | center? | Boolean | Enables rendering the modal in the center of its window. `Default: false`. |
178
+ | url? | String | The URL from which to fetch and render content. |
179
+ | auto-close? | Boolean | Close the modal when it loses the focus. `Default: false`. |
180
+ | auto-adjust? | Boolean | Ensures modal will be visible on screen. `Default: false`. |
181
+ | backdrop? | Boolean | Enables the backdrop when the modal is opened. |
182
+ | minimizable? | Boolean | Modal can be minimized. `Default: false`. |
183
+ | minimized? | Boolean | Current minimized state of the modal. |
184
+ | position? | String | Modal is automatic align during initialization. |
185
+ | title? | String | Title of the modal. |
186
+ | responsive? | Boolean | Enables responsive mode. `Default: true`. |
187
+ | layers? | Boolean | Bring to front on focus. |
188
+ | focus? | Boolean | Focus on the modal when open it. `Default: true`. |
189
+ | overflow? | Boolean | Create scroll when the content is larger than the modal. `Default: false`. |
190
+
191
+ ### Events
192
+
193
+ | Event | Description |
194
+ | --------- | ---------------------------------------- |
195
+ | onload? | When the modal is ready. |
196
+ | onclose? | Called when modal closes. |
197
+ | onopen? | Called when modal opens. |
198
+ | onresize? | When the user resize the modal. |
199
+ | onmove? | When the user change the modal position. |
200
+
201
+ ## License
202
+
203
+ The LemonadeJS Modal is released under the MIT.
204
+
205
+ ## Changelog
206
+
207
+ ### 3.1.1
208
+
209
+ - Added new events: `onmove` and `onresize`.
210
+
211
+ ### 3.1.0
212
+
213
+ - Close modal using the keyboard by pressing `Shift + Tab` on the icon.
214
+
215
+ ## Other Tools
216
+
217
+ - [jSuites](https://jsuites.net/docs)
218
+ - [Jspreadsheet Data Grid](https://jspreadsheet.com)
package/dist/index.d.ts CHANGED
@@ -23,7 +23,7 @@ declare namespace Modal {
23
23
  /** Modal can be moved from its original position. Default: false */
24
24
  draggable?: boolean;
25
25
  /** Modal is automatic align during initialization. Absolute change the CSS position to absolute position to respect the screen position */
26
- position?: 'center' | 'left' | 'right' | 'bottom' | 'absolute' |undefined;
26
+ position?: 'center' | 'left' | 'right' | 'bottom' | 'absolute' | undefined;
27
27
  /** Title of the modal */
28
28
  title?: string;
29
29
  /** Width of the modal */
@@ -49,15 +49,15 @@ declare namespace Modal {
49
49
  /** Create scroll when the content is larger than the modal. Default: false */
50
50
  overflow?: boolean;
51
51
  /** onopen event */
52
- onopen?: (self: object) => void;
53
- /** onclose event */
54
- onclose?: (self: object) => void;
52
+ onopen?: (self: Modal.Instance) => void;
53
+ /** onclose event. */
54
+ onclose?: (self: Modal.Instance, origin?: 'button' | 'backdrop' | 'focusout' | 'escape') => void;
55
55
  /** onload event */
56
- onload?: (self: object) => void;
56
+ onload?: (self: Modal.Instance) => void;
57
57
  /** Move event */
58
- onmove?: (self: object, x: number, y: number) => void;
58
+ onmove?: (self: Modal.Instance, x: number, y: number) => void;
59
59
  /** Resize event */
60
- onresize?: (self: object, w: number, h: number) => void;
60
+ onresize?: (self: Modal.Instance, w: number, h: number) => void;
61
61
  /** Import content from DOM reference */
62
62
  content?: HTMLElement;
63
63
  }
@@ -78,7 +78,7 @@ declare namespace Modal {
78
78
  /** Modal can be moved from its original position. */
79
79
  draggable?: boolean;
80
80
  /** Modal is automatic align center during initialization */
81
- position?: string | undefined;
81
+ position?: 'center' | 'left' | 'right' | 'bottom' | 'absolute' | undefined;
82
82
  /** Title of the modal */
83
83
  title?: string;
84
84
  /** Width of the modal */
@@ -111,6 +111,18 @@ declare namespace Modal {
111
111
  front: () => void;
112
112
  /** Send to back when layers is activated */
113
113
  back: () => void;
114
+ /** onopen event */
115
+ onopen?: (self: Modal.Instance) => void;
116
+ /** onclose event */
117
+ onclose?: (self: Modal.Instance, origin?: 'button' | 'backdrop' | 'focusout' | 'escape') => void;
118
+ /** onload event */
119
+ onload?: (self: Modal.Instance) => void;
120
+ /** Move event */
121
+ onmove?: (self: Modal.Instance, x: number, y: number) => void;
122
+ /** Resize event */
123
+ onresize?: (self: Modal.Instance, w: number, h: number) => void;
124
+ /** Import content from DOM reference */
125
+ content?: HTMLElement;
114
126
  }
115
127
  }
116
128
 
package/dist/index.js CHANGED
@@ -11,6 +11,36 @@ if (!lemonade && typeof (require) === 'function') {
11
11
  global.Modal = factory();
12
12
  }(this, (function () {
13
13
 
14
+ class CustomEvents extends Event {
15
+ constructor(type, props, options) {
16
+ super(type, {
17
+ bubbles: true,
18
+ composed: true,
19
+ ...options,
20
+ });
21
+
22
+ if (props) {
23
+ for (const key in props) {
24
+ // Avoid assigning if property already exists anywhere on `this`
25
+ if (! (key in this)) {
26
+ this[key] = props[key];
27
+ }
28
+ }
29
+ }
30
+ }
31
+ }
32
+
33
+ // Dispatcher
34
+ const Dispatch = function(method, type, options) {
35
+ // Try calling the method directly if provided
36
+ if (typeof method === 'function') {
37
+ let a = Object.values(options);
38
+ return method(...a);
39
+ } else if (this.tagName) {
40
+ this.dispatchEvent(new CustomEvents(type, options));
41
+ }
42
+ }
43
+
14
44
  // References
15
45
  const modals = [];
16
46
  // State of the resize and move modal
@@ -189,15 +219,6 @@ if (!lemonade && typeof (require) === 'function') {
189
219
  return e === true || e === 1 || e === 'true';
190
220
  }
191
221
 
192
- // Dispatcher
193
- const Dispatch = function(type){
194
- if (typeof this[type] === 'function') {
195
- let args = Array.from(arguments);
196
- args.shift();
197
- this[type](...args)
198
- }
199
- }
200
-
201
222
  const refreshMinimized = function() {
202
223
  let items = minimizedModals;
203
224
  let numOfItems = items.length;
@@ -405,7 +426,7 @@ if (!lemonade && typeof (require) === 'function') {
405
426
  }
406
427
  }
407
428
 
408
- const Modal = function (template) {
429
+ const Modal = function (template, { onchange, onload }) {
409
430
  let self = this;
410
431
  let backdrop = null;
411
432
  let elements = null;
@@ -420,23 +441,210 @@ if (!lemonade && typeof (require) === 'function') {
420
441
  }
421
442
 
422
443
  // Make sure keep the state as boolean
423
- self.closed = !!self.closed;
444
+ self.closed = !! self.closed;
424
445
 
425
446
  // Keep all modals references
426
447
  modals.push(self);
427
448
 
449
+ // External onload remove from the lifecycle
450
+ let change = self.onchange;
451
+ self.onchange = null;
452
+
453
+ let load = self.onload;
454
+ self.onload = null;
455
+
456
+ let ignoreEvents = false;
457
+
458
+ const click = function(e) {
459
+ if (e.target.classList.contains('lm-modal-close')) {
460
+ self.close({ origin: 'button' });
461
+ }
462
+
463
+ if (e.target.classList.contains('lm-modal-minimize')) {
464
+ // Handles minimized modal positioning
465
+ if (self.minimized === true) {
466
+ removeMini(self);
467
+ } else {
468
+ setMini(self);
469
+ }
470
+ }
471
+ }
472
+
473
+ const mousemove = function(e) {
474
+ if (getButton(e)) {
475
+ return;
476
+ }
477
+
478
+ // Get mouse coordinates
479
+ let [x,y] = getCoords(e);
480
+ // Root element of the component
481
+ let item = self.el;
482
+ // Get the position and dimensions
483
+ let rect = item.getBoundingClientRect();
484
+
485
+ controls.type = null;
486
+ controls.d = null;
487
+ controls.e = item;
488
+ controls.w = rect.width;
489
+ controls.h = rect.height;
490
+ controls.t = rect.top;
491
+ controls.l = rect.left;
492
+
493
+ // When resizable
494
+ if (isTrue(self.resizable)) {
495
+ if (e.clientY - rect.top < cornerSize) {
496
+ if (rect.width - (e.clientX - rect.left) < cornerSize) {
497
+ item.style.cursor = 'ne-resize';
498
+ } else if (e.clientX - rect.left < cornerSize) {
499
+ item.style.cursor = 'nw-resize';
500
+ } else {
501
+ item.style.cursor = 'n-resize';
502
+ }
503
+ } else if (rect.height - (e.clientY - rect.top) < cornerSize) {
504
+ if (rect.width - (e.clientX - rect.left) < cornerSize) {
505
+ item.style.cursor = 'se-resize';
506
+ } else if (e.clientX - rect.left < cornerSize) {
507
+ item.style.cursor = 'sw-resize';
508
+ } else {
509
+ item.style.cursor = 's-resize';
510
+ }
511
+ } else if (rect.width - (e.clientX - rect.left) < cornerSize) {
512
+ item.style.cursor = 'e-resize';
513
+ } else if (e.clientX - rect.left < cornerSize) {
514
+ item.style.cursor = 'w-resize';
515
+ } else {
516
+ item.style.cursor = '';
517
+ }
518
+
519
+ if (item.style.cursor) {
520
+ controls.type = 'resize';
521
+ controls.d = item.style.cursor;
522
+ } else {
523
+ controls.type = null;
524
+ controls.d = null;
525
+ }
526
+ }
527
+
528
+ if (controls.type == null && isTrue(self.draggable)) {
529
+ if (y - rect.top < 40) {
530
+ item.style.cursor = 'move';
531
+ } else {
532
+ item.style.cursor = '';
533
+ }
534
+
535
+ if (item.style.cursor) {
536
+ controls.type = 'move';
537
+ controls.d = item.style.cursor;
538
+ } else {
539
+ controls.type = null;
540
+ controls.d = null;
541
+ }
542
+ }
543
+ }
544
+
545
+ const mousedown = function(e) {
546
+ if (! self.minimized) {
547
+ // Get mouse coordinates
548
+ let [x,y] = getCoords(e);
549
+ controls.x = x;
550
+ controls.y = y;
551
+ // Root element of the component
552
+ let item = self.el;
553
+ // Get the position and dimensions
554
+ let rect = item.getBoundingClientRect();
555
+ controls.e = item;
556
+ controls.w = rect.width;
557
+ controls.h = rect.height;
558
+ controls.t = rect.top;
559
+ controls.l = rect.left;
560
+ // If is not minimized
561
+ if (controls.type === 'resize') {
562
+ // Make sure the width and height is defined for the modal
563
+ if (! item.style.width) {
564
+ item.style.width = controls.w + 'px';
565
+ }
566
+ if (! item.style.height) {
567
+ item.style.height = controls.h + 'px';
568
+ }
569
+ // This will be the callback when finalize the resize
570
+ controls.action = function () {
571
+ self.width = parseInt(item.style.width);
572
+ self.height = parseInt(item.style.height);
573
+ controls.e.classList.remove('action');
574
+ // Event
575
+ Dispatch.call(self, self.onresize, 'resize', {
576
+ instance: self,
577
+ width: self.width,
578
+ height: self.height,
579
+ });
580
+ }
581
+ controls.e.classList.add('action');
582
+ } else if (isTrue(self.draggable) && y - rect.top < 40) {
583
+ // Callback
584
+ controls.action = function () {
585
+ self.top = parseInt(item.style.top);
586
+ self.left = parseInt(item.style.left);
587
+ controls.e.classList.remove('action');
588
+ // Open event
589
+ Dispatch.call(self, self.onmove, 'move', {
590
+ instance: self,
591
+ top: self.top,
592
+ left: self.left,
593
+ });
594
+ }
595
+ controls.e.classList.add('action');
596
+ // Remove transform
597
+ removeMargin(self);
598
+ }
599
+ }
600
+ }
601
+
428
602
  self.back = function() {
429
603
  sendToBack(self.el);
430
604
  }
605
+
431
606
  self.front = function() {
432
607
  sendToFront(self.el);
433
608
  }
434
609
 
435
- // Onload method
436
- let onload = self.onload;
610
+ self.open = function() {
611
+ if (self.closed === true) {
612
+ self.closed = false;
613
+ // Close event
614
+ Dispatch.call(self, self.onopen, 'open', {
615
+ instance: self
616
+ });
617
+ }
618
+ }
619
+
620
+ self.close = function(options) {
621
+ if (self.closed === false) {
622
+ self.closed = true;
623
+ // Close event
624
+ Dispatch.call(self, self.onclose, 'close', {
625
+ instance: self,
626
+ ...options
627
+ });
628
+ }
629
+ }
630
+
631
+ self.isClosed = function() {
632
+ return self.closed;
633
+ }
634
+
635
+ if (! template || typeof(template) !== 'string') {
636
+ template = '';
637
+ }
638
+
639
+ // Custom Root Configuration
640
+ self.settings = {
641
+ getRoot: function() {
642
+ return self.root;
643
+ }
644
+ }
437
645
 
438
646
  // Native lemonade
439
- self.onload = function() {
647
+ onload(() => {
440
648
  // Dimensions
441
649
  if (self.width) {
442
650
  self.el.style.width = self.width + 'px';
@@ -472,7 +680,7 @@ if (!lemonade && typeof (require) === 'function') {
472
680
 
473
681
  // Responsive
474
682
  if (document.documentElement.clientWidth < 800) {
475
- // Full screen
683
+ // Full screen
476
684
  if (self.height > 300) {
477
685
  self.el.classList.add('fullscreen');
478
686
  }
@@ -487,8 +695,8 @@ if (!lemonade && typeof (require) === 'function') {
487
695
  if (self.backdrop === true) {
488
696
  backdrop = document.createElement('div');
489
697
  backdrop.classList.add('lm-modal-backdrop');
490
- backdrop.addEventListener('click', function() {
491
- self.closed = true;
698
+ backdrop.addEventListener('click', () => {
699
+ self.close({ origin: 'backdrop' });
492
700
  });
493
701
 
494
702
  if (self.closed === false) {
@@ -499,8 +707,8 @@ if (!lemonade && typeof (require) === 'function') {
499
707
  // Import content from DOM
500
708
  if (self.content) {
501
709
  if (typeof(self.content) === 'string') {
502
- self.root.appendChild(document.createTextNode(self.content));
503
- } else if (typeof(self.content.tagName) === 'object' && self.content.tagName) {
710
+ template = self.content;
711
+ } else if (typeof(self.content) === 'object' && self.content.tagName) {
504
712
  self.root.appendChild(self.content);
505
713
  }
506
714
  }
@@ -509,7 +717,7 @@ if (!lemonade && typeof (require) === 'function') {
509
717
  self.el.addEventListener('focusout', function(e) {
510
718
  if (! self.el.contains(e.relatedTarget)) {
511
719
  if (isTrue(self['auto-close'])) {
512
- self.closed = true;
720
+ self.close({ origin: 'focusout' });
513
721
  }
514
722
  // Remove focus
515
723
  self.el.classList.remove('lm-modal-focus');
@@ -525,26 +733,41 @@ if (!lemonade && typeof (require) === 'function') {
525
733
  self.el.addEventListener('keydown', (e) => {
526
734
  if (e.key === 'Escape') {
527
735
  if (self.closed === false) {
528
- self.closed = true;
736
+ self.close({ origin: 'escape' });
529
737
  e.preventDefault();
530
738
  e.stopImmediatePropagation();
531
739
  }
532
740
  } else if (e.key === 'Enter') {
533
- self.click(e);
741
+ click(e);
534
742
  }
535
743
  });
536
744
 
537
745
  // Append elements to the container
538
746
  appendElements(self.el.children[1], elements);
539
747
 
540
- if (typeof(onload) === 'function') {
541
- Dispatch.call(self, 'onload', self);
748
+ if (self.url) {
749
+ fetch(self.url)
750
+ .then(response => response.clone().body)
751
+ .then(body => {
752
+ let reader = body.getReader();
753
+ reader.read().then(({ done, value }) => {
754
+ // Add HTML to the modal
755
+ self.root.innerHTML = new TextDecoder().decode(value.buffer);
756
+ // Call onload event
757
+ Dispatch.call(self, load, 'load', {
758
+ instance: self
759
+ });
760
+ });
761
+ });
762
+ } else {
763
+ // Call onload event
764
+ Dispatch.call(self, load, 'load', {
765
+ instance: self
766
+ });
542
767
  }
543
- }
544
-
545
- let ignoreEvents = false;
768
+ });
546
769
 
547
- self.onchange = function(property) {
770
+ onchange((property) => {
548
771
  if (ignoreEvents) {
549
772
  return false;
550
773
  }
@@ -569,9 +792,6 @@ if (!lemonade && typeof (require) === 'function') {
569
792
  backdrop.remove();
570
793
  }
571
794
  }
572
-
573
- // Call the vents
574
- self.closed ? Dispatch.call(self,'onclose',self) : Dispatch.call(self,'onopen',self);
575
795
  } else if (property === 'top' || property === 'left' || property === 'width' || property === 'height') {
576
796
  if (self[property] !== '') {
577
797
  self.el.style[property] = self[property] + 'px';
@@ -603,182 +823,9 @@ if (!lemonade && typeof (require) === 'function') {
603
823
  }
604
824
  }
605
825
  }
606
- }
607
-
608
- self.mousemove = function(e) {
609
- if (getButton(e)) {
610
- return;
611
- }
612
-
613
- // Get mouse coordinates
614
- let [x,y] = getCoords(e);
615
- // Root element of the component
616
- let item = self.el;
617
- // Get the position and dimensions
618
- let rect = item.getBoundingClientRect();
619
-
620
- controls.type = null;
621
- controls.d = null;
622
- controls.e = item;
623
- controls.w = rect.width;
624
- controls.h = rect.height;
625
- controls.t = rect.top;
626
- controls.l = rect.left;
627
-
628
- // When resizable
629
- if (self.resizable === true) {
630
- if (e.clientY - rect.top < cornerSize) {
631
- if (rect.width - (e.clientX - rect.left) < cornerSize) {
632
- item.style.cursor = 'ne-resize';
633
- } else if (e.clientX - rect.left < cornerSize) {
634
- item.style.cursor = 'nw-resize';
635
- } else {
636
- item.style.cursor = 'n-resize';
637
- }
638
- } else if (rect.height - (e.clientY - rect.top) < cornerSize) {
639
- if (rect.width - (e.clientX - rect.left) < cornerSize) {
640
- item.style.cursor = 'se-resize';
641
- } else if (e.clientX - rect.left < cornerSize) {
642
- item.style.cursor = 'sw-resize';
643
- } else {
644
- item.style.cursor = 's-resize';
645
- }
646
- } else if (rect.width - (e.clientX - rect.left) < cornerSize) {
647
- item.style.cursor = 'e-resize';
648
- } else if (e.clientX - rect.left < cornerSize) {
649
- item.style.cursor = 'w-resize';
650
- } else {
651
- item.style.cursor = '';
652
- }
653
-
654
- if (item.style.cursor) {
655
- controls.type = 'resize';
656
- controls.d = item.style.cursor;
657
- } else {
658
- controls.type = null;
659
- controls.d = null;
660
- }
661
- }
662
-
663
- if (controls.type == null && isTrue(self.draggable)) {
664
- if (y - rect.top < 40) {
665
- item.style.cursor = 'move';
666
- } else {
667
- item.style.cursor = '';
668
- }
669
-
670
- if (item.style.cursor) {
671
- controls.type = 'move';
672
- controls.d = item.style.cursor;
673
- } else {
674
- controls.type = null;
675
- controls.d = null;
676
- }
677
- }
678
- }
679
-
680
- self.mousedown = function(e) {
681
- if (! self.minimized) {
682
- // Get mouse coordinates
683
- let [x,y] = getCoords(e);
684
- controls.x = x;
685
- controls.y = y;
686
- // Root element of the component
687
- let item = self.el;
688
- // Get the position and dimensions
689
- let rect = item.getBoundingClientRect();
690
- controls.e = item;
691
- controls.w = rect.width;
692
- controls.h = rect.height;
693
- controls.t = rect.top;
694
- controls.l = rect.left;
695
- // If is not minimized
696
- if (controls.type === 'resize') {
697
- // Make sure the width and height is defined for the modal
698
- if (! item.style.width) {
699
- item.style.width = controls.w + 'px';
700
- }
701
- if (! item.style.height) {
702
- item.style.height = controls.h + 'px';
703
- }
704
- // This will be the callback when finalize the resize
705
- controls.action = function () {
706
- self.width = parseInt(item.style.width);
707
- self.height = parseInt(item.style.height);
708
- controls.e.classList.remove('action');
709
- // Event
710
- Dispatch.call(self, 'onresize', self, self.width, self.height);
711
- }
712
- controls.e.classList.add('action');
713
- } else if (isTrue(self.draggable) && y - rect.top < 40) {
714
- // Callback
715
- controls.action = function () {
716
- self.top = parseInt(item.style.top);
717
- self.left = parseInt(item.style.left);
718
- controls.e.classList.remove('action');
719
- // Event
720
- Dispatch.call(self, 'onmove', self, self.top, self.left);
721
- }
722
- controls.e.classList.add('action');
723
- // Remove transform
724
- removeMargin(self);
725
- }
726
- }
727
- }
728
-
729
- self.click = function(e) {
730
- if (e.target.classList.contains('lm-modal-close')) {
731
- self.closed = true;
732
- }
733
-
734
- if (e.target.classList.contains('lm-modal-minimize')) {
735
- // Handles minimized modal positioning
736
- if (self.minimized === true) {
737
- removeMini(self);
738
- } else {
739
- setMini(self);
740
- }
741
- }
742
- }
743
-
744
- self.open = function() {
745
- if (self.closed === true) {
746
- self.closed = false;
747
- }
748
- // Focus on the new modal
749
- self.el.focus();
750
- }
751
-
752
- self.close = function() {
753
- if (self.closed === false) {
754
- self.closed = true;
755
- }
756
- }
757
-
758
- if (self.url) {
759
- fetch(self.url)
760
- .then(response => response.clone().body)
761
- .then(body => {
762
- let reader = body.getReader();
763
- reader.read().then(function pump({done, value}) {
764
- const decoder = new TextDecoder();
765
- self.root.innerHTML = decoder.decode(value.buffer);
766
- });
767
- });
768
- }
769
-
770
- if (! template || typeof(template) !== 'string') {
771
- template = '';
772
- }
773
-
774
- // Custom Root Configuration
775
- self.settings = {
776
- getRoot: function() {
777
- return self.root;
778
- }
779
- }
826
+ });
780
827
 
781
- return `<div class="lm-modal" animation="{{self.animation}}" position="{{self.position}}" closed="{{self.closed}}" closable="{{self.closable}}" minimizable="{{self.minimizable}}" minimized="{{self.minimized}}" overflow="{{self.overflow}}" :top="self.top" :left="self.left" :width="self.width" :height="self.height" onmousedown="self.mousedown" onmousemove="self.mousemove" onclick="self.click" tabindex="-1" role="modal">
828
+ return render => render`<div class="lm-modal" animation="{{self.animation}}" position="{{self.position}}" closed="{{self.closed}}" closable="{{self.closable}}" minimizable="{{self.minimizable}}" minimized="{{self.minimized}}" overflow="{{self.overflow}}" :top="self.top" :left="self.left" :width="self.width" :height="self.height" tabindex="-1" role="modal" onmousedown="${mousedown}" onmousemove="${mousemove}" onclick="${click}">
782
829
  <div class="lm-modal-title" data-title="{{self.title}}" data-icon="{{self.icon}}"><div class="lm-modal-icon">{{self.icon}}</div><div>{{self.title}}</div><div class="lm-modal-icon lm-modal-minimize" tabindex="0"></div><div class="lm-modal-icon lm-modal-close" tabindex="0"></div></div>
783
830
  <div :ref="self.root">${template}</div>
784
831
  </div>`
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
- {
2
- "name": "@lemonadejs/modal",
3
- "title": "JavaScript Modal",
4
- "description": "LemonadeJS modal is a JavaScript component to create floating modals.",
5
- "author": {
6
- "name": "Contact <contact@lemonadejs.net>",
7
- "url": "https://lemonadejs.net"
8
- },
9
- "keywords": [
10
- "javascript modal",
11
- "lemonadejs modal",
12
- "js modal",
13
- "modal js"
14
- ],
15
- "dependencies": {
16
- "lemonadejs": "^5.0.3"
17
- },
18
- "main": "dist/index.js",
19
- "types": "dist/index.d.ts",
20
- "version": "5.0.0"
21
- }
1
+ {
2
+ "name": "@lemonadejs/modal",
3
+ "title": "JavaScript Modal",
4
+ "description": "LemonadeJS modal is a JavaScript component to create floating modals.",
5
+ "author": {
6
+ "name": "Contact <contact@lemonadejs.com>",
7
+ "url": "https://lemonadejs.net"
8
+ },
9
+ "keywords": [
10
+ "javascript modal",
11
+ "lemonadejs modal",
12
+ "js modal",
13
+ "modal js"
14
+ ],
15
+ "dependencies": {
16
+ "lemonadejs": "^5.2.0"
17
+ },
18
+ "main": "dist/index.js",
19
+ "types": "dist/index.d.ts",
20
+ "version": "5.2.1"
21
+ }