@lemonadejs/modal 1.2.0 → 2.0.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 ADDED
@@ -0,0 +1,61 @@
1
+ # Javascript 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 data grid 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
+ ```
35
+
36
+ ### Configuration
37
+
38
+ Quick example
39
+
40
+ ```javascript
41
+ import Signature from "@lemonadejs/modal";
42
+
43
+ export default function Component() {
44
+ const self = this;
45
+ self.width = 400;
46
+ self.height = 200;
47
+
48
+ return `<Modal width="{{self.width}}" height="{{self.height}}" title="My windowmodal">
49
+ <h1>Teste</h1>
50
+ </Modal>`;
51
+ }
52
+ ```
53
+
54
+ ## License
55
+
56
+ The LemonadeJS Modal is released under the MIT.
57
+
58
+ ## Other Tools
59
+
60
+ - [jSuites](https://jsuites.net/v4/)
61
+ - [Jspreadsheet](https://jspreadsheet.com)
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Official Type definitions for LemonadeJS plugins
3
+ * https://lemonadejs.net
4
+ * Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
5
+ */
6
+
7
+ interface Modal {
8
+ (): any
9
+ [key: string]: any
10
+ }
11
+
12
+ interface options {
13
+ closed?: boolean;
14
+ closable?: boolean;
15
+ resizable?: boolean;
16
+ draggable?: boolean;
17
+ center?: boolean;
18
+ title?: string;
19
+ width?: number;
20
+ height?: number;
21
+ top?: number;
22
+ left?: number;
23
+ }
24
+
25
+ interface instance {
26
+ closed: boolean;
27
+ closable: boolean;
28
+ resizable: boolean;
29
+ draggable: boolean;
30
+ center: boolean;
31
+ title: string;
32
+ width: number;
33
+ height: number;
34
+ top: number;
35
+ left: number;
36
+ }
37
+
38
+ export declare function Modal(el: HTMLElement, options?: options): instance;
package/dist/index.js CHANGED
@@ -1,41 +1,272 @@
1
+ if (! lemonade && typeof(require) === 'function') {
2
+ var lemonade = require('lemonadejs');
3
+ }
4
+
1
5
  ;(function (global, factory) {
2
6
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
7
  typeof define === 'function' && define.amd ? define(factory) :
4
8
  global.Modal = factory();
5
9
  }(this, (function () {
10
+ let state = {};
11
+ let editorAction;
12
+ // Width of the border
13
+ let cornerSize = 10;
14
+
15
+ // Events
16
+ const mouseDown = function(e) {
17
+ let item = e.target.closest('.lm-modal');
18
+ if (item !== null) {
19
+ // Keep the tracking information
20
+ let x;
21
+ let y;
22
+ let rect = item.getBoundingClientRect();
23
+
24
+ if (e.changedTouches && e.changedTouches[0]) {
25
+ x = e.changedTouches[0].clientX;
26
+ y = e.changedTouches[0].clientY;
27
+ } else {
28
+ x = e.clientX;
29
+ y = e.clientY;
30
+ }
31
+
32
+ if (item.self.closable === true && rect.width - (x - rect.left) < 40 && (y - rect.top) < 40) {
33
+ item.self.closed = true;
34
+ } else {
35
+ editorAction = {
36
+ e: item,
37
+ x: x,
38
+ y: y,
39
+ w: rect.width,
40
+ h: rect.height,
41
+ d: item.style.cursor,
42
+ resizing: !!item.style.cursor,
43
+ actioned: false,
44
+ s: item.self,
45
+ }
46
+
47
+ // Make sure width and height styling is OK
48
+ if (!e.target.style.width) {
49
+ item.style.width = rect.width + 'px';
50
+ }
51
+
52
+ if (!item.style.height) {
53
+ item.style.height = rect.height + 'px';
54
+ }
6
55
 
7
- // Load lemonadejs
8
- if (typeof(lemonade) == 'undefined') {
9
- if (typeof(require) === 'function') {
10
- var lemonade = require('lemonadejs');
11
- } else if (window.lemonade) {
12
- var lemonade = window.lemonade;
56
+ // Remove any selection from the page
57
+ let s = window.getSelection();
58
+ if (s.rangeCount) {
59
+ for (let i = 0; i < s.rangeCount; i++) {
60
+ s.removeRange(s.getRangeAt(i));
61
+ }
62
+ }
63
+
64
+ e.preventDefault();
65
+ e.stopPropagation();
66
+ }
13
67
  }
14
68
  }
15
69
 
16
- // Load lemonadejs
17
- if (typeof(jSuites) == 'undefined') {
18
- if (typeof(require) === 'function') {
19
- var jSuites = require('jsuites');
20
- } else if (window.jSuites) {
21
- var jSuites = window.jSuites;
70
+ const mouseUp = function(e) {
71
+ if (editorAction && editorAction.e) {
72
+ // Element
73
+ if (editorAction.resizing) {
74
+ let w = parseInt(editorAction.e.style.width);
75
+ let h = parseInt(editorAction.e.style.height)
76
+ editorAction.s.width = w;
77
+ editorAction.s.height = h;
78
+ } else {
79
+ let t = parseInt(editorAction.e.style.top);
80
+ let l = parseInt(editorAction.e.style.left)
81
+ editorAction.s.top = t;
82
+ editorAction.s.left = l;
83
+ }
84
+
85
+ if (typeof(editorAction.e.refresh) == 'function') {
86
+ state.actioned = true;
87
+ editorAction.e.refresh.call(editorAction.s);
88
+ }
89
+
90
+ editorAction.e.style.cursor = '';
91
+ }
92
+
93
+ // Reset
94
+ state = {
95
+ x: null,
96
+ y: null,
97
+ }
98
+
99
+ editorAction = false;
100
+ }
101
+
102
+ const mouseMove = function(e) {
103
+ if (editorAction) {
104
+ let x = e.clientX || e.pageX;
105
+ let y = e.clientY || e.pageY;
106
+
107
+ // Action on going
108
+ if (! editorAction.resizing && editorAction.s.draggable === true) {
109
+ if (state && state.x == null && state.y == null) {
110
+ state.x = x;
111
+ state.y = y;
112
+ }
113
+
114
+ let dx = x - state.x;
115
+ let dy = y - state.y;
116
+ let top = editorAction.e.offsetTop + dy;
117
+ let left = editorAction.e.offsetLeft + dx;
118
+
119
+ // Update position
120
+ editorAction.top = top
121
+ editorAction.left = left
122
+ editorAction.e.style.top = top + 'px';
123
+ editorAction.e.style.left = left + 'px';
124
+ editorAction.e.style.cursor = "move";
125
+
126
+
127
+ state.x = x;
128
+ state.y = y;
129
+ state.top = top
130
+ state.left = left
131
+
132
+ // Update element
133
+ if (typeof(editorAction.e.refresh) == 'function') {
134
+ state.actioned = true;
135
+ editorAction.e.refresh.call(editorAction.s, 'position', top, left);
136
+ }
137
+ } else {
138
+ let width = null;
139
+ let height = null;
140
+ let newHeight = null;
141
+
142
+ if (editorAction.d === 'e-resize' || editorAction.d === 'ne-resize' || editorAction.d === 'se-resize') {
143
+ // Update width
144
+ width = editorAction.w + (x - editorAction.x);
145
+ editorAction.e.style.width = width + 'px';
146
+
147
+ // Update Height
148
+ if (e.shiftKey) {
149
+ newHeight = (x - editorAction.x) * (editorAction.h / editorAction.w);
150
+ height = editorAction.h + newHeight;
151
+ editorAction.e.style.height = height + 'px';
152
+ } else {
153
+ newHeight = false;
154
+ }
155
+ }
156
+
157
+ if (! newHeight) {
158
+ if (editorAction.d === 's-resize' || editorAction.d === 'se-resize' || editorAction.d === 'sw-resize') {
159
+ height = editorAction.h + (y - editorAction.y);
160
+ editorAction.e.style.height = height + 'px';
161
+ }
162
+ }
163
+
164
+ // Update element
165
+ if (typeof(editorAction.e.refresh) == 'function') {
166
+ state.actioned = true;
167
+ editorAction.e.refresh.call(editorAction.s, 'dimensions', width, height);
168
+ }
169
+ }
170
+ } else {
171
+ let item = e.target.closest('.lm-modal');
172
+ if (item !== null) {
173
+ if (item.self && item.self.resizable === true) {
174
+ let rect = item.getBoundingClientRect();
175
+ if (rect.height - (e.clientY - rect.top) < cornerSize) {
176
+ if (rect.width - (e.clientX - rect.left) < cornerSize) {
177
+ item.style.cursor = 'se-resize';
178
+ } else {
179
+ item.style.cursor = 's-resize';
180
+ }
181
+ } else if (rect.width - (e.clientX - rect.left) < cornerSize) {
182
+ item.style.cursor = 'e-resize';
183
+ } else {
184
+ item.style.cursor = '';
185
+ }
186
+ }
187
+ }
22
188
  }
23
189
  }
24
190
 
25
- return function(html) {
26
- var self = this;
191
+ document.addEventListener('mouseup', mouseUp);
192
+ document.addEventListener('mousemove', mouseMove);
193
+
194
+ const Modal = function (template) {
195
+ let self = this;
27
196
 
28
- self.create = function(o) {
29
- self.modal = jSuites.modal(o, self);
197
+ // Default values
198
+ if (typeof(self.title) === 'undefined') {
199
+ self.title = '';
200
+ }
201
+ if (typeof(self.closed) === 'undefined') {
202
+ self.closed = false;
30
203
  }
204
+ if (typeof(self.closable) === 'undefined') {
205
+ self.closable = false;
206
+ }
207
+
208
+ // Dispatcher
209
+ const Dispatch = (type, option) => {
210
+ if (typeof self[type] === 'function') {
211
+ self[type](self, option)
212
+ }
213
+ }
214
+
215
+ self.mousedown = mouseDown;
216
+
217
+ self.onload = function() {
218
+ if (self.url) {
219
+ fetch(self.url)
220
+ .then(response => response.clone().body)
221
+ .then(body => {
222
+ let reader = body.getReader();
223
+ reader.read().then(function pump({done, value}) {
224
+ const decoder = new TextDecoder();
225
+ template += decoder.decode(value.buffer);
226
+ });
227
+ });
228
+ }
31
229
 
32
- var template = `
33
- <div @ready="self.create(this)" name={{self.name}}>
34
- ${html}
35
- </div>
36
- `;
230
+ // Initial centralize
231
+ if (self.center === true) {
232
+ self.top = (window.innerHeight - self.height) / 2;
233
+ self.left = (window.innerWidth - self.width) / 2;
234
+ }
37
235
 
38
- return lemonade.element(template, self);
236
+ // Make sure the instance of the self is available via the DOM element
237
+ self.el.self = self;
238
+
239
+ // Close
240
+ document.addEventListener('keydown', (e) => {
241
+ if (e.key === 'Escape' && self.closed === false) {
242
+ self.closed = true;
243
+ }
244
+ });
245
+
246
+ // Full screen
247
+ if (self.height > 260) {
248
+ self.el.classList.add('fullscreen');
249
+ }
250
+ }
251
+
252
+ self.onchange = function(property) {
253
+ if (property === 'closed') {
254
+ self.closed ? Dispatch('onclose') : Dispatch('onopen');
255
+ }
256
+ }
257
+
258
+ return `<div class="lm-modal" title="{{self.title}}" :closed="self.closed" :closable="self.closable" style="width: {{self.width}}px; height: {{self.height}}px; top: {{self.top}}px; left: {{self.left}}px;" onmousedown="self.mousedown(e)" tabindex="-1">${template}</div>`
39
259
  }
40
260
 
261
+
262
+ lemonade.setComponents({ Modal: Modal });
263
+
264
+ return function (root, options) {
265
+ if (typeof(root) === 'object') {
266
+ lemonade.render(Modal, root, options)
267
+ return options;
268
+ } else {
269
+ return Modal.call(this, root)
270
+ }
271
+ }
41
272
  })));
package/dist/style.css ADDED
@@ -0,0 +1,83 @@
1
+ .lm-modal {
2
+ position: absolute;
3
+ min-width: 150px;
4
+ min-height: 120px;
5
+ width: 300px;
6
+ height: 260px;
7
+ border-radius: 4px;
8
+ z-index: 9;
9
+ background-color: #fff;
10
+ border: 1px solid #ccc;
11
+ box-sizing: border-box;
12
+ box-shadow: 0 0 4px 3px rgba(80,80,80,.1);
13
+ }
14
+
15
+ @media only screen and (max-width : 800px) {
16
+ .lm-modal {
17
+ width: 100% !important;
18
+ bottom: 0;
19
+ left: 0;
20
+ border: 0;
21
+ border-radius: 0;
22
+ transform: none;
23
+ animation: slide-bottom-in 0.4s forwards;
24
+ }
25
+
26
+ .lm-modal.fullscreen {
27
+ top: 0;
28
+ height: 100% !important;
29
+ }
30
+ }
31
+
32
+ .lm-modal-picker {
33
+ width: 100% !important;
34
+ height: 260px !important;
35
+ left: 0;
36
+ bottom: 0;
37
+ border: 0;
38
+ border-radius: 0;
39
+ transform: none;
40
+ }
41
+
42
+ .lm-modal-center {
43
+ display: flex;
44
+ justify-content: center;
45
+ align-items: center;
46
+ }
47
+
48
+ .lm-modal[title]::before {
49
+ content: attr(title);
50
+ display: block;
51
+ position: relative;
52
+ width: 100%;
53
+ border-bottom: 1px solid #ccc;
54
+ padding: 10px;
55
+ box-sizing: border-box;
56
+ font-size: 1.2em;
57
+ line-height: 24px;
58
+ }
59
+
60
+ .lm-modal[closable="true"]::after {
61
+ content: 'close';
62
+ font-family: 'Material Icons';
63
+ display: block;
64
+ position: absolute;
65
+ top: 10px;
66
+ right: 10px;
67
+ font-size: 24px;
68
+ cursor: pointer;
69
+ }
70
+
71
+
72
+ .lm-modal[title=""]::before {
73
+ display: none;
74
+ }
75
+
76
+ .lm-modal[closed="true"] {
77
+ display: none !important;
78
+ }
79
+
80
+ @keyframes slide-bottom-in {
81
+ 0% { transform: translateY(100%); }
82
+ 100% { transform: translateY(0%); }
83
+ }
package/package.json CHANGED
@@ -1,22 +1,20 @@
1
1
  {
2
2
  "name": "@lemonadejs/modal",
3
- "title": "LemonadeJS modal",
4
- "description": "LemonadeJS modal integration.",
3
+ "title": "JavaScript Modal",
4
+ "description": "LemonadeJS modal is a JavaScript component to create floating modals.",
5
5
  "author": {
6
6
  "name": "Contact <contact@lemonadejs.net>",
7
7
  "url": "https://lemonadejs.net"
8
8
  },
9
9
  "keywords": [
10
10
  "javascript modal",
11
- "lemonadejs plugins",
12
- "js",
13
- "library",
14
- "javascript plugins"
11
+ "lemonadejs modal",
12
+ "js modal",
13
+ "modal js"
15
14
  ],
16
15
  "dependencies": {
17
- "lemonadejs": "^2.6.3",
18
- "jsuites": "^4.15.1"
16
+ "lemonadejs": "^3.3.1"
19
17
  },
20
18
  "main": "dist/index.js",
21
- "version": "1.2.0"
19
+ "version": "2.0.1"
22
20
  }