menupro 2.0.0 → 2.0.2

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 (3) hide show
  1. package/README.md +112 -320
  2. package/index.js +1 -1
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -1,353 +1,145 @@
1
- # NOTE
1
+ # menupro
2
2
 
3
- Create menu in your saas like Desktop App
3
+ [![npm version](https://img.shields.io/npm/v/menupro.svg)](https://www.npmjs.com/package/menupro)
4
+ [![License](https://img.shields.io/npm/l/menupro.svg)](https://opensource.org/licenses/MIT)
4
5
 
5
- ## install
6
+ A lightweight, dependency-free dropdown menu library for web applications. Create desktop-style navigation menus with ease.
6
7
 
7
- ```bash
8
- npm i -D menupro
9
- ```
8
+ ## Features
10
9
 
11
- ## setup
10
+ - **Zero dependencies** - No jQuery, React, or other libraries required
11
+ - **Lightweight** - Only ~2.4KB minified (including CSS)
12
+ - **Auto-injected CSS** - Styles are automatically loaded with the JavaScript
13
+ - **Recursive menus** - Support for unlimited nested submenus
14
+ - **Icon support** - Add icons to menu items
15
+ - **Easy event handling** - Multiple ways to handle click events
12
16
 
13
- On top of your project
17
+ ## Install
14
18
 
15
- ```js
16
- import 'menupro'
19
+ ```bash
20
+ npm i menupro
17
21
  ```
18
22
 
19
- ## use
20
-
21
- in your app (React too)
23
+ ## Quick Start
22
24
 
23
- ```js
24
- useEffect(() => {
25
-
26
- menupro.start({
27
- name: "menupro",
28
- element: "#root>nav",
29
- ...json
30
- })
25
+ ### 1. Import the library
31
26
 
32
- }, [])
27
+ ```html
28
+ <script src="menupro/index.js"></script>
33
29
  ```
34
30
 
35
- OR
31
+ Or with ES modules:
36
32
 
37
33
  ```js
38
- return (
39
-
40
- <nav>
41
-
42
- <menupro.start {
43
- ...{
44
- name: "menupro",
45
- element: "#root>nav",
46
- ...json
47
- }
48
- }
49
- />
50
-
51
- </nav>
52
-
53
- )
54
- />
34
+ import 'menupro'
55
35
  ```
56
36
 
57
- OR
37
+ ### 2. Initialize the menu
58
38
 
39
+ ```js
40
+ menupro.start({
41
+ name: 'menupro',
42
+ element: '#navbar',
43
+ nav: [
44
+ {
45
+ name: 'File',
46
+ sub: [
47
+ { name: 'New', onclick: 'createNew()' },
48
+ { name: 'Open', onclick: "openFile('doc')" },
49
+ { name: '' }, // Separator
50
+ { name: 'Exit', onclick: 'app.exit()' }
51
+ ]
52
+ },
53
+ {
54
+ name: 'Edit',
55
+ sub: [
56
+ { name: 'Cut', onclick: 'edit.cut()' },
57
+ { name: 'Copy', onclick: 'edit.copy()' },
58
+ { name: 'Paste', onclick: 'edit.paste()' }
59
+ ]
60
+ },
61
+ {
62
+ name: 'Help',
63
+ onclick: 'showHelp()'
64
+ }
65
+ ]
66
+ })
67
+ ```
59
68
 
69
+ ## Configuration
60
70
 
61
- ### parameters
71
+ ### Parameters
62
72
 
63
- "name" <-- the name for your element
73
+ | Parameter | Type | Description |
74
+ |-----------|------|-------------|
75
+ | `name` | string | CSS class name for the menu (default: "menupro") |
76
+ | `element` | string \| HTMLElement | Target container for the menu |
77
+ | `nav` | array | Menu structure (see below) |
64
78
 
65
- "element" <-- where you want your menu append (usually NAV)
79
+ ### Menu Item Structure
66
80
 
67
- "...json" <-- the object contains your menu (see the json)
81
+ ```js
82
+ {
83
+ name: 'Menu Label', // Required (empty string for separator)
84
+ onclick: 'functionName', // Optional: function name or call
85
+ icon: '<img src="...">', // Optional: HTML icon
86
+ sub: [ // Optional: nested menu items
87
+ { name: 'Sub Item', ... }
88
+ ]
89
+ }
90
+ ```
68
91
 
69
- ## config
92
+ ### onclick Options
70
93
 
71
- you can use a json to configure the menu.
72
- Here some ways...
94
+ The `onclick` property supports multiple formats:
73
95
 
74
96
  ```js
75
- const json = require("./menu.json")
97
+ // 1. Function name (must be global)
98
+ { onclick: 'myFunction' }
76
99
 
77
- or
100
+ // 2. Function call with arguments
101
+ { onclick: "openFile('document.pdf')" }
78
102
 
79
- import json from "./menu.json"
103
+ // 3. Direct function reference
104
+ { onclick: () => console.log('clicked!') }
80
105
  ```
81
106
 
82
- > example:
83
-
84
- ```json
85
-
86
- {
87
- "author": "",
88
- "charset": "UTF-8",
89
- "title": "navmenu",
90
- "short": "navmenu",
91
- "keywords": "",
92
- "nav": [
93
- {
94
- "name": "file",
95
- "title": "",
96
- "target": "",
97
- "link": "",
98
- "onclick": "",
99
- "icon": "",
100
- "lang": {
101
- "en": "file"
102
- },
103
- "sub": [
104
- {
105
- "name": "test_file_1_1",
106
- "title": "",
107
- "target": "",
108
- "link": "",
109
- "onclick": "message('test')",
110
- "icon": "<img src='/assets/icons/list-alt.svg' />",
111
- "lang": {
112
- "en": "test"
113
- },
114
- "sub": []
115
- },
116
- {
117
- "name": "test_file_2_1",
118
- "title": "",
119
- "target": "",
120
- "link": "",
121
- "onclick": "message('test')",
122
- "icon": "<img src='/assets/icons/tasks.svg' />",
123
- "lang": {
124
- "en": "test"
125
- },
126
- "sub": []
127
- },
128
- {
129
- "name": ""
130
- },
131
- {
132
- "name": "test_file_3_1",
133
- "title": "",
134
- "target": "",
135
- "link": "",
136
- "onclick": "message('test')",
137
- "icon": "<img src='/assets/icons/thumbtack.svg' />",
138
- "lang": {
139
- "en": "test"
140
- },
141
- "sub": []
142
- },
143
- {
144
- "name": "test_file_4_1",
145
- "title": "",
146
- "target": "",
147
- "link": "",
148
- "onclick": "message('test')",
149
- "icon": "<img src='/assets/icons/users.svg' />",
150
- "lang": {
151
- "en": "test"
152
- },
153
- "sub": [
154
- {
155
- "name": "test_file_2_1",
156
- "title": "",
157
- "target": "",
158
- "link": "",
159
- "onclick": "message('test')",
160
- "icon": "",
161
- "lang": {
162
- "en": "test"
163
- },
164
- "sub": [
165
- {
166
- "name": "test_file_3_1",
167
- "title": "",
168
- "target": "",
169
- "link": "",
170
- "onclick": "message('test')",
171
- "icon": "<img src='/assets/icons/users-cog.svg' />",
172
- "lang": {
173
- "en": "test"
174
- },
175
- "sub": []
176
- },
177
- {
178
- "name": ""
179
- },
180
- {
181
- "name": "test_file_3_2",
182
- "title": "",
183
- "target": "",
184
- "link": "",
185
- "onclick": "message('test')",
186
- "icon": "<img src='/assets/icons/wifi.svg' />",
187
- "lang": {
188
- "en": "test"
189
- },
190
- "sub": []
191
- }
192
- ]
193
- }
194
- ]
195
- },
196
- {
197
- "name": "test_file_5_1",
198
- "title": "",
199
- "target": "",
200
- "link": "",
201
- "onclick": "message('test')",
202
- "icon": "<img src='/assets/icons/wrench.svg' />",
203
- "lang": {
204
- "en": "test"
205
- },
206
- "sub": [
207
- {
208
- "name": "test_file_2_1",
209
- "title": "",
210
- "target": "",
211
- "link": "",
212
- "onclick": "message('test')",
213
- "icon": "",
214
- "lang": {
215
- "en": "test"
216
- },
217
- "sub": [
218
- {
219
- "name": "test_file_3_1",
220
- "title": "",
221
- "target": "",
222
- "link": "",
223
- "onclick": "message('test')",
224
- "icon": "",
225
- "lang": {
226
- "en": "test"
227
- },
228
- "sub": []
229
- },
230
- {
231
- "name": "test_file_3_2",
232
- "title": "",
233
- "target": "",
234
- "link": "",
235
- "onclick": "message('test')",
236
- "icon": "",
237
- "lang": {
238
- "en": "test"
239
- },
240
- "sub": []
241
- }
242
- ]
243
- }
244
- ]
245
- }
246
- ]
247
- },
248
- {
249
- "name": "edit",
250
- "title": "",
251
- "target": "",
252
- "link": "",
253
- "onclick": "",
254
- "icon": "",
255
- "lang": {
256
- "en": "edit"
257
- },
258
- "sub": [
259
- {
260
- "name": "test_edit_1",
261
- "title": "",
262
- "target": "",
263
- "link": "",
264
- "onclick": "message('test')",
265
- "icon": "",
266
- "lang": {
267
- "en": "test"
268
- },
269
- "sub": [
270
- {
271
- "name": "test_edit_1_1",
272
- "title": "",
273
- "target": "",
274
- "link": "",
275
- "onclick": "message('test')",
276
- "icon": "",
277
- "lang": {
278
- "en": "test"
279
- },
280
- "sub": []
281
- },
282
- {
283
- "name": "test_edit_1_2",
284
- "title": "",
285
- "target": "",
286
- "link": "",
287
- "onclick": "message('test')",
288
- "icon": "",
289
- "lang": {
290
- "en": "test"
291
- },
292
- "sub": []
293
- },
294
- {
295
- "name": ""
296
- },
297
- {
298
- "name": "test_edit_1_3",
299
- "title": "",
300
- "target": "",
301
- "link": "",
302
- "onclick": "message('test')",
303
- "icon": "",
304
- "lang": {
305
- "en": "test"
306
- },
307
- "sub": [
308
- {
309
- "name": "test_edit_2_1",
310
- "title": "",
311
- "target": "",
312
- "link": "",
313
- "onclick": "message('test')",
314
- "icon": "",
315
- "lang": {
316
- "en": "test"
317
- },
318
- "sub": []
319
- }
320
- ]
321
- },
322
- {
323
- "name": "test_edit_1_4",
324
- "title": "",
325
- "target": "",
326
- "link": "",
327
- "onclick": "message('test')",
328
- "icon": "",
329
- "lang": {
330
- "en": "test"
331
- },
332
- "sub": []
333
- }
334
- ]
335
- }
336
- ]
337
- },
338
- {
339
- "name": "selection",
340
- "title": "",
341
- "target": "",
342
- "link": "",
343
- "onclick": "message('test')",
344
- "icon": "",
345
- "lang": {
346
- "en": "selection"
347
- },
348
- "sub": []
107
+ ## Example HTML
108
+
109
+ ```html
110
+ <!DOCTYPE html>
111
+ <html>
112
+ <head>
113
+ <title>menupro Demo</title>
114
+ <script src="menupro/index.js"></script>
115
+ </head>
116
+ <body>
117
+ <nav id="navbar"></nav>
118
+
119
+ <script>
120
+ // Define a global function
121
+ function message(text) {
122
+ alert('You clicked: ' + text);
349
123
  }
350
- ]
351
- }
352
124
 
125
+ // Initialize menu
126
+ menupro.start({
127
+ name: 'menupro',
128
+ element: '#navbar',
129
+ nav: [
130
+ { name: 'Home', onclick: "message('Home')" },
131
+ { name: 'Products', sub: [
132
+ { name: 'Software', onclick: "message('Software')" },
133
+ { name: 'Hardware', onclick: "message('Hardware')" }
134
+ ]},
135
+ { name: 'About', onclick: "message('About')" }
136
+ ]
137
+ });
138
+ </script>
139
+ </body>
140
+ </html>
353
141
  ```
142
+
143
+ ## Credits
144
+
145
+ Created by Dario Passariello. Licensed under MIT.
package/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";((d=>{const s=d.createElement('style');s.textContent='@charset "UTF-8";.menupro{position:relative;margin:0;padding:0}.menupro ul,.menupro li{background-color:#000;list-style:none;margin:0;padding:0}.menupro li:hover{transition:0s;transition-delay:0s}.menupro ul,.menupro ul:hover{transition:0s;transition-delay:.5s}.menupro hr{border:1px solid!important;height:0!important;color:#333!important;background-color:#333!important;margin:0;padding:0}.menupro a{padding:4px 10px;display:block;text-align:left;white-space:nowrap}.menupro :hover{background-color:#0b86bf}.menupro li{float:left;position:relative}.menupro li :hover,.menupro li :active{background-color:#0b86bf}.menupro li:hover>ul,.menupro li:focus-within>ul{opacity:1;visibility:visible;transition-delay:visibility 0s}.menupro li>span.icon{position:absolute;left:5px;top:5px;width:13px;height:auto;filter:invert(.5)}.menupro li>span.arrow:before{content:"\\203a";position:absolute;right:5px;top:0;font-size:1.5em;line-height:1em}.menupro li>ul{position:absolute;width:auto;float:left;opacity:0;visibility:hidden;transition-delay:visibility 0s;box-shadow:0 10px 12px -8px #000;padding:0}.menupro li>ul li{float:left;position:relative;width:100%;padding:0}.menupro li>ul li:hover>ul,.menupro li>ul li:focus-within>ul{opacity:1;pointer-events:auto}.menupro li>ul li:not(:visible){pointer-events:none}.menupro li>ul li>ul{position:absolute;margin:0 auto;top:0;left:99%}.menupro li>ul li a{padding:4px 20px 4px 30px}\n';d.head.appendChild(s)})(document));(()=>{var w=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var H=Object.prototype.hasOwnProperty;var u=(t,i)=>()=>(t&&(i=t(t=0)),i);var N=(t,i,p,d)=>{if(i&&typeof i=="object"||typeof i=="function")for(let e of L(i))!H.call(t,e)&&e!==p&&w(t,e,{get:()=>i[e],enumerable:!(d=C(i,e))||d.enumerable});return t};var y=t=>N(w({},"__esModule",{value:!0}),t);var r=u(()=>{});var x=u(()=>{});var P={};var k=u(()=>{"use strict";r();x();menupro.start=t=>{let{element:i,name:p=t.name||"menupro",nav:d=t.nav||[]}=t,e,g,l=a=>document.createElement(a),b=(a,s="."+p)=>{let h=typeof s=="string"?document.querySelector(s):s;h&&a?.map(n=>{if(n.name){e=l("li");let o=l("a");o.textContent=n.name,e.appendChild(o),h.appendChild(e)}if(n.onclick&&n.sub?.length===0){let o;if(typeof n.onclick=="function")o=n.onclick;else if(typeof n.onclick=="string"){let m=n.onclick.trim();if(m.includes("("))o=()=>{try{new Function(m)()}catch(f){console.warn("menupro: onclick error:",f)}};else{let f=window[m];o=f||(()=>{console.warn("menupro: function not found:",m)})}}else o=()=>{};e.addEventListener("click",o)}if(n.name===""&&(e=l("hr"),h.appendChild(e)),s!="."+p){if(n.icon){let o=l("span");o.className="icon",o.innerHTML=n.icon,e.appendChild(o)}if(n.sub?.length>0){let o=l("span");o.className="arrow",e.appendChild(o)}}n.sub?.length>0&&(g=l("ul"),e.appendChild(g)),n.sub?.length>0&&b(n.sub,g)})};setTimeout(()=>{let a=l("ul");a.className=p;let s=typeof i=="string"?document.querySelector(i):i;s&&(s.appendChild(a),b(d,a))},0)}});var c,M=u(()=>{c={app:{port:3002,code:"menupro",proxy:{api:{tst:"http://localhost:5003/",dev:"https://a51.dev/",pro:"https://a51.dev/"}},socket:{url:{tst:"wss://ws.a51.dev/",dev:"wss://ws.a51.dev/",pro:"wss://ws.a51.dev/"}},info:{},cdn:{}}}});var q={};var E=u(()=>{"use strict";r();M();Object.defineProperty(menupro,"credits",{value:()=>{console.groupCollapsed(`%c${c.app.code} v0%c`,"color:orange",""),console.debug(`%c${c.app.code} v0%c by Dario Passariello started`,"color:orange",""),console.debug(`%cType ${c.app.code} in this console to see it`,"color:gray",""),console.debug("code: %c"+c.app.code,"color:orange",""),console.groupEnd()},writable:!1,configurable:!1,enumerable:!1})});r();r();var T=()=>{window.menupro||(Object.defineProperty(window,"menupro",{value:{start:{}},writable:!1,configurable:!1,enumerable:!1}),k(),E(),y(q))};T();})();
1
+ "use strict";((d=>{const s=d.createElement('style');s.textContent='@charset "UTF-8";.menupro{position:relative;margin:0;padding:0}.menupro ul,.menupro li{background-color:#000;list-style:none;margin:0;padding:0}.menupro li:hover{transition:0s;transition-delay:0s}.menupro ul,.menupro ul:hover{transition:0s;transition-delay:.5s}.menupro hr{border:1px solid!important;height:0!important;color:#333!important;background-color:#333!important;margin:0;padding:0}.menupro a{padding:4px 10px;display:block;text-align:left;white-space:nowrap}.menupro :hover{background-color:#0b86bf}.menupro li{float:left;position:relative}.menupro li :hover,.menupro li :active{background-color:#0b86bf}.menupro li:hover>ul,.menupro li:focus-within>ul{opacity:1;visibility:visible;transition-delay:visibility 0s}.menupro li>span.icon{position:absolute;left:5px;top:5px;width:13px;height:auto;filter:invert(.5)}.menupro li>span.arrow:before{content:"\\203a";position:absolute;right:5px;top:0;font-size:1.5em;line-height:1em}.menupro li>ul{position:absolute;width:auto;float:left;opacity:0;visibility:hidden;transition-delay:visibility 0s;box-shadow:0 10px 12px -8px #000;padding:0}.menupro li>ul li{float:left;position:relative;width:100%;padding:0}.menupro li>ul li:hover>ul,.menupro li>ul li:focus-within>ul{opacity:1;pointer-events:auto}.menupro li>ul li:not(:visible){pointer-events:none}.menupro li>ul li>ul{position:absolute;margin:0 auto;top:0;left:99%}.menupro li>ul li a{padding:4px 20px 4px 30px}\n';d.head.appendChild(s)})(document));(()=>{var L=Object.defineProperty;var A=Object.getOwnPropertyDescriptor;var F=Object.getOwnPropertyNames;var O=Object.prototype.hasOwnProperty;var g=(n,r)=>()=>(n&&(r=n(n=0)),r);var z=(n,r,m,v)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of F(r))!O.call(n,o)&&o!==m&&L(n,o,{get:()=>r[o],enumerable:!(v=A(r,o))||v.enumerable});return n};var H=n=>z(L({},"__esModule",{value:!0}),n);var l=g(()=>{});var $=g(()=>{});var U={};var K,I,q=g(()=>{"use strict";l();$();K=new Set(["eval","Function","exec","spawn","execSync","fetch","XMLHttpRequest","WebSocket","importScripts","setTimeout","setInterval","setImmediate","document.write","document.writeln","innerHTML","outerHTML","location","location.href","location.assign","location.replace","history.pushState","history.replaceState","localStorage","sessionStorage","cookie","postMessage","import","require"]),I=n=>/^[a-zA-Z_$][a-zA-Z0-9_$.]*$/.test(n)&&!K.has(n)&&!n.includes("__");menupro.start=n=>{let{element:r,name:m=n.name||"menupro",nav:v=n.nav||[]}=n,o,y,c=p=>document.createElement(p),N=(p,d="."+m)=>{let k=typeof d=="string"?document.querySelector(d):d;k&&p?.map(i=>{if(i.name){o=c("li");let e=c("a");e.textContent=i.name,o.appendChild(e),k.appendChild(o)}if(i.onclick&&i.sub?.length===0){let e;if(typeof i.onclick=="function")e=i.onclick;else if(typeof i.onclick=="string"){let a=i.onclick.trim();if(a.includes("(")&&a.endsWith(")")){let h=a.match(/^(\w+)\((.*)\)$/);if(h){let[,w,E]=h;if(!I(w))e=()=>{console.warn("menupro: blocked dangerous function:",w)};else{let x=window[w];if(x&&typeof x=="function"){let C=s=>{let t=s.trim();if(t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'"))return t.slice(1,-1);if(!isNaN(Number(t)))return Number(t);if(t==="true")return!0;if(t==="false")return!1;if(t==="null")return null;t!=="undefined"&&console.warn("menupro: variable reference blocked:",t)},M=[];if(E.trim()){let s="",t=0,f=!1,S="";for(let u of E)(u==='"'||u==="'")&&s.slice(-1)!=="\\"&&(f?u===S&&(f=!1,S=""):(f=!0,S=u)),!f&&u==="("&&t++,!f&&u===")"&&t--,!f&&t===0&&u===","?(M.push(C(s)),s=""):s+=u;s.trim()&&M.push(C(s))}e=()=>{try{x(...M)}catch(s){console.warn("menupro: onclick error:",s)}}}else e=()=>{console.warn("menupro: function not found:",w)}}}else e=()=>{console.warn("menupro: invalid function call:",a)}}else if(!I(a))e=()=>{console.warn("menupro: blocked dangerous function:",a)};else{let h=window[a];e=h||(()=>{console.warn("menupro: function not found:",a)})}}else e=()=>{};o.addEventListener("click",e)}if(i.name===""&&(o=c("hr"),k.appendChild(o)),d!="."+m){if(i.icon){let e=c("span");e.className="icon",e.innerHTML=i.icon,o.appendChild(e)}if(i.sub?.length>0){let e=c("span");e.className="arrow",o.appendChild(e)}}i.sub?.length>0&&(y=c("ul"),o.appendChild(y)),i.sub?.length>0&&N(i.sub,y)})};setTimeout(()=>{let p=c("ul");p.className=m;let d=typeof r=="string"?document.querySelector(r):r;d&&(d.appendChild(p),N(v,p))},0)}});var b,W=g(()=>{b={app:{port:3002,code:"menupro",proxy:{api:{tst:"http://localhost:5003/",dev:"https://a51.dev/",pro:"https://a51.dev/"}},socket:{url:{tst:"wss://ws.a51.dev/",dev:"wss://ws.a51.dev/",pro:"wss://ws.a51.dev/"}},info:{},cdn:{}}}});var D={};var P=g(()=>{"use strict";l();W();Object.defineProperty(menupro,"credits",{value:()=>{console.groupCollapsed(`%c${b.app.code} v0%c`,"color:orange",""),console.debug(`%c${b.app.code} v0%c by Dario Passariello started`,"color:orange",""),console.debug(`%cType ${b.app.code} in this console to see it`,"color:gray",""),console.debug("code: %c"+b.app.code,"color:orange",""),console.groupEnd()},writable:!1,configurable:!1,enumerable:!1})});l();l();var _=()=>{window.menupro||(Object.defineProperty(window,"menupro",{value:{start:{}},writable:!1,configurable:!1,enumerable:!1}),q(),P(),H(D))};_();})();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "menupro",
3
3
  "description": "custom menu like OS by Dario Passariello",
4
- "version": "2.0.0",
4
+ "version": "2.0.2",
5
5
  "copyright": "Dario Passariello",
6
6
  "keywords": [
7
7
  "layer",
@@ -54,4 +54,4 @@
54
54
  "tslib": "2.8.1",
55
55
  "typescript": "5.9.3"
56
56
  }
57
- }
57
+ }