@lemonadejs/contextmenu 1.0.8 → 1.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 +98 -0
- package/dist/index.d.ts +24 -21
- package/dist/index.js +35 -6
- package/dist/react.d.ts +15 -0
- package/dist/style.css +3 -3
- package/dist/vue.d.ts +15 -0
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# LemonadeJS Context Menu
|
|
2
|
+
|
|
3
|
+
[Official website and documentation is here](https://lemonadejs.net/docs/plugins/context-menu)
|
|
4
|
+
|
|
5
|
+
Compatible with Vanilla JavaScript, LemonadeJS, React, Vue or Angular.
|
|
6
|
+
|
|
7
|
+
The LemonadeJS Context Menu is a versatile solution for interactive menu navigation, offering a customizable and intuitive experience. Designed for efficient decision-making, users can choose options that trigger specific actions or toggle the opening of another menu—configurable to your preferences.
|
|
8
|
+
|
|
9
|
+
With a focus on flexibility, this component empowers you to tailor the menu's behavior according to your application's needs. Whether it's executing actions directly or revealing nested options for a more in-depth selection process, the Context Menu adapts seamlessly.
|
|
10
|
+
|
|
11
|
+
Noteworthy features include a user-friendly interface, allowing for smooth interactions and a clear decision-making process. The configuration options provided by the Context Menu make it a valuable addition to various applications, ensuring a responsive and adaptable menu system.
|
|
12
|
+
|
|
13
|
+
## Getting Started
|
|
14
|
+
|
|
15
|
+
You can install using NPM or using directly from a CDN.
|
|
16
|
+
|
|
17
|
+
### npm Installation
|
|
18
|
+
|
|
19
|
+
To install it in your project using npm, run the following command:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
$ npm install @lemonadejs/contextmenu
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### CDN
|
|
26
|
+
|
|
27
|
+
To use Context Menu via a CDN, include the following script tags in your HTML file:
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
|
|
31
|
+
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@lemonadejs/contextmenu/dist/index.min.js"></script>
|
|
32
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/contextmenu/dist/style.min.css" />
|
|
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
|
+
Quick example with Lemonade
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
// Add the following link to your HTML file:
|
|
43
|
+
// <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />
|
|
44
|
+
import Contextmenu from '@lemonadejs/contextmenu';
|
|
45
|
+
import '@lemonadejs/contextmenu/dist/style.css';
|
|
46
|
+
import '@lemonadejs/modal/dist/style.css';
|
|
47
|
+
|
|
48
|
+
export default function App() {
|
|
49
|
+
const self = this;
|
|
50
|
+
|
|
51
|
+
self.options = [
|
|
52
|
+
{
|
|
53
|
+
title: 'Console.log',
|
|
54
|
+
onclick:function() {
|
|
55
|
+
console.log('Hello!')
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
title: 'Show Alert',
|
|
60
|
+
onclick:function() {
|
|
61
|
+
alert('Hello!')
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
return `<div style="background-color: #2222AA; width: 100px; height: 100px;">
|
|
67
|
+
<Contextmenu :options="self.options" :ref="self.contextmenu" />
|
|
68
|
+
</div>`
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Properties
|
|
73
|
+
|
|
74
|
+
| Property | Type | Description |
|
|
75
|
+
|-----------|------|-------------|
|
|
76
|
+
| options | option[] | An array of option objects describing the rendering options. Each item should follow the structure defined in the 'Option Details' section. |
|
|
77
|
+
|
|
78
|
+
### Option Details
|
|
79
|
+
|
|
80
|
+
| Property | Type | Description |
|
|
81
|
+
|-----------|------|-------------|
|
|
82
|
+
| submenu? | array of options | An optional array containing options displayed as a sub-menu. |
|
|
83
|
+
| title? | string | The title text associated with the option. |
|
|
84
|
+
| type? | string | The type of the current object, which can be utilized to display a line with 'line'. |
|
|
85
|
+
| onclick? | function | The function executed upon selecting the option. |
|
|
86
|
+
| icon? | string | The name of the Material Icon associated with the option. |
|
|
87
|
+
| render? | function | The function executed when rendering the option. |
|
|
88
|
+
| onopen? | function | The function executed when the submenu is opened. |
|
|
89
|
+
| onclose? | function | The function executed when the submenu is closed. |
|
|
90
|
+
|
|
91
|
+
## License
|
|
92
|
+
|
|
93
|
+
The [LemonadeJS](https://lemonadejs.net) Context Menu is released under the MIT.
|
|
94
|
+
|
|
95
|
+
## Other Tools
|
|
96
|
+
|
|
97
|
+
- [jSuites](https://jsuites.net/v4/)
|
|
98
|
+
- [Jspreadsheet Data Grid](https://jspreadsheet.com)
|
package/dist/index.d.ts
CHANGED
|
@@ -4,29 +4,32 @@
|
|
|
4
4
|
* Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
(): any
|
|
9
|
-
[key: string]: any
|
|
10
|
-
}
|
|
7
|
+
declare function Contextmenu(el: HTMLElement, options?: Contextmenu.Options): Contextmenu.Instance;
|
|
11
8
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
declare namespace Contextmenu {
|
|
10
|
+
interface Item {
|
|
11
|
+
submenu?: Item[];
|
|
12
|
+
title?: string;
|
|
13
|
+
type: 'line' | undefined;
|
|
14
|
+
onclick?: (e: MouseEvent, element: HTMLElement) => void;
|
|
15
|
+
icon?: string;
|
|
16
|
+
render?: (e: MouseEvent, element: HTMLElement) => void;
|
|
17
|
+
/** onopen event */
|
|
18
|
+
onopen?: (self: object) => void;
|
|
19
|
+
/** onclose event */
|
|
20
|
+
onclose?: (self: object) => void;
|
|
21
|
+
}
|
|
20
22
|
|
|
21
|
-
interface Options {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
23
|
+
interface Options {
|
|
24
|
+
/** Modal is closed */
|
|
25
|
+
options?: Item[];
|
|
26
|
+
}
|
|
25
27
|
|
|
26
|
-
interface
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
interface Instance {
|
|
29
|
+
options: boolean;
|
|
30
|
+
open: (options: Options, x: number, y: number, e: MouseEvent) => void;
|
|
31
|
+
close: () => void;
|
|
32
|
+
}
|
|
30
33
|
}
|
|
31
34
|
|
|
32
|
-
export
|
|
35
|
+
export default Contextmenu;
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,11 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
25
25
|
y = e.clientY;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
// Adjust for any scrollable parent element
|
|
29
|
+
let b = document.body;
|
|
30
|
+
x -= b.scrollLeft;
|
|
31
|
+
y -= b.scrollTop;
|
|
32
|
+
|
|
28
33
|
return [x,y];
|
|
29
34
|
}
|
|
30
35
|
|
|
@@ -60,6 +65,17 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
60
65
|
self.onclose = function() {
|
|
61
66
|
// Reset any cursor
|
|
62
67
|
resetCursor.call(self.modal);
|
|
68
|
+
// Parent
|
|
69
|
+
if (typeof(self.parent.onclose) === 'function') {
|
|
70
|
+
self.parent.onclose(self.parent, self);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
self.onopen = function() {
|
|
75
|
+
// Parent
|
|
76
|
+
if (typeof(self.parent.onopen) === 'function') {
|
|
77
|
+
self.parent.onopen(self.parent, self);
|
|
78
|
+
}
|
|
63
79
|
}
|
|
64
80
|
|
|
65
81
|
/**
|
|
@@ -109,6 +125,8 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
109
125
|
// Position cursor
|
|
110
126
|
modal.cursor = 0;
|
|
111
127
|
}
|
|
128
|
+
|
|
129
|
+
onopen(modal, s.submenu)
|
|
112
130
|
} else {
|
|
113
131
|
// Close modals with higher level
|
|
114
132
|
self.parent.close(index+1);
|
|
@@ -140,7 +158,7 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
140
158
|
}
|
|
141
159
|
}
|
|
142
160
|
|
|
143
|
-
let template = `<Modal :overflow="true" :closed="true" :ref="self.modal" :responsive="false" :auto-adjust="true" :
|
|
161
|
+
let template = `<Modal position="absolute" :overflow="true" :closed="true" :ref="self.modal" :responsive="false" :auto-adjust="true" :focus="false" :layers="false" :onopen="self.onopen" :onclose="self.onclose">
|
|
144
162
|
<div class="lm-menu-submenu">
|
|
145
163
|
<Item :loop="self.options" />
|
|
146
164
|
</div>
|
|
@@ -186,6 +204,8 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
186
204
|
if (this.options[cursor].type === 'line') {
|
|
187
205
|
setCursor.call(this, direction);
|
|
188
206
|
}
|
|
207
|
+
|
|
208
|
+
return true;
|
|
189
209
|
}
|
|
190
210
|
|
|
191
211
|
/**
|
|
@@ -237,6 +257,15 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
237
257
|
}
|
|
238
258
|
}
|
|
239
259
|
|
|
260
|
+
const onopen = function(s, options) {
|
|
261
|
+
// Onopen
|
|
262
|
+
for (let i = 0; i < options.length; i++) {
|
|
263
|
+
if (typeof(options[i].onopen) === 'function') {
|
|
264
|
+
options[i].onopen(s);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
240
269
|
const Contextmenu = function() {
|
|
241
270
|
let self = this;
|
|
242
271
|
|
|
@@ -269,7 +298,6 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
269
298
|
} else if (e.type === 'click') {
|
|
270
299
|
modal.closed = ! modal.closed;
|
|
271
300
|
}
|
|
272
|
-
|
|
273
301
|
// If the modal is open and the content is different from what is shown
|
|
274
302
|
if (modal.closed === false) {
|
|
275
303
|
// Close modals with higher level
|
|
@@ -282,6 +310,7 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
282
310
|
// Refresh content
|
|
283
311
|
modal.options = options;
|
|
284
312
|
}
|
|
313
|
+
onopen(self, options);
|
|
285
314
|
}
|
|
286
315
|
}
|
|
287
316
|
|
|
@@ -319,9 +348,9 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
319
348
|
} else if (e.key === 'ArrowRight') {
|
|
320
349
|
ret = openSubmenu.call(m);
|
|
321
350
|
} else if (e.key === 'ArrowUp') {
|
|
322
|
-
setCursor.call(m, 0);
|
|
351
|
+
ret = setCursor.call(m, 0);
|
|
323
352
|
} else if (e.key === 'ArrowDown') {
|
|
324
|
-
setCursor.call(m, 1);
|
|
353
|
+
ret = setCursor.call(m, 1);
|
|
325
354
|
} else if (e.key === 'Enter') {
|
|
326
355
|
ret = actionCursor.call(m, e);
|
|
327
356
|
}
|
|
@@ -336,7 +365,7 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
336
365
|
// Create event for focus out
|
|
337
366
|
self.root.addEventListener("focusout", (e) => {
|
|
338
367
|
if (! self.root.contains(e.relatedTarget)) {
|
|
339
|
-
self.close(0);
|
|
368
|
+
//self.close(0);
|
|
340
369
|
}
|
|
341
370
|
});
|
|
342
371
|
|
|
@@ -344,7 +373,7 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
344
373
|
self.root.addEventListener("contextmenu", function(e) {
|
|
345
374
|
let [x,y] = getCoords(e);
|
|
346
375
|
// Open the context menu
|
|
347
|
-
|
|
376
|
+
let scrollPosition = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
|
|
348
377
|
self.open(self.options, x, y+scrollPosition, e);
|
|
349
378
|
e.preventDefault();
|
|
350
379
|
e.stopImmediatePropagation();
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Official Type definitions for the LemonadeJS plugins
|
|
3
|
+
* https://lemonadejs.net
|
|
4
|
+
* Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
|
5
|
+
*/
|
|
6
|
+
import Component from './index';
|
|
7
|
+
|
|
8
|
+
interface Contextmenu {
|
|
9
|
+
(): any
|
|
10
|
+
[key: string]: any
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
declare function Contextmenu<Contextmenu>(props: Component.Options): any;
|
|
14
|
+
|
|
15
|
+
export default Contextmenu;
|
package/dist/style.css
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
.lm-menu-submenu > div.lm-menu-item {
|
|
20
20
|
box-sizing: border-box;
|
|
21
21
|
display: flex;
|
|
22
|
-
padding: 0 8px 0
|
|
22
|
+
padding: 0 8px 0 8px;
|
|
23
23
|
width: 250px;
|
|
24
24
|
font-size: 11px;
|
|
25
25
|
font-family:sans-serif;
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
content: attr(data-icon);
|
|
65
65
|
font-family: 'Material Icons';
|
|
66
66
|
font-size: 16px;
|
|
67
|
-
position: absolute;
|
|
68
|
-
left: 9px;
|
|
69
67
|
line-height: 24px;
|
|
68
|
+
margin-right: 10px;
|
|
69
|
+
width: 16px;
|
|
70
70
|
}
|
package/dist/vue.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Official Type definitions for the LemonadeJS plugins
|
|
3
|
+
* https://lemonadejs.net
|
|
4
|
+
* Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
|
5
|
+
*/
|
|
6
|
+
import Component from './index';
|
|
7
|
+
|
|
8
|
+
interface Contextmenu {
|
|
9
|
+
(): any
|
|
10
|
+
[key: string]: any
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
declare function Contextmenu<Contextmenu>(props: Component.Options): any;
|
|
14
|
+
|
|
15
|
+
export default Contextmenu;
|
package/package.json
CHANGED
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
"build": "webpack --config webpack.config.js"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@lemonadejs/modal": "^2.
|
|
17
|
+
"@lemonadejs/modal": "^2.7.1",
|
|
18
18
|
"lemonadejs": "^4.0.7"
|
|
19
19
|
},
|
|
20
20
|
"main": "dist/index.js",
|
|
21
21
|
"types": "dist/index.d.ts",
|
|
22
|
-
"version": "1.
|
|
22
|
+
"version": "1.1.1"
|
|
23
23
|
}
|