@asup/context-menu 1.0.2 → 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/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,
@@ -89,10 +90,10 @@ var $5150b66b01c99189$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, ($parcel$inter
89
90
  children: entries.map(function(e, i) {
90
91
  return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsxs)("div", {
91
92
  className: "context-menu-item".concat(e.disabled ? " disabled" : ""),
92
- onClick: function(ev) {
93
+ onClickCapture: function(ev) {
93
94
  ev.preventDefault();
94
95
  ev.stopPropagation();
95
- e.action && !e.disabled && e.action();
96
+ e.action && !e.disabled && e.action(target);
96
97
  !e.disabled && toClose();
97
98
  },
98
99
  children: [
@@ -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);
@@ -122,8 +124,11 @@ var $3c568ee547c732c3$export$ed4f9641643dc7e4 = function(param) {
122
124
  var _useState = (0, ($parcel$interopDefault($gTuX4$swchelperslib_sliced_to_arrayjs)))((0, $gTuX4$react.useState)(0), 2), menuXPos = _useState[0], setMenuXPos = _useState[1];
123
125
  var _useState1 = (0, ($parcel$interopDefault($gTuX4$swchelperslib_sliced_to_arrayjs)))((0, $gTuX4$react.useState)(0), 2), menuYPos = _useState1[0], setMenuYPos = _useState1[1];
124
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];
125
128
  // Show menu when context is requested
126
129
  var showMenu = function(e) {
130
+ var sel = window.getSelection();
131
+ setTarget(sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null);
127
132
  e.preventDefault();
128
133
  e.stopPropagation();
129
134
  setMenuVisible(true);
@@ -167,6 +172,7 @@ var $3c568ee547c732c3$export$ed4f9641643dc7e4 = function(param) {
167
172
  entries: menuItems,
168
173
  xPos: menuXPos,
169
174
  yPos: menuYPos,
175
+ target: target,
170
176
  toClose: function() {
171
177
  return setMenuVisible(false);
172
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 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"}
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,7 +1,7 @@
1
1
  export interface iMenuItem {
2
2
  label: string;
3
3
  disabled?: boolean;
4
- action?: () => void;
4
+ action?: (target?: Range | null) => void;
5
5
  group?: iMenuItem[];
6
6
  }
7
7
  export const ContextMenuHandler: ({ children, menuItems, style, }: {
@@ -1 +1 @@
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"}
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.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,
@@ -64,10 +65,10 @@ const $567ed433af94513f$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, $duWW8$react
64
65
  },
65
66
  children: entries.map((e, i)=>/*#__PURE__*/ (0, $duWW8$jsxs)("div", {
66
67
  className: `context-menu-item${e.disabled ? " disabled" : ""}`,
67
- onClick: (ev)=>{
68
+ onClickCapture: (ev)=>{
68
69
  ev.preventDefault();
69
70
  ev.stopPropagation();
70
- e.action && !e.disabled && e.action();
71
+ e.action && !e.disabled && e.action(target);
71
72
  !e.disabled && toClose();
72
73
  },
73
74
  children: [
@@ -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))
@@ -95,8 +97,11 @@ const $1e1c1e9e0b943830$export$ed4f9641643dc7e4 = ({ children: children , menuIt
95
97
  const [menuXPos, setMenuXPos] = (0, $duWW8$useState)(0);
96
98
  const [menuYPos, setMenuYPos] = (0, $duWW8$useState)(0);
97
99
  const [menuVisible, setMenuVisible] = (0, $duWW8$useState)(false);
100
+ const [target, setTarget] = (0, $duWW8$useState)(null);
98
101
  // Show menu when context is requested
99
102
  const showMenu = (e)=>{
103
+ const sel = window.getSelection();
104
+ setTarget(sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null);
100
105
  e.preventDefault();
101
106
  e.stopPropagation();
102
107
  setMenuVisible(true);
@@ -140,6 +145,7 @@ const $1e1c1e9e0b943830$export$ed4f9641643dc7e4 = ({ children: children , menuIt
140
145
  entries: menuItems,
141
146
  xPos: menuXPos,
142
147
  yPos: menuYPos,
148
+ target: target,
143
149
  toClose: ()=>setMenuVisible(false)
144
150
  })
145
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 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"}
1
+ {"mappings":";;;;;;;;;;;AEAA;;;ACAA;;ACAA;;;AAUO,MAAM,4CAAU,CAAC,WAAE,QAAO,UAAE,OAAM,WAAE,QAAO,EAAgB,GAAkB;IAClF,MAAM,CAAC,SAAS,WAAW,GAAG,CAAA,GAAA,eAAO,EAAW,KAAK;IAErD,qBACE,iBAAC;QACC,WAAU;QACV,cAAc,IAAM;YAClB,WAAW,IAAI;QACjB;QACA,cAAc,IAAM;YAClB,WAAW,KAAK;QAClB;;0BAEA,gBAAC;gBACC,OAAM;gBACN,OAAM;gBACN,QAAO;gBACP,MAAK;gBACL,SAAQ;0BAER,cAAA,gBAAC;oBAAK,GAAE;;;0BAEV,gBAAC;gBAAI,WAAU;0BACb,cAAA,gBAAC,CAAA,GAAA,yCAAW,AAAD;oBACT,SAAS;oBACT,SAAS;oBACT,QAAQ;oBACR,MAAM;oBACN,MAAM;oBACN,SAAS;;;;;AAKnB;;;AD/BO,MAAM,0DAAc,CAAA,GAAA,YAAI,EAAE,UAAU,CACzC,CAAC,WAAE,QAAO,WAAE,QAAO,UAAE,OAAM,QAAE,KAAI,QAAE,KAAI,WAAE,QAAO,EAAE,EAAE,MAAqB;IACvE,0CAAY,WAAW,GAAG;IAE1B,qBACE,gBAAC;QACC,KAAK;QACL,WAAW,CAAC,YAAY,EAAE,UAAU,aAAa,EAAE,CAAC,CAAC;QACrD,OAAO;YACL,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC;YAChB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;QACnB;kBAEC,QAAQ,GAAG,CAAC,CAAC,GAAG,kBACf,iBAAC;gBAEC,WAAW,CAAC,iBAAiB,EAAE,EAAE,QAAQ,GAAG,cAAc,EAAE,CAAC,CAAC;gBAC9D,gBAAgB,CAAC,KAAO;oBACtB,GAAG,cAAc;oBACjB,GAAG,eAAe;oBAClB,EAAE,MAAM,IAAI,CAAC,EAAE,QAAQ,IAAI,EAAE,MAAM,CAAC;oBACpC,CAAC,EAAE,QAAQ,IAAI;gBACjB;;kCAEA,gBAAC;kCAAM,EAAE,KAAK;;oBACb,EAAE,KAAK,kBACN,gBAAC,CAAA,GAAA,yCAAO,AAAD;wBACL,SAAS;wBACT,SAAS,EAAE,KAAK;wBAChB,QAAQ;;;eAdP;;AAqBf;;;;AD3CK,MAAM,4CAAqB,CAAC,YACjC,SAAQ,aACR,UAAS,SACT,QAAQ;IACN,QAAQ;IACR,OAAO;AACT,IAKD,GAAkB;IACjB,iBAAiB;IACjB,MAAM,SAAS,CAAA,GAAA,aAAK,EAAyB,IAAI;IACjD,MAAM,UAAU,CAAA,GAAA,aAAK,EAAyB,IAAI;IAClD,MAAM,CAAC,UAAU,YAAY,GAAG,CAAA,GAAA,eAAQ,AAAD,EAAU;IACjD,MAAM,CAAC,UAAU,YAAY,GAAG,CAAA,GAAA,eAAQ,AAAD,EAAU;IACjD,MAAM,CAAC,aAAa,eAAe,GAAG,CAAA,GAAA,eAAO,EAAW,KAAK;IAC7D,MAAM,CAAC,QAAQ,UAAU,GAAG,CAAA,GAAA,eAAO,EAAgB,IAAI;IAEvD,sCAAsC;IACtC,MAAM,WAAW,CAAC,IAAkC;QAClD,MAAM,MAAM,OAAO,YAAY;QAC/B,UAAU,OAAO,IAAI,UAAU,GAAG,IAAI,IAAI,UAAU,CAAC,KAAK,IAAI;QAC9D,EAAE,cAAc;QAChB,EAAE,eAAe;QACjB,eAAe,IAAI;QACnB,YAAY,EAAE,KAAK;QACnB,YAAY,EAAE,KAAK;IACrB;IAEA,4BAA4B;IAC5B,MAAM,cAAc,CAAA,GAAA,kBAAW,AAAD,EAAE,CAAC,IAA6B;YAGxB;QAFpC,IACE,QAAQ,OAAO,IACd,CAAA,AAAC,EAAE,MAAM,YAAY,WAAW,EAAC,CAAA,mBAAA,QAAQ,OAAO,cAAf,8BAAA,KAAA,IAAA,iBAAiB,SAAS,EAAE,MAAM,MAClE,CAAE,CAAA,EAAE,MAAM,YAAY,OAAM,CAAC,GAE/B,eAAe,KAAK;IAExB,GAAG,EAAE;IAEL,oCAAoC;IACpC,CAAA,GAAA,gBAAS,AAAD,EAAE,IAAM;QACd,IAAI,aAAa,SAAS,gBAAgB,CAAC,aAAa;aACnD,SAAS,mBAAmB,CAAC,aAAa;QAC/C,OAAO,IAAM;YACX,SAAS,mBAAmB,CAAC,aAAa;QAC5C;IACF,GAAG;QAAC;QAAa;KAAY;IAE7B,qBACE;;0BACE,gBAAC;gBACC,eAAe;gBACf,WAAU;gBACV,OAAO;0BAEN;;YAEF,6BACC,CAAA,GAAA,mBAAY,AAAD,gBACT,gBAAC;gBACC,OAAO;oBAAE,UAAU;oBAAY,KAAK;oBAAG,MAAM;gBAAE;gBAC/C,KAAK;0BAEL,cAAA,gBAAC,CAAA,GAAA,yCAAW,AAAD;oBACT,SAAS,IAAI;oBACb,KAAK;oBACL,SAAS;oBACT,MAAM;oBACN,MAAM;oBACN,QAAQ;oBACR,SAAS,IAAM,eAAe,KAAK;;gBAGvC,SAAS,IAAI;;;AAIvB;;ADtFA;;ADAA","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.2",
3
+ "version": "1.0.3",
4
4
  "description": "REACT Typescript Context menu component",
5
5
  "author": "Paul Thomas <@PaulDThomas>",
6
6
  "private": false,