@asup/context-menu 1.0.0 → 1.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.
- package/README.md +18 -33
- package/dist/cjs/main.css +27 -14
- package/dist/cjs/main.css.map +1 -1
- package/dist/cjs/main.js +65 -9
- package/dist/cjs/main.js.map +1 -1
- package/dist/context-menu.d.ts +4 -1
- package/dist/context-menu.d.ts.map +1 -1
- package/dist/main.css +27 -14
- package/dist/main.css.map +1 -1
- package/dist/main.js +63 -9
- package/dist/main.js.map +1 -1
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -22,41 +22,26 @@ npm install @asup/context-menu
|
|
|
22
22
|
## Usage
|
|
23
23
|
|
|
24
24
|
Context menu provider, takes a list of available actions and renders a context menu on appropriate click.
|
|
25
|
+
Sub menus can be added within each item.
|
|
26
|
+
Wrap around the elements that need to have the menu.
|
|
25
27
|
|
|
26
28
|
```
|
|
27
|
-
import { ContextMenuProvider, iMenuItem
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const showMenu = useCallback((e) => {
|
|
37
|
-
e.preventDefault();
|
|
38
|
-
e.stopPropagation();
|
|
39
|
-
const menuItems: iMenuItem[] = [
|
|
40
|
-
{ label: 'Item 1', action: item1Function },
|
|
41
|
-
{ label: 'Item 2', action: item2Function },
|
|
42
|
-
...
|
|
43
|
-
];
|
|
44
|
-
menuContext.set && menuContext.set({
|
|
45
|
-
visible: true,
|
|
46
|
-
y: e.pageY,
|
|
47
|
-
x: e.pageX,
|
|
48
|
-
menuItems: menuItems,
|
|
49
|
-
});
|
|
29
|
+
import { ContextMenuProvider, iMenuItem } from '@asup/context-menu';
|
|
30
|
+
|
|
31
|
+
<ContextMenuHandler
|
|
32
|
+
menuItems={[
|
|
33
|
+
{ label: 'Item 1', action: item1Function },
|
|
34
|
+
{ label: 'Item 2', action: item2Function, group: [
|
|
35
|
+
{ label: 'Subitem 2.1', action: item21Function }
|
|
36
|
+
...
|
|
37
|
+
]
|
|
50
38
|
},
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
39
|
+
{ label: 'Item 3', action: item3Function, disabeld: true },
|
|
40
|
+
...
|
|
41
|
+
]}
|
|
42
|
+
>
|
|
43
|
+
<Chilren
|
|
44
|
+
where the context menu is applied...
|
|
45
|
+
/>
|
|
59
46
|
</ContextMenuProvider>
|
|
60
47
|
```
|
|
61
|
-
|
|
62
|
-
Add an `onContextMenu` action to an element inside the `ContextMenuProvider`, and create a corresponding function that loads the menuItems array and then sets it to visible.
|
package/dist/cjs/main.css
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
.context-menu-handler {
|
|
2
|
-
height: -webkit-fit-content;
|
|
3
|
-
height: -moz-fit-content;
|
|
4
|
-
height: fit-content;
|
|
5
|
-
width: -webkit-fit-content;
|
|
6
|
-
width: -moz-fit-content;
|
|
7
|
-
width: fit-content;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
1
|
.context-menu {
|
|
11
2
|
visibility: hidden;
|
|
12
3
|
opacity: 1;
|
|
@@ -25,27 +16,49 @@
|
|
|
25
16
|
color: #111418;
|
|
26
17
|
cursor: pointer;
|
|
27
18
|
min-width: 80px;
|
|
19
|
+
height: 21px;
|
|
20
|
+
white-space: nowrap;
|
|
21
|
+
flex-direction: row;
|
|
22
|
+
justify-content: space-between;
|
|
28
23
|
padding: 0 4px;
|
|
24
|
+
display: flex;
|
|
25
|
+
position: relative;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.context-menu-item.disabled {
|
|
29
|
+
cursor: not-allowed;
|
|
30
|
+
background-color: rgba(0, 0, 0, .2);
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
.context-menu-item:first-child {
|
|
32
|
-
padding-top:
|
|
34
|
+
padding-top: 4px;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
.context-menu-item:last-child {
|
|
36
|
-
padding-bottom:
|
|
38
|
+
padding-bottom: 4px;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
.context-menu-item:hover {
|
|
41
|
+
.context-menu-item:not(.disabled):hover {
|
|
40
42
|
background-color: #fbe9e6;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
.context-menu-item:hover:first-child {
|
|
44
|
-
border-radius: 6px
|
|
46
|
+
border-top-left-radius: 6px;
|
|
47
|
+
border-top-right-radius: 6px;
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
.context-menu-item:hover:last-child {
|
|
48
|
-
border-radius:
|
|
51
|
+
border-bottom-right-radius: 6px;
|
|
52
|
+
border-bottom-left-radius: 6px;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.context-menu-item .caret-holder {
|
|
56
|
+
align-self: flex-end;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.context-menu-item .caret-holder .sub-menu {
|
|
60
|
+
z-index: 1;
|
|
61
|
+
position: relative;
|
|
49
62
|
}
|
|
50
63
|
|
|
51
64
|
/*# sourceMappingURL=main.css.map */
|
package/dist/cjs/main.css.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"AAAA
|
|
1
|
+
{"mappings":"AAAA;;;;;;;;;;AAWA;;;;AAIA;;;;;;;;;;;;;AAaA;;;;;AAKA;;;;AAIA;;;;AAIA;;;;AAIA;;;;;AAKA;;;;;AAKA;;;;AAIA","sources":["src/components/ContextMenu.scss"],"sourcesContent":[".context-menu {\n position: absolute;\n visibility: hidden;\n border: 1px solid;\n border-color: rgb(17, 20, 24);\n border-radius: 8px;\n opacity: 1;\n background-color: rgb(251, 253, 246);\n z-index: 10000;\n}\n\n.context-menu.visible {\n visibility: inherit;\n}\n\n.context-menu-item {\n color: rgb(17, 20, 24);\n cursor: pointer;\n padding: 0 4px;\n min-width: 80px;\n height: 21px;\n position: relative;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n white-space: nowrap;\n}\n\n.context-menu-item.disabled {\n background-color: rgba(0, 0, 0, 0.2);\n cursor: not-allowed;\n}\n\n.context-menu-item:first-child {\n padding-top: 4px;\n}\n\n.context-menu-item:last-child {\n padding-bottom: 4px;\n}\n\n.context-menu-item:not(.disabled):hover {\n background-color: rgb(251, 233, 230);\n}\n\n.context-menu-item:hover:first-child {\n border-top-left-radius: 6px;\n border-top-right-radius: 6px;\n}\n\n.context-menu-item:hover:last-child {\n border-bottom-left-radius: 6px;\n border-bottom-right-radius: 6px;\n}\n\n.context-menu-item .caret-holder {\n align-self: flex-end;\n}\n\n.context-menu-item .caret-holder .sub-menu {\n z-index: 1;\n position: relative;\n}\n"],"names":[],"version":3,"file":"main.css.map"}
|
package/dist/cjs/main.js
CHANGED
|
@@ -35,24 +35,75 @@ $parcel$export($a68bd8a6c0fd98c2$exports, "ContextMenuHandler", function () { re
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
var $2275c4645c0c5e94$export$a9c522a6d7beb830 = function(param) {
|
|
43
|
+
var entries = param.entries, toClose = param.toClose;
|
|
44
|
+
var _useState = (0, ($parcel$interopDefault($gTuX4$swchelperslib_sliced_to_arrayjs)))((0, $gTuX4$react.useState)(false), 2), visible = _useState[0], setVisible = _useState[1];
|
|
45
|
+
return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsxs)("span", {
|
|
46
|
+
className: "caret-holder",
|
|
47
|
+
onMouseEnter: function() {
|
|
48
|
+
setVisible(true);
|
|
49
|
+
},
|
|
50
|
+
onMouseLeave: function() {
|
|
51
|
+
setVisible(false);
|
|
52
|
+
},
|
|
53
|
+
children: [
|
|
54
|
+
/*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("svg", {
|
|
55
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
56
|
+
width: "16",
|
|
57
|
+
height: "16",
|
|
58
|
+
fill: "currentColor",
|
|
59
|
+
viewBox: "0 0 16 16",
|
|
60
|
+
children: /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("path", {
|
|
61
|
+
d: "m12.14 8.753-5.482 4.796c-.646.566-1.658.106-1.658-.753V3.204a1 1 0 0 1 1.659-.753l5.48 4.796a1 1 0 0 1 0 1.506z"
|
|
62
|
+
})
|
|
63
|
+
}),
|
|
64
|
+
/*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", {
|
|
65
|
+
className: "sub-menu",
|
|
66
|
+
children: /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $5150b66b01c99189$export$8dc6765e8be191c7), {
|
|
67
|
+
visible: visible,
|
|
68
|
+
entries: entries,
|
|
69
|
+
xPos: 14,
|
|
70
|
+
yPos: -21,
|
|
71
|
+
toClose: toClose
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
]
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
|
|
38
79
|
var $5150b66b01c99189$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, ($parcel$interopDefault($gTuX4$react))).forwardRef(function(param, ref) {
|
|
39
|
-
var entries = param.entries, xPos = param.xPos, yPos = param.yPos, toClose = param.toClose;
|
|
80
|
+
var visible = param.visible, entries = param.entries, xPos = param.xPos, yPos = param.yPos, toClose = param.toClose;
|
|
40
81
|
$5150b66b01c99189$export$8dc6765e8be191c7.displayName = "ContextMenu";
|
|
41
82
|
return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", {
|
|
42
83
|
ref: ref,
|
|
43
|
-
className: "context-menu visible",
|
|
84
|
+
className: "context-menu".concat(visible ? " visible" : ""),
|
|
44
85
|
style: {
|
|
45
86
|
top: "".concat(yPos, "px"),
|
|
46
87
|
left: "".concat(xPos, "px")
|
|
47
88
|
},
|
|
48
89
|
children: entries.map(function(e, i) {
|
|
49
|
-
return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.
|
|
50
|
-
className: "context-menu-item",
|
|
51
|
-
onClick: function() {
|
|
52
|
-
|
|
53
|
-
|
|
90
|
+
return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsxs)("div", {
|
|
91
|
+
className: "context-menu-item".concat(e.disabled ? " disabled" : ""),
|
|
92
|
+
onClick: function(ev) {
|
|
93
|
+
ev.preventDefault();
|
|
94
|
+
ev.stopPropagation();
|
|
95
|
+
e.action && !e.disabled && e.action();
|
|
96
|
+
!e.disabled && toClose();
|
|
54
97
|
},
|
|
55
|
-
children:
|
|
98
|
+
children: [
|
|
99
|
+
/*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("span", {
|
|
100
|
+
children: e.label
|
|
101
|
+
}),
|
|
102
|
+
e.group && /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $2275c4645c0c5e94$export$a9c522a6d7beb830), {
|
|
103
|
+
toClose: toClose,
|
|
104
|
+
entries: e.group
|
|
105
|
+
})
|
|
106
|
+
]
|
|
56
107
|
}, i);
|
|
57
108
|
})
|
|
58
109
|
});
|
|
@@ -61,7 +112,10 @@ var $5150b66b01c99189$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, ($parcel$inter
|
|
|
61
112
|
|
|
62
113
|
|
|
63
114
|
var $3c568ee547c732c3$export$ed4f9641643dc7e4 = function(param) {
|
|
64
|
-
var children = param.children, menuItems = param.menuItems
|
|
115
|
+
var children = param.children, menuItems = param.menuItems, _param_style = param.style, style = _param_style === void 0 ? {
|
|
116
|
+
height: "fit-content",
|
|
117
|
+
width: "fit-content"
|
|
118
|
+
} : _param_style;
|
|
65
119
|
// Menu resources
|
|
66
120
|
var divRef = (0, $gTuX4$react.useRef)(null);
|
|
67
121
|
var menuRef = (0, $gTuX4$react.useRef)(null);
|
|
@@ -97,6 +151,7 @@ var $3c568ee547c732c3$export$ed4f9641643dc7e4 = function(param) {
|
|
|
97
151
|
/*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", {
|
|
98
152
|
onContextMenu: showMenu,
|
|
99
153
|
className: "context-menu-handler",
|
|
154
|
+
style: style,
|
|
100
155
|
children: children
|
|
101
156
|
}),
|
|
102
157
|
menuVisible && /*#__PURE__*/ (0, $gTuX4$reactdom.createPortal)(/*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", {
|
|
@@ -107,6 +162,7 @@ var $3c568ee547c732c3$export$ed4f9641643dc7e4 = function(param) {
|
|
|
107
162
|
},
|
|
108
163
|
ref: divRef,
|
|
109
164
|
children: /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $5150b66b01c99189$export$8dc6765e8be191c7), {
|
|
165
|
+
visible: true,
|
|
110
166
|
ref: menuRef,
|
|
111
167
|
entries: menuItems,
|
|
112
168
|
xPos: menuXPos,
|
package/dist/cjs/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AEAA;;;;ACAA;;
|
|
1
|
+
{"mappings":"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","sources":["src/main.ts","src/components/index.ts","src/components/ContextMenuHandler.tsx","src/components/ContextMenu.tsx","src/components/SubMenu.tsx"],"sourcesContent":["export * from './components';\n","import { ContextMenuHandler } from './ContextMenuHandler';\nimport { iMenuItem } from './interface';\n\nexport { ContextMenuHandler };\nexport type { iMenuItem };\n","import { MouseEvent, useCallback, useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { ContextMenu } from './ContextMenu';\nimport { iMenuItem } from './interface';\nimport './ContextMenu.scss';\n\nexport const ContextMenuHandler = ({\n children,\n menuItems,\n style = {\n height: 'fit-content',\n width: 'fit-content',\n },\n}: {\n children: JSX.Element[] | JSX.Element;\n menuItems: iMenuItem[];\n style?: React.CSSProperties;\n}): JSX.Element => {\n // Menu resources\n const divRef = useRef<HTMLDivElement | null>(null);\n const menuRef = useRef<HTMLDivElement | null>(null);\n const [menuXPos, setMenuXPos] = useState<number>(0);\n const [menuYPos, setMenuYPos] = useState<number>(0);\n const [menuVisible, setMenuVisible] = useState<boolean>(false);\n\n // Show menu when context is requested\n const showMenu = (e: MouseEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n setMenuVisible(true);\n setMenuXPos(e.pageX);\n setMenuYPos(e.pageY);\n };\n\n // Handle click off the menu\n const handleClick = useCallback((e: globalThis.MouseEvent) => {\n if (\n menuRef.current &&\n ((e.target instanceof Element && !menuRef.current?.contains(e.target)) ||\n !(e.target instanceof Element))\n ) {\n setMenuVisible(false);\n }\n }, []);\n\n // Update the document click handler\n useEffect(() => {\n if (menuVisible) document.addEventListener('mousedown', handleClick);\n else document.removeEventListener('mousedown', handleClick);\n return () => {\n document.removeEventListener('mousedown', handleClick);\n };\n }, [handleClick, menuVisible]);\n\n return (\n <>\n <div\n onContextMenu={showMenu}\n className='context-menu-handler'\n style={style}\n >\n {children}\n </div>\n {menuVisible &&\n createPortal(\n <div\n style={{ position: 'absolute', top: 0, left: 0 }}\n ref={divRef}\n >\n <ContextMenu\n visible={true}\n ref={menuRef}\n entries={menuItems}\n xPos={menuXPos}\n yPos={menuYPos}\n toClose={() => setMenuVisible(false)}\n />\n </div>,\n document.body,\n )}\n </>\n );\n};\n","import React from 'react';\nimport { iMenuItem } from './interface';\nimport { SubMenu } from './SubMenu';\n\nexport interface contextMenuProps {\n visible: boolean;\n entries: iMenuItem[];\n xPos: number;\n yPos: number;\n toClose: () => void;\n}\n\nexport const ContextMenu = React.forwardRef<HTMLDivElement, contextMenuProps>(\n ({ visible, entries, xPos, yPos, toClose }, ref): JSX.Element => {\n ContextMenu.displayName = 'ContextMenu';\n\n return (\n <div\n ref={ref}\n className={`context-menu${visible ? ' visible' : ''}`}\n style={{\n top: `${yPos}px`,\n left: `${xPos}px`,\n }}\n >\n {entries.map((e, i) => (\n <div\n key={i}\n className={`context-menu-item${e.disabled ? ' disabled' : ''}`}\n onClick={(ev) => {\n ev.preventDefault();\n ev.stopPropagation();\n e.action && !e.disabled && e.action();\n !e.disabled && toClose();\n }}\n >\n <span>{e.label}</span>\n {e.group && (\n <SubMenu\n toClose={toClose}\n entries={e.group}\n />\n )}\n </div>\n ))}\n </div>\n );\n },\n);\n","import { useState } from 'react';\nimport { ContextMenu } from './ContextMenu';\nimport { iMenuItem } from './interface';\n\nexport interface subMenuProps {\n entries: iMenuItem[];\n toClose: () => void;\n}\n\nexport const SubMenu = ({ entries, toClose }: subMenuProps): JSX.Element => {\n const [visible, setVisible] = useState<boolean>(false);\n\n return (\n <span\n className='caret-holder'\n onMouseEnter={() => {\n setVisible(true);\n }}\n onMouseLeave={() => {\n setVisible(false);\n }}\n >\n <svg\n xmlns='http://www.w3.org/2000/svg'\n width='16'\n height='16'\n fill='currentColor'\n viewBox='0 0 16 16'\n >\n <path d='m12.14 8.753-5.482 4.796c-.646.566-1.658.106-1.658-.753V3.204a1 1 0 0 1 1.659-.753l5.48 4.796a1 1 0 0 1 0 1.506z' />\n </svg>\n <div className='sub-menu'>\n <ContextMenu\n visible={visible}\n entries={entries}\n xPos={14}\n yPos={-21}\n toClose={toClose}\n />\n </div>\n </span>\n );\n};\n"],"names":[],"version":3,"file":"main.js.map"}
|
package/dist/context-menu.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
export interface iMenuItem {
|
|
2
2
|
label: string;
|
|
3
|
+
disabled?: boolean;
|
|
3
4
|
action?: () => void;
|
|
5
|
+
group?: iMenuItem[];
|
|
4
6
|
}
|
|
5
|
-
export const ContextMenuHandler: ({ children, menuItems, }: {
|
|
7
|
+
export const ContextMenuHandler: ({ children, menuItems, style, }: {
|
|
6
8
|
children: JSX.Element[] | JSX.Element;
|
|
7
9
|
menuItems: iMenuItem[];
|
|
10
|
+
style?: import("react").CSSProperties | undefined;
|
|
8
11
|
}) => JSX.Element;
|
|
9
12
|
|
|
10
13
|
//# sourceMappingURL=context-menu.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"AAAA;IACE,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;
|
|
1
|
+
{"mappings":"AAAA;IACE,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;CACrB;AGCD,OAAO,MAAM;cAQD,WAAW,EAAE,GAAG,WAAW;eAC1B,SAAS,EAAE;;MAEpB,WAiEH,CAAC","sources":["src/src/components/interface.ts","src/src/components/SubMenu.tsx","src/src/components/ContextMenu.tsx","src/src/components/ContextMenuHandler.tsx","src/src/components/index.ts","src/src/main.ts","src/main.ts"],"sourcesContent":[null,null,null,null,null,null,"export * from './components';\n"],"names":[],"version":3,"file":"context-menu.d.ts.map"}
|
package/dist/main.css
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
.context-menu-handler {
|
|
2
|
-
height: -webkit-fit-content;
|
|
3
|
-
height: -moz-fit-content;
|
|
4
|
-
height: fit-content;
|
|
5
|
-
width: -webkit-fit-content;
|
|
6
|
-
width: -moz-fit-content;
|
|
7
|
-
width: fit-content;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
1
|
.context-menu {
|
|
11
2
|
visibility: hidden;
|
|
12
3
|
opacity: 1;
|
|
@@ -25,27 +16,49 @@
|
|
|
25
16
|
color: #111418;
|
|
26
17
|
cursor: pointer;
|
|
27
18
|
min-width: 80px;
|
|
19
|
+
height: 21px;
|
|
20
|
+
white-space: nowrap;
|
|
21
|
+
flex-direction: row;
|
|
22
|
+
justify-content: space-between;
|
|
28
23
|
padding: 0 4px;
|
|
24
|
+
display: flex;
|
|
25
|
+
position: relative;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.context-menu-item.disabled {
|
|
29
|
+
cursor: not-allowed;
|
|
30
|
+
background-color: rgba(0, 0, 0, .2);
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
.context-menu-item:first-child {
|
|
32
|
-
padding-top:
|
|
34
|
+
padding-top: 4px;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
.context-menu-item:last-child {
|
|
36
|
-
padding-bottom:
|
|
38
|
+
padding-bottom: 4px;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
.context-menu-item:hover {
|
|
41
|
+
.context-menu-item:not(.disabled):hover {
|
|
40
42
|
background-color: #fbe9e6;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
.context-menu-item:hover:first-child {
|
|
44
|
-
border-radius: 6px
|
|
46
|
+
border-top-left-radius: 6px;
|
|
47
|
+
border-top-right-radius: 6px;
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
.context-menu-item:hover:last-child {
|
|
48
|
-
border-radius:
|
|
51
|
+
border-bottom-right-radius: 6px;
|
|
52
|
+
border-bottom-left-radius: 6px;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.context-menu-item .caret-holder {
|
|
56
|
+
align-self: flex-end;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.context-menu-item .caret-holder .sub-menu {
|
|
60
|
+
z-index: 1;
|
|
61
|
+
position: relative;
|
|
49
62
|
}
|
|
50
63
|
|
|
51
64
|
/*# sourceMappingURL=main.css.map */
|
package/dist/main.css.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"AAAA
|
|
1
|
+
{"mappings":"AAAA;;;;;;;;;;AAWA;;;;AAIA;;;;;;;;;;;;;AAaA;;;;;AAKA;;;;AAIA;;;;AAIA;;;;AAIA;;;;;AAKA;;;;;AAKA;;;;AAIA","sources":["src/components/ContextMenu.scss"],"sourcesContent":[".context-menu {\n position: absolute;\n visibility: hidden;\n border: 1px solid;\n border-color: rgb(17, 20, 24);\n border-radius: 8px;\n opacity: 1;\n background-color: rgb(251, 253, 246);\n z-index: 10000;\n}\n\n.context-menu.visible {\n visibility: inherit;\n}\n\n.context-menu-item {\n color: rgb(17, 20, 24);\n cursor: pointer;\n padding: 0 4px;\n min-width: 80px;\n height: 21px;\n position: relative;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n white-space: nowrap;\n}\n\n.context-menu-item.disabled {\n background-color: rgba(0, 0, 0, 0.2);\n cursor: not-allowed;\n}\n\n.context-menu-item:first-child {\n padding-top: 4px;\n}\n\n.context-menu-item:last-child {\n padding-bottom: 4px;\n}\n\n.context-menu-item:not(.disabled):hover {\n background-color: rgb(251, 233, 230);\n}\n\n.context-menu-item:hover:first-child {\n border-top-left-radius: 6px;\n border-top-right-radius: 6px;\n}\n\n.context-menu-item:hover:last-child {\n border-bottom-left-radius: 6px;\n border-bottom-right-radius: 6px;\n}\n\n.context-menu-item .caret-holder {\n align-self: flex-end;\n}\n\n.context-menu-item .caret-holder .sub-menu {\n z-index: 1;\n position: relative;\n}\n"],"names":[],"version":3,"file":"main.css.map"}
|
package/dist/main.js
CHANGED
|
@@ -14,29 +14,81 @@ $parcel$export($b65191f6d0a0a991$exports, "ContextMenuHandler", function () { re
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
const $885a1576aecbe1c6$export$a9c522a6d7beb830 = ({ entries: entries , toClose: toClose })=>{
|
|
21
|
+
const [visible, setVisible] = (0, $duWW8$useState)(false);
|
|
22
|
+
return /*#__PURE__*/ (0, $duWW8$jsxs)("span", {
|
|
23
|
+
className: "caret-holder",
|
|
24
|
+
onMouseEnter: ()=>{
|
|
25
|
+
setVisible(true);
|
|
26
|
+
},
|
|
27
|
+
onMouseLeave: ()=>{
|
|
28
|
+
setVisible(false);
|
|
29
|
+
},
|
|
30
|
+
children: [
|
|
31
|
+
/*#__PURE__*/ (0, $duWW8$jsx)("svg", {
|
|
32
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
33
|
+
width: "16",
|
|
34
|
+
height: "16",
|
|
35
|
+
fill: "currentColor",
|
|
36
|
+
viewBox: "0 0 16 16",
|
|
37
|
+
children: /*#__PURE__*/ (0, $duWW8$jsx)("path", {
|
|
38
|
+
d: "m12.14 8.753-5.482 4.796c-.646.566-1.658.106-1.658-.753V3.204a1 1 0 0 1 1.659-.753l5.48 4.796a1 1 0 0 1 0 1.506z"
|
|
39
|
+
})
|
|
40
|
+
}),
|
|
41
|
+
/*#__PURE__*/ (0, $duWW8$jsx)("div", {
|
|
42
|
+
className: "sub-menu",
|
|
43
|
+
children: /*#__PURE__*/ (0, $duWW8$jsx)((0, $567ed433af94513f$export$8dc6765e8be191c7), {
|
|
44
|
+
visible: visible,
|
|
45
|
+
entries: entries,
|
|
46
|
+
xPos: 14,
|
|
47
|
+
yPos: -21,
|
|
48
|
+
toClose: toClose
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
]
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
const $567ed433af94513f$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, $duWW8$react).forwardRef(({ visible: visible , entries: entries , xPos: xPos , yPos: yPos , toClose: toClose }, ref)=>{
|
|
18
57
|
$567ed433af94513f$export$8dc6765e8be191c7.displayName = "ContextMenu";
|
|
19
58
|
return /*#__PURE__*/ (0, $duWW8$jsx)("div", {
|
|
20
59
|
ref: ref,
|
|
21
|
-
className:
|
|
60
|
+
className: `context-menu${visible ? " visible" : ""}`,
|
|
22
61
|
style: {
|
|
23
62
|
top: `${yPos}px`,
|
|
24
63
|
left: `${xPos}px`
|
|
25
64
|
},
|
|
26
|
-
children: entries.map((e, i)=>/*#__PURE__*/ (0, $duWW8$
|
|
27
|
-
className:
|
|
28
|
-
onClick: ()=>{
|
|
29
|
-
|
|
30
|
-
|
|
65
|
+
children: entries.map((e, i)=>/*#__PURE__*/ (0, $duWW8$jsxs)("div", {
|
|
66
|
+
className: `context-menu-item${e.disabled ? " disabled" : ""}`,
|
|
67
|
+
onClick: (ev)=>{
|
|
68
|
+
ev.preventDefault();
|
|
69
|
+
ev.stopPropagation();
|
|
70
|
+
e.action && !e.disabled && e.action();
|
|
71
|
+
!e.disabled && toClose();
|
|
31
72
|
},
|
|
32
|
-
children:
|
|
73
|
+
children: [
|
|
74
|
+
/*#__PURE__*/ (0, $duWW8$jsx)("span", {
|
|
75
|
+
children: e.label
|
|
76
|
+
}),
|
|
77
|
+
e.group && /*#__PURE__*/ (0, $duWW8$jsx)((0, $885a1576aecbe1c6$export$a9c522a6d7beb830), {
|
|
78
|
+
toClose: toClose,
|
|
79
|
+
entries: e.group
|
|
80
|
+
})
|
|
81
|
+
]
|
|
33
82
|
}, i))
|
|
34
83
|
});
|
|
35
84
|
});
|
|
36
85
|
|
|
37
86
|
|
|
38
87
|
|
|
39
|
-
const $1e1c1e9e0b943830$export$ed4f9641643dc7e4 = ({ children: children , menuItems: menuItems
|
|
88
|
+
const $1e1c1e9e0b943830$export$ed4f9641643dc7e4 = ({ children: children , menuItems: menuItems , style: style = {
|
|
89
|
+
height: "fit-content",
|
|
90
|
+
width: "fit-content"
|
|
91
|
+
} })=>{
|
|
40
92
|
// Menu resources
|
|
41
93
|
const divRef = (0, $duWW8$useRef)(null);
|
|
42
94
|
const menuRef = (0, $duWW8$useRef)(null);
|
|
@@ -72,6 +124,7 @@ const $1e1c1e9e0b943830$export$ed4f9641643dc7e4 = ({ children: children , menuIt
|
|
|
72
124
|
/*#__PURE__*/ (0, $duWW8$jsx)("div", {
|
|
73
125
|
onContextMenu: showMenu,
|
|
74
126
|
className: "context-menu-handler",
|
|
127
|
+
style: style,
|
|
75
128
|
children: children
|
|
76
129
|
}),
|
|
77
130
|
menuVisible && /*#__PURE__*/ (0, $duWW8$createPortal)(/*#__PURE__*/ (0, $duWW8$jsx)("div", {
|
|
@@ -82,6 +135,7 @@ const $1e1c1e9e0b943830$export$ed4f9641643dc7e4 = ({ children: children , menuIt
|
|
|
82
135
|
},
|
|
83
136
|
ref: divRef,
|
|
84
137
|
children: /*#__PURE__*/ (0, $duWW8$jsx)((0, $567ed433af94513f$export$8dc6765e8be191c7), {
|
|
138
|
+
visible: true,
|
|
85
139
|
ref: menuRef,
|
|
86
140
|
entries: menuItems,
|
|
87
141
|
xPos: menuXPos,
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;;;;;;;;;AEAA;;;ACAA;;
|
|
1
|
+
{"mappings":"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","sources":["src/main.ts","src/components/index.ts","src/components/ContextMenuHandler.tsx","src/components/ContextMenu.tsx","src/components/SubMenu.tsx"],"sourcesContent":["export * from './components';\n","import { ContextMenuHandler } from './ContextMenuHandler';\nimport { iMenuItem } from './interface';\n\nexport { ContextMenuHandler };\nexport type { iMenuItem };\n","import { MouseEvent, useCallback, useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { ContextMenu } from './ContextMenu';\nimport { iMenuItem } from './interface';\nimport './ContextMenu.scss';\n\nexport const ContextMenuHandler = ({\n children,\n menuItems,\n style = {\n height: 'fit-content',\n width: 'fit-content',\n },\n}: {\n children: JSX.Element[] | JSX.Element;\n menuItems: iMenuItem[];\n style?: React.CSSProperties;\n}): JSX.Element => {\n // Menu resources\n const divRef = useRef<HTMLDivElement | null>(null);\n const menuRef = useRef<HTMLDivElement | null>(null);\n const [menuXPos, setMenuXPos] = useState<number>(0);\n const [menuYPos, setMenuYPos] = useState<number>(0);\n const [menuVisible, setMenuVisible] = useState<boolean>(false);\n\n // Show menu when context is requested\n const showMenu = (e: MouseEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n setMenuVisible(true);\n setMenuXPos(e.pageX);\n setMenuYPos(e.pageY);\n };\n\n // Handle click off the menu\n const handleClick = useCallback((e: globalThis.MouseEvent) => {\n if (\n menuRef.current &&\n ((e.target instanceof Element && !menuRef.current?.contains(e.target)) ||\n !(e.target instanceof Element))\n ) {\n setMenuVisible(false);\n }\n }, []);\n\n // Update the document click handler\n useEffect(() => {\n if (menuVisible) document.addEventListener('mousedown', handleClick);\n else document.removeEventListener('mousedown', handleClick);\n return () => {\n document.removeEventListener('mousedown', handleClick);\n };\n }, [handleClick, menuVisible]);\n\n return (\n <>\n <div\n onContextMenu={showMenu}\n className='context-menu-handler'\n style={style}\n >\n {children}\n </div>\n {menuVisible &&\n createPortal(\n <div\n style={{ position: 'absolute', top: 0, left: 0 }}\n ref={divRef}\n >\n <ContextMenu\n visible={true}\n ref={menuRef}\n entries={menuItems}\n xPos={menuXPos}\n yPos={menuYPos}\n toClose={() => setMenuVisible(false)}\n />\n </div>,\n document.body,\n )}\n </>\n );\n};\n","import React from 'react';\nimport { iMenuItem } from './interface';\nimport { SubMenu } from './SubMenu';\n\nexport interface contextMenuProps {\n visible: boolean;\n entries: iMenuItem[];\n xPos: number;\n yPos: number;\n toClose: () => void;\n}\n\nexport const ContextMenu = React.forwardRef<HTMLDivElement, contextMenuProps>(\n ({ visible, entries, xPos, yPos, toClose }, ref): JSX.Element => {\n ContextMenu.displayName = 'ContextMenu';\n\n return (\n <div\n ref={ref}\n className={`context-menu${visible ? ' visible' : ''}`}\n style={{\n top: `${yPos}px`,\n left: `${xPos}px`,\n }}\n >\n {entries.map((e, i) => (\n <div\n key={i}\n className={`context-menu-item${e.disabled ? ' disabled' : ''}`}\n onClick={(ev) => {\n ev.preventDefault();\n ev.stopPropagation();\n e.action && !e.disabled && e.action();\n !e.disabled && toClose();\n }}\n >\n <span>{e.label}</span>\n {e.group && (\n <SubMenu\n toClose={toClose}\n entries={e.group}\n />\n )}\n </div>\n ))}\n </div>\n );\n },\n);\n","import { useState } from 'react';\nimport { ContextMenu } from './ContextMenu';\nimport { iMenuItem } from './interface';\n\nexport interface subMenuProps {\n entries: iMenuItem[];\n toClose: () => void;\n}\n\nexport const SubMenu = ({ entries, toClose }: subMenuProps): JSX.Element => {\n const [visible, setVisible] = useState<boolean>(false);\n\n return (\n <span\n className='caret-holder'\n onMouseEnter={() => {\n setVisible(true);\n }}\n onMouseLeave={() => {\n setVisible(false);\n }}\n >\n <svg\n xmlns='http://www.w3.org/2000/svg'\n width='16'\n height='16'\n fill='currentColor'\n viewBox='0 0 16 16'\n >\n <path d='m12.14 8.753-5.482 4.796c-.646.566-1.658.106-1.658-.753V3.204a1 1 0 0 1 1.659-.753l5.48 4.796a1 1 0 0 1 0 1.506z' />\n </svg>\n <div className='sub-menu'>\n <ContextMenu\n visible={visible}\n entries={entries}\n xPos={14}\n yPos={-21}\n toClose={toClose}\n />\n </div>\n </span>\n );\n};\n"],"names":[],"version":3,"file":"main.js.map"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asup/context-menu",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "REACT Typescript Context menu component",
|
|
5
5
|
"author": "Paul Thomas <@PaulDThomas>",
|
|
6
6
|
"private": false,
|
|
@@ -12,8 +12,7 @@
|
|
|
12
12
|
"keywords": [
|
|
13
13
|
"react",
|
|
14
14
|
"typescript",
|
|
15
|
-
"
|
|
16
|
-
"treeview"
|
|
15
|
+
"context menu"
|
|
17
16
|
],
|
|
18
17
|
"bugs": {
|
|
19
18
|
"url": "https://github.com/PaulDThomas/context-menu/issues"
|
|
@@ -41,6 +40,9 @@
|
|
|
41
40
|
"@types/node": "^18.11.9",
|
|
42
41
|
"@types/react": "^18.0.25",
|
|
43
42
|
"@types/react-dom": "^18.0.8",
|
|
43
|
+
"@typescript-eslint/eslint-plugin": "^5.49.0",
|
|
44
|
+
"@typescript-eslint/parser": "^5.49.0",
|
|
45
|
+
"eslint": "^8.32.0",
|
|
44
46
|
"eslint-config-prettier": "^8.5.0",
|
|
45
47
|
"eslint-plugin-prettier": "^4.2.1",
|
|
46
48
|
"eslint-plugin-react": "^7.31.10",
|