@asup/context-menu 1.0.1 → 1.0.3

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 CHANGED
@@ -36,6 +36,7 @@ import { ContextMenuProvider, iMenuItem } from '@asup/context-menu';
36
36
  ...
37
37
  ]
38
38
  },
39
+ { label: 'Item 3', action: item3Function, disabeld: true },
39
40
  ...
40
41
  ]}
41
42
  >
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;
@@ -34,6 +25,11 @@
34
25
  position: relative;
35
26
  }
36
27
 
28
+ .context-menu-item.disabled {
29
+ cursor: not-allowed;
30
+ background-color: rgba(0, 0, 0, .2);
31
+ }
32
+
37
33
  .context-menu-item:first-child {
38
34
  padding-top: 4px;
39
35
  }
@@ -42,16 +38,18 @@
42
38
  padding-bottom: 4px;
43
39
  }
44
40
 
45
- .context-menu-item:hover {
41
+ .context-menu-item:not(.disabled):hover {
46
42
  background-color: #fbe9e6;
47
43
  }
48
44
 
49
45
  .context-menu-item:hover:first-child {
50
- border-radius: 6px 6px 0 0;
46
+ border-top-left-radius: 6px;
47
+ border-top-right-radius: 6px;
51
48
  }
52
49
 
53
50
  .context-menu-item:hover:last-child {
54
- border-radius: 0 0 6px 6px;
51
+ border-bottom-right-radius: 6px;
52
+ border-bottom-left-radius: 6px;
55
53
  }
56
54
 
57
55
  .context-menu-item .caret-holder {
@@ -1 +1 @@
1
- {"mappings":"AAAA;;;;;;;;;AAKA;;;;;;;;;;AAWA;;;;AAIA;;;;;;;;;;;;;AAaA;;;;AAIA;;;;AAIA;;;;AAIA;;;;AAIA;;;;AAIA;;;;AAIA","sources":["src/components/ContextMenu.scss"],"sourcesContent":[".context-menu-handler {\n height: fit-content;\n width: fit-content;\n}\n\n.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:first-child {\n padding-top: 4px;\n}\n\n.context-menu-item:last-child {\n padding-bottom: 4px;\n}\n\n.context-menu-item:hover {\n background-color: rgb(251, 233, 230);\n}\n\n.context-menu-item:hover:first-child {\n border-radius: 6px 6px 0 0;\n}\n\n.context-menu-item:hover:last-child {\n border-radius: 0 0 6px 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"}
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
@@ -40,7 +40,7 @@ $parcel$export($a68bd8a6c0fd98c2$exports, "ContextMenuHandler", function () { re
40
40
 
41
41
 
42
42
  var $2275c4645c0c5e94$export$a9c522a6d7beb830 = function(param) {
43
- var entries = param.entries, toClose = param.toClose;
43
+ var entries = param.entries, target = param.target, toClose = param.toClose;
44
44
  var _useState = (0, ($parcel$interopDefault($gTuX4$swchelperslib_sliced_to_arrayjs)))((0, $gTuX4$react.useState)(false), 2), visible = _useState[0], setVisible = _useState[1];
45
45
  return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsxs)("span", {
46
46
  className: "caret-holder",
@@ -66,6 +66,7 @@ var $2275c4645c0c5e94$export$a9c522a6d7beb830 = function(param) {
66
66
  children: /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $5150b66b01c99189$export$8dc6765e8be191c7), {
67
67
  visible: visible,
68
68
  entries: entries,
69
+ target: target,
69
70
  xPos: 14,
70
71
  yPos: -21,
71
72
  toClose: toClose
@@ -77,7 +78,7 @@ var $2275c4645c0c5e94$export$a9c522a6d7beb830 = function(param) {
77
78
 
78
79
 
79
80
  var $5150b66b01c99189$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, ($parcel$interopDefault($gTuX4$react))).forwardRef(function(param, ref) {
80
- var visible = param.visible, entries = param.entries, xPos = param.xPos, yPos = param.yPos, toClose = param.toClose;
81
+ var visible = param.visible, entries = param.entries, target = param.target, xPos = param.xPos, yPos = param.yPos, toClose = param.toClose;
81
82
  $5150b66b01c99189$export$8dc6765e8be191c7.displayName = "ContextMenu";
82
83
  return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", {
83
84
  ref: ref,
@@ -88,12 +89,12 @@ var $5150b66b01c99189$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, ($parcel$inter
88
89
  },
89
90
  children: entries.map(function(e, i) {
90
91
  return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsxs)("div", {
91
- className: "context-menu-item",
92
- onClick: function(ev) {
92
+ className: "context-menu-item".concat(e.disabled ? " disabled" : ""),
93
+ onClickCapture: function(ev) {
93
94
  ev.preventDefault();
94
95
  ev.stopPropagation();
95
- e.action && e.action();
96
- toClose();
96
+ e.action && !e.disabled && e.action(target);
97
+ !e.disabled && toClose();
97
98
  },
98
99
  children: [
99
100
  /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("span", {
@@ -101,7 +102,8 @@ var $5150b66b01c99189$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, ($parcel$inter
101
102
  }),
102
103
  e.group && /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $2275c4645c0c5e94$export$a9c522a6d7beb830), {
103
104
  toClose: toClose,
104
- entries: e.group
105
+ entries: e.group,
106
+ target: target
105
107
  })
106
108
  ]
107
109
  }, i);
@@ -112,15 +114,21 @@ var $5150b66b01c99189$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, ($parcel$inter
112
114
 
113
115
 
114
116
  var $3c568ee547c732c3$export$ed4f9641643dc7e4 = function(param) {
115
- var children = param.children, menuItems = param.menuItems;
117
+ var children = param.children, menuItems = param.menuItems, _param_style = param.style, style = _param_style === void 0 ? {
118
+ height: "fit-content",
119
+ width: "fit-content"
120
+ } : _param_style;
116
121
  // Menu resources
117
122
  var divRef = (0, $gTuX4$react.useRef)(null);
118
123
  var menuRef = (0, $gTuX4$react.useRef)(null);
119
124
  var _useState = (0, ($parcel$interopDefault($gTuX4$swchelperslib_sliced_to_arrayjs)))((0, $gTuX4$react.useState)(0), 2), menuXPos = _useState[0], setMenuXPos = _useState[1];
120
125
  var _useState1 = (0, ($parcel$interopDefault($gTuX4$swchelperslib_sliced_to_arrayjs)))((0, $gTuX4$react.useState)(0), 2), menuYPos = _useState1[0], setMenuYPos = _useState1[1];
121
126
  var _useState2 = (0, ($parcel$interopDefault($gTuX4$swchelperslib_sliced_to_arrayjs)))((0, $gTuX4$react.useState)(false), 2), menuVisible = _useState2[0], setMenuVisible = _useState2[1];
127
+ var _useState3 = (0, ($parcel$interopDefault($gTuX4$swchelperslib_sliced_to_arrayjs)))((0, $gTuX4$react.useState)(null), 2), target = _useState3[0], setTarget = _useState3[1];
122
128
  // Show menu when context is requested
123
129
  var showMenu = function(e) {
130
+ var sel = window.getSelection();
131
+ setTarget(sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null);
124
132
  e.preventDefault();
125
133
  e.stopPropagation();
126
134
  setMenuVisible(true);
@@ -148,6 +156,7 @@ var $3c568ee547c732c3$export$ed4f9641643dc7e4 = function(param) {
148
156
  /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", {
149
157
  onContextMenu: showMenu,
150
158
  className: "context-menu-handler",
159
+ style: style,
151
160
  children: children
152
161
  }),
153
162
  menuVisible && /*#__PURE__*/ (0, $gTuX4$reactdom.createPortal)(/*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", {
@@ -163,6 +172,7 @@ var $3c568ee547c732c3$export$ed4f9641643dc7e4 = function(param) {
163
172
  entries: menuItems,
164
173
  xPos: menuXPos,
165
174
  yPos: menuYPos,
175
+ target: target,
166
176
  toClose: function() {
167
177
  return setMenuVisible(false);
168
178
  }
@@ -1 +1 @@
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}: {\n children: JSX.Element[] | JSX.Element;\n menuItems: iMenuItem[];\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 >\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'\n onClick={(ev) => {\n ev.preventDefault();\n ev.stopPropagation();\n e.action && e.action();\n 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"}
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 const [target, setTarget] = useState<Range | null>(null);\n\n // Show menu when context is requested\n const showMenu = (e: MouseEvent<HTMLDivElement>) => {\n const sel = window.getSelection();\n setTarget(sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null);\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 target={target}\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 target: Range | null;\n xPos: number;\n yPos: number;\n toClose: () => void;\n}\n\nexport const ContextMenu = React.forwardRef<HTMLDivElement, contextMenuProps>(\n ({ visible, entries, target, 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 onClickCapture={(ev) => {\n ev.preventDefault();\n ev.stopPropagation();\n e.action && !e.disabled && e.action(target);\n !e.disabled && toClose();\n }}\n >\n <span>{e.label}</span>\n {e.group && (\n <SubMenu\n toClose={toClose}\n entries={e.group}\n target={target}\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 target: Range | null;\n toClose: () => void;\n}\n\nexport const SubMenu = ({ entries, target, 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 target={target}\n xPos={14}\n yPos={-21}\n toClose={toClose}\n />\n </div>\n </span>\n );\n};\n"],"names":[],"version":3,"file":"main.js.map"}
@@ -1,11 +1,13 @@
1
1
  export interface iMenuItem {
2
2
  label: string;
3
- action?: () => void;
3
+ disabled?: boolean;
4
+ action?: (target?: Range | null) => void;
4
5
  group?: iMenuItem[];
5
6
  }
6
- export const ContextMenuHandler: ({ children, menuItems, }: {
7
+ export const ContextMenuHandler: ({ children, menuItems, style, }: {
7
8
  children: JSX.Element[] | JSX.Element;
8
9
  menuItems: iMenuItem[];
10
+ style?: import("react").CSSProperties | undefined;
9
11
  }) => JSX.Element;
10
12
 
11
13
  //# sourceMappingURL=context-menu.d.ts.map
@@ -1 +1 @@
1
- {"mappings":"AAAA;IACE,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;CACrB;AGED,OAAO,MAAM;cAID,WAAW,EAAE,GAAG,WAAW;eAC1B,SAAS,EAAE;MACpB,WAgEH,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"}
1
+ {"mappings":"AAAA;IACE,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC;IACzC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;CACrB;AGCD,OAAO,MAAM;cAQD,WAAW,EAAE,GAAG,WAAW;eAC1B,SAAS,EAAE;;MAEpB,WAqEH,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;
@@ -34,6 +25,11 @@
34
25
  position: relative;
35
26
  }
36
27
 
28
+ .context-menu-item.disabled {
29
+ cursor: not-allowed;
30
+ background-color: rgba(0, 0, 0, .2);
31
+ }
32
+
37
33
  .context-menu-item:first-child {
38
34
  padding-top: 4px;
39
35
  }
@@ -42,16 +38,18 @@
42
38
  padding-bottom: 4px;
43
39
  }
44
40
 
45
- .context-menu-item:hover {
41
+ .context-menu-item:not(.disabled):hover {
46
42
  background-color: #fbe9e6;
47
43
  }
48
44
 
49
45
  .context-menu-item:hover:first-child {
50
- border-radius: 6px 6px 0 0;
46
+ border-top-left-radius: 6px;
47
+ border-top-right-radius: 6px;
51
48
  }
52
49
 
53
50
  .context-menu-item:hover:last-child {
54
- border-radius: 0 0 6px 6px;
51
+ border-bottom-right-radius: 6px;
52
+ border-bottom-left-radius: 6px;
55
53
  }
56
54
 
57
55
  .context-menu-item .caret-holder {
package/dist/main.css.map CHANGED
@@ -1 +1 @@
1
- {"mappings":"AAAA;;;;;;;;;AAKA;;;;;;;;;;AAWA;;;;AAIA;;;;;;;;;;;;;AAaA;;;;AAIA;;;;AAIA;;;;AAIA;;;;AAIA;;;;AAIA;;;;AAIA","sources":["src/components/ContextMenu.scss"],"sourcesContent":[".context-menu-handler {\n height: fit-content;\n width: fit-content;\n}\n\n.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:first-child {\n padding-top: 4px;\n}\n\n.context-menu-item:last-child {\n padding-bottom: 4px;\n}\n\n.context-menu-item:hover {\n background-color: rgb(251, 233, 230);\n}\n\n.context-menu-item:hover:first-child {\n border-radius: 6px 6px 0 0;\n}\n\n.context-menu-item:hover:last-child {\n border-radius: 0 0 6px 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"}
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
@@ -17,7 +17,7 @@ $parcel$export($b65191f6d0a0a991$exports, "ContextMenuHandler", function () { re
17
17
 
18
18
 
19
19
 
20
- const $885a1576aecbe1c6$export$a9c522a6d7beb830 = ({ entries: entries , toClose: toClose })=>{
20
+ const $885a1576aecbe1c6$export$a9c522a6d7beb830 = ({ entries: entries , target: target , toClose: toClose })=>{
21
21
  const [visible, setVisible] = (0, $duWW8$useState)(false);
22
22
  return /*#__PURE__*/ (0, $duWW8$jsxs)("span", {
23
23
  className: "caret-holder",
@@ -43,6 +43,7 @@ const $885a1576aecbe1c6$export$a9c522a6d7beb830 = ({ entries: entries , toClose:
43
43
  children: /*#__PURE__*/ (0, $duWW8$jsx)((0, $567ed433af94513f$export$8dc6765e8be191c7), {
44
44
  visible: visible,
45
45
  entries: entries,
46
+ target: target,
46
47
  xPos: 14,
47
48
  yPos: -21,
48
49
  toClose: toClose
@@ -53,7 +54,7 @@ const $885a1576aecbe1c6$export$a9c522a6d7beb830 = ({ entries: entries , toClose:
53
54
  };
54
55
 
55
56
 
56
- const $567ed433af94513f$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, $duWW8$react).forwardRef(({ visible: visible , entries: entries , xPos: xPos , yPos: yPos , toClose: toClose }, ref)=>{
57
+ const $567ed433af94513f$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, $duWW8$react).forwardRef(({ visible: visible , entries: entries , target: target , xPos: xPos , yPos: yPos , toClose: toClose }, ref)=>{
57
58
  $567ed433af94513f$export$8dc6765e8be191c7.displayName = "ContextMenu";
58
59
  return /*#__PURE__*/ (0, $duWW8$jsx)("div", {
59
60
  ref: ref,
@@ -63,12 +64,12 @@ const $567ed433af94513f$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, $duWW8$react
63
64
  left: `${xPos}px`
64
65
  },
65
66
  children: entries.map((e, i)=>/*#__PURE__*/ (0, $duWW8$jsxs)("div", {
66
- className: "context-menu-item",
67
- onClick: (ev)=>{
67
+ className: `context-menu-item${e.disabled ? " disabled" : ""}`,
68
+ onClickCapture: (ev)=>{
68
69
  ev.preventDefault();
69
70
  ev.stopPropagation();
70
- e.action && e.action();
71
- toClose();
71
+ e.action && !e.disabled && e.action(target);
72
+ !e.disabled && toClose();
72
73
  },
73
74
  children: [
74
75
  /*#__PURE__*/ (0, $duWW8$jsx)("span", {
@@ -76,7 +77,8 @@ const $567ed433af94513f$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, $duWW8$react
76
77
  }),
77
78
  e.group && /*#__PURE__*/ (0, $duWW8$jsx)((0, $885a1576aecbe1c6$export$a9c522a6d7beb830), {
78
79
  toClose: toClose,
79
- entries: e.group
80
+ entries: e.group,
81
+ target: target
80
82
  })
81
83
  ]
82
84
  }, i))
@@ -85,15 +87,21 @@ const $567ed433af94513f$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, $duWW8$react
85
87
 
86
88
 
87
89
 
88
- const $1e1c1e9e0b943830$export$ed4f9641643dc7e4 = ({ children: children , menuItems: menuItems })=>{
90
+ const $1e1c1e9e0b943830$export$ed4f9641643dc7e4 = ({ children: children , menuItems: menuItems , style: style = {
91
+ height: "fit-content",
92
+ width: "fit-content"
93
+ } })=>{
89
94
  // Menu resources
90
95
  const divRef = (0, $duWW8$useRef)(null);
91
96
  const menuRef = (0, $duWW8$useRef)(null);
92
97
  const [menuXPos, setMenuXPos] = (0, $duWW8$useState)(0);
93
98
  const [menuYPos, setMenuYPos] = (0, $duWW8$useState)(0);
94
99
  const [menuVisible, setMenuVisible] = (0, $duWW8$useState)(false);
100
+ const [target, setTarget] = (0, $duWW8$useState)(null);
95
101
  // Show menu when context is requested
96
102
  const showMenu = (e)=>{
103
+ const sel = window.getSelection();
104
+ setTarget(sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null);
97
105
  e.preventDefault();
98
106
  e.stopPropagation();
99
107
  setMenuVisible(true);
@@ -121,6 +129,7 @@ const $1e1c1e9e0b943830$export$ed4f9641643dc7e4 = ({ children: children , menuIt
121
129
  /*#__PURE__*/ (0, $duWW8$jsx)("div", {
122
130
  onContextMenu: showMenu,
123
131
  className: "context-menu-handler",
132
+ style: style,
124
133
  children: children
125
134
  }),
126
135
  menuVisible && /*#__PURE__*/ (0, $duWW8$createPortal)(/*#__PURE__*/ (0, $duWW8$jsx)("div", {
@@ -136,6 +145,7 @@ const $1e1c1e9e0b943830$export$ed4f9641643dc7e4 = ({ children: children , menuIt
136
145
  entries: menuItems,
137
146
  xPos: menuXPos,
138
147
  yPos: menuYPos,
148
+ target: target,
139
149
  toClose: ()=>setMenuVisible(false)
140
150
  })
141
151
  }), document.body)
package/dist/main.js.map CHANGED
@@ -1 +1 @@
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}: {\n children: JSX.Element[] | JSX.Element;\n menuItems: iMenuItem[];\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 >\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'\n onClick={(ev) => {\n ev.preventDefault();\n ev.stopPropagation();\n e.action && e.action();\n 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"}
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 const [target, setTarget] = useState<Range | null>(null);\n\n // Show menu when context is requested\n const showMenu = (e: MouseEvent<HTMLDivElement>) => {\n const sel = window.getSelection();\n setTarget(sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null);\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 target={target}\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 target: Range | null;\n xPos: number;\n yPos: number;\n toClose: () => void;\n}\n\nexport const ContextMenu = React.forwardRef<HTMLDivElement, contextMenuProps>(\n ({ visible, entries, target, 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 onClickCapture={(ev) => {\n ev.preventDefault();\n ev.stopPropagation();\n e.action && !e.disabled && e.action(target);\n !e.disabled && toClose();\n }}\n >\n <span>{e.label}</span>\n {e.group && (\n <SubMenu\n toClose={toClose}\n entries={e.group}\n target={target}\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 target: Range | null;\n toClose: () => void;\n}\n\nexport const SubMenu = ({ entries, target, 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 target={target}\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.1",
3
+ "version": "1.0.3",
4
4
  "description": "REACT Typescript Context menu component",
5
5
  "author": "Paul Thomas <@PaulDThomas>",
6
6
  "private": false,