@asup/context-menu 1.1.5 → 1.2.0

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.css CHANGED
@@ -65,6 +65,64 @@
65
65
  flex-grow: 1;
66
66
  }
67
67
 
68
+ .low-menu {
69
+ z-index: 2;
70
+ -webkit-font-smoothing: antialiased;
71
+ -moz-osx-font-smoothing: grayscale;
72
+ opacity: .5;
73
+ background-color: #111418;
74
+ border: 2px solid #111418;
75
+ border-top-right-radius: 4px;
76
+ border-bottom-right-radius: 4px;
77
+ border-bottom-left-radius: 4px;
78
+ flex-flow: wrap;
79
+ gap: 2px;
80
+ margin: 0;
81
+ font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
82
+ font-size: 9pt;
83
+ transition: opacity .3s linear;
84
+ display: flex;
85
+ position: absolute;
86
+ top: 0;
87
+ box-shadow: 2px 2px 2px rgba(64, 64, 64, .5);
88
+ }
89
+
90
+ .low-menu:hover {
91
+ opacity: 1;
92
+ }
93
+
94
+ .low-menu-item {
95
+ color: #111418;
96
+ cursor: pointer;
97
+ white-space: nowrap;
98
+ background-color: #fbfdf6;
99
+ border: 0;
100
+ border-radius: 4px;
101
+ flex-direction: row;
102
+ justify-content: space-between;
103
+ padding: 0 4px;
104
+ display: flex;
105
+ position: relative;
106
+ }
107
+
108
+ .low-menu-item.disabled {
109
+ cursor: not-allowed;
110
+ background-color: #c8c8c8;
111
+ }
112
+
113
+ .low-menu-item:not(.disabled):hover {
114
+ background-color: #fbe9e6;
115
+ }
116
+
117
+ .low-menu-item .caret-holder {
118
+ align-self: flex-end;
119
+ }
120
+
121
+ .low-menu-item .caret-holder .sub-menu {
122
+ z-index: 1;
123
+ position: relative;
124
+ }
125
+
68
126
  .contextwindow {
69
127
  z-index: 2001;
70
128
  resize: both;
@@ -1 +1 @@
1
- {"mappings":"AAAA;;;;;;;;;;AAWA;;;;AAIA;;;;;;;;;;;;;AAaA;;;;;AAKA;;;;AAIA;;;;AAIA;;;;AAIA;;;;;AAKA;;;;;AAKA;;;;AAIA;;;;;AAKA;;;;AChEA;;;;;;;;;;;;;;;;;AAiBA;;;;;;;;;;;;AAYA;;;;AAIA;;;;AAIA;;;;;;AAMA;;;;;;;AAOA;;;;;AAKA;;;;;AAKA;;;;;;AAMA","sources":["src/components/ContextMenu.css","src/components/ContextWindow.css"],"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 margin-top: 4px;\n}\n\n.context-menu-item:last-child {\n margin-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\n.context-menu-item-label {\n flex-grow: 1;\n}\n",".contextwindow {\n z-index: 2001;\n border: 1px black solid;\n margin: 0;\n padding: 4px;\n background-color: rgb(250, 250, 250);\n box-shadow: 6px 6px 6px rgb(64, 64, 64, 0.5);\n transition: opacity 0.25s linear;\n justify-content: flex-start;\n position: absolute;\n border-top-left-radius: 8px;\n border-top-right-radius: 8px;\n border-bottom-left-radius: 8px;\n resize: both;\n overflow: auto;\n}\n\n.contextwindow-title {\n text-transform: capitalize;\n border-bottom: 1px black dashed;\n padding-bottom: 4px;\n margin: 0 4px 3px 4px;\n font-size: 18px;\n font-weight: 600;\n flex-grow: 1;\n height: 24px;\n cursor: grab;\n}\n\n.contextwindow-title.moving {\n cursor: grabbing;\n}\n\n.contextwindow-title-text {\n display: inline-block;\n}\n\n.contextwindow-title-close {\n float: right;\n font-size: small;\n cursor: auto;\n}\n\n.contextwindow-body {\n overflow: auto;\n padding-bottom: 8px;\n margin-right: 4px;\n height: calc(100% - 40px);\n}\n\n.contextwindow-body::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n.contextwindow-body::-webkit-scrollbar-track {\n background: white;\n border-radius: 8px;\n}\n\n.contextwindow-body::-webkit-scrollbar-thumb {\n background: lightgrey;\n border: none;\n border-radius: 8px;\n}\n\n.contextwindow-body::-webkit-scrollbar-thumb:hover {\n background: grey;\n}\n"],"names":[],"version":3,"file":"main.css.map"}
1
+ {"mappings":"AAAA;;;;;;;;;;AAWA;;;;AAIA;;;;;;;;;;;;;AAaA;;;;;AAKA;;;;AAIA;;;;AAIA;;;;AAIA;;;;;AAKA;;;;;AAKA;;;;AAIA;;;;;AAKA;;;;AChEA;;;;;;;;;;;;;;;;;;;;;;AAyBA;;;;AAIA;;;;;;;;;;;;;;AAcA;;;;;AAKA;;;;AAIA;;;;AAIA;;;;;ACxDA;;;;;;;;;;;;;;;;;AAiBA;;;;;;;;;;;;AAYA;;;;AAIA;;;;AAIA;;;;;;AAMA;;;;;;;AAOA;;;;;AAKA;;;;;AAKA;;;;;;AAMA","sources":["src/components/ContextMenu.css","src/components/LowMenu.css","src/components/ContextWindow.css"],"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 margin-top: 4px;\n}\n\n.context-menu-item:last-child {\n margin-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\n.context-menu-item-label {\n flex-grow: 1;\n}\n",".low-menu {\n z-index: 2;\n position: absolute;\n top: 0;\n margin: 0px;\n border: 2px solid rgb(17, 20, 24);\n border-top-right-radius: 4px;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n background-color: rgb(17, 20, 24);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',\n 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n font-size: 9pt;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n box-shadow: 2px 2px 2px rgb(64, 64, 64, 0.5);\n opacity: 0.5;\n transition: opacity 0.3s linear;\n display: flex;\n flex-wrap: wrap;\n flex-direction: row;\n gap: 2px;\n row-gap: 2px;\n}\n\n.low-menu:hover {\n opacity: 1;\n}\n\n.low-menu-item {\n background-color: rgb(251, 253, 246);\n border: 0;\n border-radius: 4px;\n color: rgb(17, 20, 24);\n cursor: pointer;\n padding: 0 4px;\n position: relative;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n white-space: nowrap;\n}\n\n.low-menu-item.disabled {\n background-color: rgba(200, 200, 200);\n cursor: not-allowed;\n}\n\n.low-menu-item:not(.disabled):hover {\n background-color: rgb(251, 233, 230);\n}\n\n.low-menu-item .caret-holder {\n align-self: flex-end;\n}\n\n.low-menu-item .caret-holder .sub-menu {\n z-index: 1;\n position: relative;\n}\n",".contextwindow {\n z-index: 2001;\n border: 1px black solid;\n margin: 0;\n padding: 4px;\n background-color: rgb(250, 250, 250);\n box-shadow: 6px 6px 6px rgb(64, 64, 64, 0.5);\n transition: opacity 0.25s linear;\n justify-content: flex-start;\n position: absolute;\n border-top-left-radius: 8px;\n border-top-right-radius: 8px;\n border-bottom-left-radius: 8px;\n resize: both;\n overflow: auto;\n}\n\n.contextwindow-title {\n text-transform: capitalize;\n border-bottom: 1px black dashed;\n padding-bottom: 4px;\n margin: 0 4px 3px 4px;\n font-size: 18px;\n font-weight: 600;\n flex-grow: 1;\n height: 24px;\n cursor: grab;\n}\n\n.contextwindow-title.moving {\n cursor: grabbing;\n}\n\n.contextwindow-title-text {\n display: inline-block;\n}\n\n.contextwindow-title-close {\n float: right;\n font-size: small;\n cursor: auto;\n}\n\n.contextwindow-body {\n overflow: auto;\n padding-bottom: 8px;\n margin-right: 4px;\n height: calc(100% - 40px);\n}\n\n.contextwindow-body::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n.contextwindow-body::-webkit-scrollbar-track {\n background: white;\n border-radius: 8px;\n}\n\n.contextwindow-body::-webkit-scrollbar-thumb {\n background: lightgrey;\n border: none;\n border-radius: 8px;\n}\n\n.contextwindow-body::-webkit-scrollbar-thumb:hover {\n background: grey;\n}\n"],"names":[],"version":3,"file":"main.css.map"}
package/dist/cjs/main.js CHANGED
@@ -44,7 +44,7 @@ $parcel$export($a68bd8a6c0fd98c2$exports, "ContextWindowStack", function () { re
44
44
 
45
45
 
46
46
 
47
- var $2275c4645c0c5e94$export$a9c522a6d7beb830 = function(param) {
47
+ var $d35a356381c44181$export$7e4e6110f96afd7e = function(param) {
48
48
  var entries = param.entries, target = param.target, toClose = param.toClose;
49
49
  var _useState = (0, $gTuX4$swchelperscjs_sliced_to_arraycjs._)((0, $gTuX4$react.useState)(false), 2), visible = _useState[0], setVisible = _useState[1];
50
50
  return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsxs)("span", {
@@ -80,7 +80,7 @@ var $2275c4645c0c5e94$export$a9c522a6d7beb830 = function(param) {
80
80
  ]
81
81
  });
82
82
  };
83
- $2275c4645c0c5e94$export$a9c522a6d7beb830.displayName = "SubMenu";
83
+ $d35a356381c44181$export$7e4e6110f96afd7e.displayName = "ContextSubMenu";
84
84
 
85
85
 
86
86
  var $5150b66b01c99189$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, ($parcel$interopDefault($gTuX4$react))).forwardRef(function(param, ref) {
@@ -97,23 +97,25 @@ var $5150b66b01c99189$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, ($parcel$inter
97
97
  e.preventDefault();
98
98
  e.stopPropagation();
99
99
  },
100
- children: entries.map(function(e, i) {
100
+ children: entries.map(function(entry, i) {
101
101
  return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsxs)("div", {
102
- className: "context-menu-item".concat(e.disabled ? " disabled" : ""),
103
- onClick: function(ev) {
102
+ className: "context-menu-item".concat(entry.disabled ? " disabled" : ""),
103
+ "aria-label": entry.label,
104
+ "aria-disabled": entry.disabled,
105
+ onMouseDownCapture: function(ev) {
104
106
  ev.preventDefault();
105
107
  ev.stopPropagation();
106
- e.action && !e.disabled && e.action(target);
107
- !e.disabled && toClose();
108
+ entry.action && !entry.disabled && entry.action(target);
109
+ !entry.disabled && toClose();
108
110
  },
109
111
  children: [
110
112
  /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("span", {
111
113
  className: "context-menu-item-label",
112
- children: e.label
114
+ children: entry.label
113
115
  }),
114
- e.group && /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $2275c4645c0c5e94$export$a9c522a6d7beb830), {
116
+ entry.group && /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $d35a356381c44181$export$7e4e6110f96afd7e), {
115
117
  toClose: toClose,
116
- entries: e.group,
118
+ entries: entry.group,
117
119
  target: target
118
120
  })
119
121
  ]
@@ -125,8 +127,100 @@ $5150b66b01c99189$export$8dc6765e8be191c7.displayName = "ContextMenu";
125
127
 
126
128
 
127
129
 
130
+
131
+
132
+
133
+
134
+
135
+
136
+
137
+ var $d30299730ea8ec1e$export$251b9f54013cdfac = function(param) {
138
+ var entry = param.entry, target = param.target;
139
+ var _useState = (0, $gTuX4$swchelperscjs_sliced_to_arraycjs._)((0, $gTuX4$react.useState)(false), 2), visible = _useState[0], setVisible = _useState[1];
140
+ if (!entry.group || entry.group.length === 0) return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $gTuX4$reactjsxruntime.Fragment), {});
141
+ return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsxs)("span", {
142
+ "aria-label": "Sub menu for ".concat(entry.label),
143
+ className: "caret-holder",
144
+ onMouseEnter: function() {
145
+ setVisible(true);
146
+ },
147
+ onMouseLeave: function() {
148
+ setVisible(false);
149
+ },
150
+ children: [
151
+ /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("svg", {
152
+ xmlns: "http://www.w3.org/2000/svg",
153
+ width: "16",
154
+ height: "16",
155
+ fill: "currentColor",
156
+ viewBox: "0 0 16 16",
157
+ children: /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("path", {
158
+ 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"
159
+ })
160
+ }),
161
+ /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", {
162
+ className: "sub-menu",
163
+ children: /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $5150b66b01c99189$export$8dc6765e8be191c7), {
164
+ visible: visible,
165
+ entries: entry.group,
166
+ target: target,
167
+ xPos: 14,
168
+ yPos: entry.group.length * -21 - 8,
169
+ toClose: function() {
170
+ return setVisible(false);
171
+ }
172
+ })
173
+ })
174
+ ]
175
+ });
176
+ };
177
+ $d30299730ea8ec1e$export$251b9f54013cdfac.displayName = "LowSubMenu";
178
+
179
+
180
+ var $b34598671fff4a77$export$aafc28aea571c4bc = function(param) {
181
+ var entry = param.entry, target = param.target;
182
+ return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsxs)("div", {
183
+ className: "low-menu-item".concat(entry.disabled ? " disabled" : ""),
184
+ "aria-label": entry.label,
185
+ "aria-disabled": entry.disabled,
186
+ onClick: function(event) {
187
+ event.preventDefault();
188
+ event.stopPropagation();
189
+ entry.action && !entry.disabled && entry.action(target);
190
+ },
191
+ children: [
192
+ /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("span", {
193
+ className: "low-menu-item-label",
194
+ children: entry.label
195
+ }),
196
+ entry.group && /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $d30299730ea8ec1e$export$251b9f54013cdfac), {
197
+ entry: entry,
198
+ target: target
199
+ })
200
+ ]
201
+ });
202
+ };
203
+ $b34598671fff4a77$export$aafc28aea571c4bc.displayName = "LowMenuButton";
204
+
205
+
206
+ var $10d1ee4e7fc9bbbd$export$49e8edc8ebca5f25 = function(param) {
207
+ var entries = param.entries, target = param.target;
208
+ return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", {
209
+ className: "low-menu",
210
+ "aria-label": "Low context menu",
211
+ children: entries.map(function(e, i) {
212
+ return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $b34598671fff4a77$export$aafc28aea571c4bc), {
213
+ entry: e,
214
+ target: target
215
+ }, i);
216
+ })
217
+ });
218
+ };
219
+ $10d1ee4e7fc9bbbd$export$49e8edc8ebca5f25.displayName = "LowMenu";
220
+
221
+
128
222
  var $3c568ee547c732c3$export$ed4f9641643dc7e4 = function(param) {
129
- var children = param.children, menuItems = param.menuItems, _param_style = param.style, style = _param_style === void 0 ? {
223
+ var children = param.children, menuItems = param.menuItems, _param_showLowMenu = param.showLowMenu, showLowMenu = _param_showLowMenu === void 0 ? false : _param_showLowMenu, _param_style = param.style, style = _param_style === void 0 ? {
130
224
  height: "fit-content",
131
225
  width: "fit-content"
132
226
  } : _param_style;
@@ -137,6 +231,7 @@ var $3c568ee547c732c3$export$ed4f9641643dc7e4 = function(param) {
137
231
  var _useState1 = (0, $gTuX4$swchelperscjs_sliced_to_arraycjs._)((0, $gTuX4$react.useState)(0), 2), menuYPos = _useState1[0], setMenuYPos = _useState1[1];
138
232
  var _useState2 = (0, $gTuX4$swchelperscjs_sliced_to_arraycjs._)((0, $gTuX4$react.useState)(false), 2), menuVisible = _useState2[0], setMenuVisible = _useState2[1];
139
233
  var _useState3 = (0, $gTuX4$swchelperscjs_sliced_to_arraycjs._)((0, $gTuX4$react.useState)(null), 2), target = _useState3[0], setTarget = _useState3[1];
234
+ var _useState4 = (0, $gTuX4$swchelperscjs_sliced_to_arraycjs._)((0, $gTuX4$react.useState)(null), 2), lowTarget = _useState4[0], setLowTarget = _useState4[1];
140
235
  // Show menu when context is requested
141
236
  var showMenu = function(e) {
142
237
  var sel = window.getSelection();
@@ -166,12 +261,12 @@ var $3c568ee547c732c3$export$ed4f9641643dc7e4 = function(param) {
166
261
  return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsxs)((0, $gTuX4$reactjsxruntime.Fragment), {
167
262
  children: [
168
263
  /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", {
169
- onContextMenu: showMenu,
264
+ onContextMenu: showLowMenu ? undefined : showMenu,
170
265
  className: "context-menu-handler",
171
266
  style: style,
172
267
  children: children
173
268
  }),
174
- menuVisible && /*#__PURE__*/ (0, $gTuX4$reactdom.createPortal)(/*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", {
269
+ menuVisible && !showLowMenu && /*#__PURE__*/ (0, $gTuX4$reactdom.createPortal)(/*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", {
175
270
  style: {
176
271
  position: "absolute",
177
272
  top: 0,
@@ -189,7 +284,25 @@ var $3c568ee547c732c3$export$ed4f9641643dc7e4 = function(param) {
189
284
  return setMenuVisible(false);
190
285
  }
191
286
  })
192
- }), document.body)
287
+ }), document.body),
288
+ showLowMenu && /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", {
289
+ style: {
290
+ position: "relative"
291
+ },
292
+ onMouseEnter: function() {
293
+ var sel = window.getSelection();
294
+ var lowSel = sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
295
+ setLowTarget(lowSel);
296
+ },
297
+ onMouseLeave: function() {
298
+ setLowTarget(null);
299
+ },
300
+ children: /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $10d1ee4e7fc9bbbd$export$49e8edc8ebca5f25), {
301
+ entries: menuItems,
302
+ target: lowTarget
303
+ })
304
+ }),
305
+ " "
193
306
  ]
194
307
  });
195
308
  };
@@ -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","src/components/ContextWindow.tsx","src/components/ContextWindowStack.tsx","src/functions/chkPosition.ts"],"sourcesContent":["export * from './components';\n","import { ContextMenuHandler } from './ContextMenuHandler';\nimport { ContextWindow } from './ContextWindow';\nimport { ContextWindowStack } from './ContextWindowStack';\nimport { iMenuItem } from './interface';\n\nexport { ContextMenuHandler, ContextWindow, ContextWindowStack };\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.css';\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\nContextMenuHandler.displayName = 'ContextMenuHandler';\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 onContextMenuCapture={(e) => {\n e.preventDefault();\n e.stopPropagation();\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(target);\n !e.disabled && toClose();\n }}\n >\n <span className='context-menu-item-label'>{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\nContextMenu.displayName = 'ContextMenu';\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\nSubMenu.displayName = 'SubMenu';\n","import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport './ContextWindow.css';\nimport { ContextWindowStackContext } from './ContextWindowStack';\nimport { chkPosition } from '../functions/chkPosition';\n\ninterface ContextWindowProps {\n id: string;\n visible: boolean;\n onOpen?: () => void;\n onClose?: () => void;\n title: string;\n style?: React.CSSProperties;\n children: JSX.Element[] | JSX.Element | string;\n}\n\nexport const ContextWindow = ({\n id,\n visible,\n title,\n style,\n children,\n onOpen,\n onClose,\n}: ContextWindowProps): JSX.Element => {\n const windowStack = useContext(ContextWindowStackContext);\n const windowId = useRef<number | null>(null);\n const divRef = useRef<HTMLDivElement | null>(null);\n const windowRef = useRef<HTMLDivElement | null>(null);\n const [windowVisible, setWindowVisible] = useState<boolean>(false);\n const zIndex = useMemo(() => {\n return windowStack?.currentWindows.find((w) => w.windowId === windowId.current)?.zIndex ?? 1;\n }, [windowStack?.currentWindows]);\n\n // Position\n const windowPos = useRef<{ x: number; y: number }>({ x: 0, y: 0 });\n const [moving, setMoving] = useState<boolean>(false);\n\n const move = useCallback((x: number, y: number) => {\n if (windowRef.current && windowPos.current) {\n const window = windowRef.current;\n const pos = windowPos.current;\n pos.x += x;\n pos.y += y;\n window.style.transform = `translate(${pos.x}px, ${pos.y}px)`;\n }\n }, []);\n\n const checkPosition = useCallback(() => {\n const chkPos = chkPosition(windowRef);\n move(chkPos.translateX, chkPos.translateY);\n }, [move]);\n\n const mouseMove = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n move(e.movementX, e.movementY);\n },\n [move],\n );\n\n const mouseUp = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setMoving(false);\n checkPosition();\n document.removeEventListener('mousemove', mouseMove);\n document.removeEventListener('mouseup', mouseUp);\n window.removeEventListener('resize', checkPosition);\n if (e.target && (e.target instanceof HTMLElement || e.target instanceof SVGElement))\n e.target.style.userSelect = 'auto';\n },\n [checkPosition, mouseMove],\n );\n\n // Update visibility\n useEffect(() => {\n if (windowStack) {\n if (visible && !windowVisible) {\n if (!windowId.current) {\n const maxWindowId = Math.max(0, ...windowStack.currentWindows.map((w) => w.windowId));\n windowId.current = maxWindowId + 1;\n }\n windowStack.pushToTop(windowId.current);\n setWindowVisible(visible);\n onOpen && onOpen();\n // Get starting position\n if (divRef.current && windowRef.current) {\n const parentPos = divRef.current.getBoundingClientRect();\n const pos = windowRef.current.getBoundingClientRect();\n const windowHeight = pos.bottom - pos.top;\n windowRef.current.style.left = `${parentPos.left}px`;\n windowRef.current.style.top = `${\n parentPos.bottom + windowHeight < window.innerHeight\n ? parentPos.bottom\n : Math.max(0, parentPos.top - windowHeight)\n }px`;\n windowRef.current.style.transform = '';\n windowPos.current = { x: 0, y: 0 };\n }\n } else if (windowId.current && !visible && windowVisible) {\n setWindowVisible(false);\n }\n }\n }, [onOpen, visible, windowStack, windowVisible]);\n\n return (\n <div\n className='contextwindow-anchor'\n ref={divRef}\n >\n {windowStack &&\n createPortal(\n <div\n id={id}\n className='contextwindow'\n style={{\n ...style,\n opacity: moving ? 0.8 : windowVisible ? 1 : 0,\n visibility: windowVisible ? 'visible' : 'hidden',\n zIndex: zIndex ?? 1,\n minHeight: style?.minHeight ?? '150px',\n minWidth: style?.minWidth ?? '200px',\n maxHeight: style?.maxHeight ?? '1000px',\n maxWidth: style?.maxWidth ?? '1000px',\n }}\n onClickCapture={() => {\n windowId && windowId.current && windowStack.pushToTop(windowId.current);\n }}\n ref={windowRef}\n >\n <div\n className={`contextwindow-title ${moving ? 'moving' : ''}`}\n onMouseDown={(e: React.MouseEvent) => {\n if (e.target && (e.target instanceof HTMLElement || e.target instanceof SVGElement))\n e.target.style.userSelect = 'none';\n setMoving(true);\n windowId && windowId.current && windowStack.pushToTop(windowId.current);\n document.addEventListener('mouseup', mouseUp);\n document.addEventListener('mousemove', mouseMove);\n window.addEventListener('resize', () => checkPosition());\n }}\n >\n <span className='contextwindow-title-text'>{title}</span>\n <span className='contextwindow-title-close'>\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 onClick={onClose}\n aria-label='Close window'\n >\n <path d='M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z' />\n </svg>\n </span>\n </div>\n <div className='contextwindow-body'>\n <div>{children}</div>\n </div>\n </div>,\n document.body,\n )}\n </div>\n );\n};\n\nContextWindow.displayName = 'ContextWindow';\n","import { createContext, useState } from 'react';\n\nexport interface ContextWindowZIndex {\n windowId: number;\n zIndex: number;\n}\n\nexport interface ContextWindowStackContextProps {\n currentWindows: ContextWindowZIndex[];\n pushToTop: (ret: number) => void;\n}\n\nexport const ContextWindowStackContext = createContext<ContextWindowStackContextProps | null>(null);\n\ninterface ContextWindowStackProps {\n id?: string;\n minZIndex?: number;\n children?: JSX.Element[] | JSX.Element;\n}\n\nconst pushToTop = (\n windowId: number,\n minZIndex: number,\n windowList: ContextWindowZIndex[],\n setWindowList: (ret: ContextWindowZIndex[]) => void,\n) => {\n const otherWindows = windowList\n .filter((w) => w.windowId !== windowId)\n .map((w, i) => ({ windowId: w.windowId, zIndex: minZIndex + i }));\n setWindowList([...otherWindows, { windowId, zIndex: minZIndex + otherWindows.length }]);\n};\n\nexport const ContextWindowStack = ({\n minZIndex = 1000,\n children,\n}: ContextWindowStackProps): JSX.Element => {\n const [currentWindows, setCurrentWindows] = useState<ContextWindowZIndex[]>([]);\n\n return (\n <ContextWindowStackContext.Provider\n value={{\n currentWindows: currentWindows.map((w) => ({\n windowId: w.windowId,\n zIndex: minZIndex + w.zIndex,\n })),\n pushToTop: (ret: number) => pushToTop(ret, minZIndex, currentWindows, setCurrentWindows),\n }}\n >\n {children}\n </ContextWindowStackContext.Provider>\n );\n};\n\nContextWindowStack.displayName = 'ContextWindowStack';\n","import { RefObject } from 'react';\n\n/**\n * Check that an existing div is inside the viewport\n * @param divRef Check div is inside view port, and return n\n * @returns \\{ translateX, translateY \\} Amount to move on X and Y axis\n */\nexport const chkPosition = (\n divRef: RefObject<HTMLDivElement>,\n): { translateX: number; translateY: number } => {\n if (!divRef.current) {\n return { translateX: 0, translateY: 0 };\n } else {\n const innerBounce = 16;\n const posn = divRef.current.getBoundingClientRect();\n let translateX = 0;\n if (posn.left < innerBounce) {\n translateX = -posn.left + innerBounce;\n } else if (posn.right > window.innerWidth) {\n translateX = Math.max(-posn.left + innerBounce, window.innerWidth - posn.right - innerBounce);\n }\n let translateY = 0;\n if (posn.top < innerBounce) {\n translateY = -posn.top + innerBounce;\n } else if (posn.bottom > window.innerHeight) {\n translateY = Math.max(\n -posn.top + innerBounce,\n window.innerHeight - posn.bottom - innerBounce,\n );\n }\n return { translateX, translateY };\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/ContextSubMenu.tsx","src/components/LowMenu.tsx","src/components/LowMenuButton.tsx","src/components/LowSubMenu.tsx","src/components/ContextWindow.tsx","src/components/ContextWindowStack.tsx","src/functions/chkPosition.ts"],"sourcesContent":["export * from './components';\n","import { ContextMenuHandler } from './ContextMenuHandler';\nimport { ContextWindow } from './ContextWindow';\nimport { ContextWindowStack } from './ContextWindowStack';\nimport { iMenuItem } from './interface';\n\nexport { ContextMenuHandler, ContextWindow, ContextWindowStack };\nexport type { iMenuItem };\n","import { MouseEvent, useCallback, useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { ContextMenu } from './ContextMenu';\nimport './ContextMenu.css';\nimport { LowMenu } from './LowMenu';\nimport { iMenuItem } from './interface';\n\ninterface contextMenuHandlerProps {\n children: JSX.Element[] | JSX.Element;\n menuItems: iMenuItem[];\n showLowMenu?: boolean;\n lowMenuTarget?: Range | null;\n style?: React.CSSProperties;\n}\n\nexport const ContextMenuHandler = ({\n children,\n menuItems,\n showLowMenu = false,\n style = {\n height: 'fit-content',\n width: 'fit-content',\n },\n}: contextMenuHandlerProps): 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 const [lowTarget, setLowTarget] = 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={showLowMenu ? undefined : showMenu}\n className='context-menu-handler'\n style={style}\n >\n {children}\n </div>\n {menuVisible &&\n !showLowMenu &&\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 {showLowMenu && (\n <div\n style={{ position: 'relative' }}\n onMouseEnter={() => {\n const sel = window.getSelection();\n const lowSel = sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null;\n setLowTarget(lowSel);\n }}\n onMouseLeave={() => {\n setLowTarget(null);\n }}\n >\n <LowMenu\n entries={menuItems}\n target={lowTarget}\n />\n </div>\n )}{' '}\n </>\n );\n};\n\nContextMenuHandler.displayName = 'ContextMenuHandler';\n","import React from 'react';\nimport { ContextSubMenu } from './ContextSubMenu';\nimport { iMenuItem } from './interface';\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 onContextMenuCapture={(e) => {\n e.preventDefault();\n e.stopPropagation();\n }}\n >\n {entries.map((entry, i) => (\n <div\n key={i}\n className={`context-menu-item${entry.disabled ? ' disabled' : ''}`}\n aria-label={entry.label}\n aria-disabled={entry.disabled}\n onMouseDownCapture={(ev) => {\n ev.preventDefault();\n ev.stopPropagation();\n entry.action && !entry.disabled && entry.action(target);\n !entry.disabled && toClose();\n }}\n >\n <span className='context-menu-item-label'>{entry.label}</span>\n {entry.group && (\n <ContextSubMenu\n toClose={toClose}\n entries={entry.group}\n target={target}\n />\n )}\n </div>\n ))}\n </div>\n );\n },\n);\n\nContextMenu.displayName = 'ContextMenu';\n","import { useState } from 'react';\nimport { ContextMenu } from './ContextMenu';\nimport { iMenuItem } from './interface';\n\nexport interface ContextSubMenuProps {\n entries: iMenuItem[];\n target: Range | null;\n toClose: () => void;\n lowMenu?: boolean;\n}\n\nexport const ContextSubMenu = ({ entries, target, toClose }: ContextSubMenuProps): 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\nContextSubMenu.displayName = 'ContextSubMenu';\n","import { iMenuItem } from './interface';\nimport './LowMenu.css';\nimport { LowMenuButton } from './LowMenuButton';\n\ninterface LowMenuProps {\n entries: iMenuItem[];\n target: Range | null;\n}\n\nexport const LowMenu = ({ entries, target }: LowMenuProps): JSX.Element => {\n return (\n <div\n className='low-menu'\n aria-label='Low context menu'\n >\n {entries.map((e, i) => (\n <LowMenuButton\n key={i}\n entry={e}\n target={target}\n />\n ))}\n </div>\n );\n};\n\nLowMenu.displayName = 'LowMenu';\n","import { LowSubMenu } from './LowSubMenu';\nimport { iMenuItem } from './interface';\n\ninterface LowMenuButtonProps {\n entry: iMenuItem;\n target: Range | null;\n}\nexport const LowMenuButton = ({ entry, target }: LowMenuButtonProps) => {\n return (\n <div\n className={`low-menu-item${entry.disabled ? ' disabled' : ''}`}\n aria-label={entry.label}\n aria-disabled={entry.disabled}\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n entry.action && !entry.disabled && entry.action(target);\n }}\n >\n <span className='low-menu-item-label'>{entry.label}</span>\n {entry.group && (\n <LowSubMenu\n entry={entry}\n target={target}\n />\n )}\n </div>\n );\n};\n\nLowMenuButton.displayName = 'LowMenuButton';\n","import { useState } from 'react';\nimport { ContextMenu } from './ContextMenu';\nimport { iMenuItem } from './interface';\n\nexport interface LowSubMenuProps {\n entry: iMenuItem;\n target: Range | null;\n lowMenu?: boolean;\n}\n\nexport const LowSubMenu = ({ entry, target }: LowSubMenuProps): JSX.Element => {\n const [visible, setVisible] = useState<boolean>(false);\n if (!entry.group || entry.group.length === 0) return <></>;\n return (\n <span\n aria-label={`Sub menu for ${entry.label}`}\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={entry.group}\n target={target}\n xPos={14}\n yPos={entry.group.length * -21 - 8}\n toClose={() => setVisible(false)}\n />\n </div>\n </span>\n );\n};\n\nLowSubMenu.displayName = 'LowSubMenu';\n","import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport './ContextWindow.css';\nimport { ContextWindowStackContext } from './ContextWindowStack';\nimport { chkPosition } from '../functions/chkPosition';\n\ninterface ContextWindowProps {\n id: string;\n visible: boolean;\n onOpen?: () => void;\n onClose?: () => void;\n title: string;\n style?: React.CSSProperties;\n children: JSX.Element[] | JSX.Element | string;\n}\n\nexport const ContextWindow = ({\n id,\n visible,\n title,\n style,\n children,\n onOpen,\n onClose,\n}: ContextWindowProps): JSX.Element => {\n const windowStack = useContext(ContextWindowStackContext);\n const windowId = useRef<number | null>(null);\n const divRef = useRef<HTMLDivElement | null>(null);\n const windowRef = useRef<HTMLDivElement | null>(null);\n const [windowVisible, setWindowVisible] = useState<boolean>(false);\n const zIndex = useMemo(() => {\n return windowStack?.currentWindows.find((w) => w.windowId === windowId.current)?.zIndex ?? 1;\n }, [windowStack?.currentWindows]);\n\n // Position\n const windowPos = useRef<{ x: number; y: number }>({ x: 0, y: 0 });\n const [moving, setMoving] = useState<boolean>(false);\n\n const move = useCallback((x: number, y: number) => {\n if (windowRef.current && windowPos.current) {\n const window = windowRef.current;\n const pos = windowPos.current;\n pos.x += x;\n pos.y += y;\n window.style.transform = `translate(${pos.x}px, ${pos.y}px)`;\n }\n }, []);\n\n const checkPosition = useCallback(() => {\n const chkPos = chkPosition(windowRef);\n move(chkPos.translateX, chkPos.translateY);\n }, [move]);\n\n const mouseMove = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n move(e.movementX, e.movementY);\n },\n [move],\n );\n\n const mouseUp = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setMoving(false);\n checkPosition();\n document.removeEventListener('mousemove', mouseMove);\n document.removeEventListener('mouseup', mouseUp);\n window.removeEventListener('resize', checkPosition);\n if (e.target && (e.target instanceof HTMLElement || e.target instanceof SVGElement))\n e.target.style.userSelect = 'auto';\n },\n [checkPosition, mouseMove],\n );\n\n // Update visibility\n useEffect(() => {\n if (windowStack) {\n if (visible && !windowVisible) {\n if (!windowId.current) {\n const maxWindowId = Math.max(0, ...windowStack.currentWindows.map((w) => w.windowId));\n windowId.current = maxWindowId + 1;\n }\n windowStack.pushToTop(windowId.current);\n setWindowVisible(visible);\n onOpen && onOpen();\n // Get starting position\n if (divRef.current && windowRef.current) {\n const parentPos = divRef.current.getBoundingClientRect();\n const pos = windowRef.current.getBoundingClientRect();\n const windowHeight = pos.bottom - pos.top;\n windowRef.current.style.left = `${parentPos.left}px`;\n windowRef.current.style.top = `${\n parentPos.bottom + windowHeight < window.innerHeight\n ? parentPos.bottom\n : Math.max(0, parentPos.top - windowHeight)\n }px`;\n windowRef.current.style.transform = '';\n windowPos.current = { x: 0, y: 0 };\n }\n } else if (windowId.current && !visible && windowVisible) {\n setWindowVisible(false);\n }\n }\n }, [onOpen, visible, windowStack, windowVisible]);\n\n return (\n <div\n className='contextwindow-anchor'\n ref={divRef}\n >\n {windowStack &&\n createPortal(\n <div\n id={id}\n className='contextwindow'\n style={{\n ...style,\n opacity: moving ? 0.8 : windowVisible ? 1 : 0,\n visibility: windowVisible ? 'visible' : 'hidden',\n zIndex: zIndex ?? 1,\n minHeight: style?.minHeight ?? '150px',\n minWidth: style?.minWidth ?? '200px',\n maxHeight: style?.maxHeight ?? '1000px',\n maxWidth: style?.maxWidth ?? '1000px',\n }}\n onClickCapture={() => {\n windowId && windowId.current && windowStack.pushToTop(windowId.current);\n }}\n ref={windowRef}\n >\n <div\n className={`contextwindow-title ${moving ? 'moving' : ''}`}\n onMouseDown={(e: React.MouseEvent) => {\n if (e.target && (e.target instanceof HTMLElement || e.target instanceof SVGElement))\n e.target.style.userSelect = 'none';\n setMoving(true);\n windowId && windowId.current && windowStack.pushToTop(windowId.current);\n document.addEventListener('mouseup', mouseUp);\n document.addEventListener('mousemove', mouseMove);\n window.addEventListener('resize', () => checkPosition());\n }}\n >\n <span className='contextwindow-title-text'>{title}</span>\n <span className='contextwindow-title-close'>\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 onClick={onClose}\n aria-label='Close window'\n >\n <path d='M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z' />\n </svg>\n </span>\n </div>\n <div className='contextwindow-body'>\n <div>{children}</div>\n </div>\n </div>,\n document.body,\n )}\n </div>\n );\n};\n\nContextWindow.displayName = 'ContextWindow';\n","import { createContext, useState } from 'react';\n\nexport interface ContextWindowZIndex {\n windowId: number;\n zIndex: number;\n}\n\nexport interface ContextWindowStackContextProps {\n currentWindows: ContextWindowZIndex[];\n pushToTop: (ret: number) => void;\n}\n\nexport const ContextWindowStackContext = createContext<ContextWindowStackContextProps | null>(null);\n\ninterface ContextWindowStackProps {\n id?: string;\n minZIndex?: number;\n children?: JSX.Element[] | JSX.Element;\n}\n\nconst pushToTop = (\n windowId: number,\n minZIndex: number,\n windowList: ContextWindowZIndex[],\n setWindowList: (ret: ContextWindowZIndex[]) => void,\n) => {\n const otherWindows = windowList\n .filter((w) => w.windowId !== windowId)\n .map((w, i) => ({ windowId: w.windowId, zIndex: minZIndex + i }));\n setWindowList([...otherWindows, { windowId, zIndex: minZIndex + otherWindows.length }]);\n};\n\nexport const ContextWindowStack = ({\n minZIndex = 1000,\n children,\n}: ContextWindowStackProps): JSX.Element => {\n const [currentWindows, setCurrentWindows] = useState<ContextWindowZIndex[]>([]);\n\n return (\n <ContextWindowStackContext.Provider\n value={{\n currentWindows: currentWindows.map((w) => ({\n windowId: w.windowId,\n zIndex: minZIndex + w.zIndex,\n })),\n pushToTop: (ret: number) => pushToTop(ret, minZIndex, currentWindows, setCurrentWindows),\n }}\n >\n {children}\n </ContextWindowStackContext.Provider>\n );\n};\n\nContextWindowStack.displayName = 'ContextWindowStack';\n","import { RefObject } from 'react';\n\n/**\n * Check that an existing div is inside the viewport\n * @param divRef Check div is inside view port, and return n\n * @returns \\{ translateX, translateY \\} Amount to move on X and Y axis\n */\nexport const chkPosition = (\n divRef: RefObject<HTMLDivElement>,\n): { translateX: number; translateY: number } => {\n if (!divRef.current) {\n return { translateX: 0, translateY: 0 };\n } else {\n const innerBounce = 16;\n const posn = divRef.current.getBoundingClientRect();\n let translateX = 0;\n if (posn.left < innerBounce) {\n translateX = -posn.left + innerBounce;\n } else if (posn.right > window.innerWidth) {\n translateX = Math.max(-posn.left + innerBounce, window.innerWidth - posn.right - innerBounce);\n }\n let translateY = 0;\n if (posn.top < innerBounce) {\n translateY = -posn.top + innerBounce;\n } else if (posn.bottom > window.innerHeight) {\n translateY = Math.max(\n -posn.top + innerBounce,\n window.innerHeight - posn.bottom - innerBounce,\n );\n }\n return { translateX, translateY };\n }\n};\n"],"names":[],"version":3,"file":"main.js.map"}
@@ -5,12 +5,15 @@ export interface iMenuItem {
5
5
  action?: (target?: Range | null) => void;
6
6
  group?: iMenuItem[];
7
7
  }
8
+ interface contextMenuHandlerProps {
9
+ children: JSX.Element[] | JSX.Element;
10
+ menuItems: iMenuItem[];
11
+ showLowMenu?: boolean;
12
+ lowMenuTarget?: Range | null;
13
+ style?: React.CSSProperties;
14
+ }
8
15
  export const ContextMenuHandler: {
9
- ({ children, menuItems, style, }: {
10
- children: JSX.Element[] | JSX.Element;
11
- menuItems: iMenuItem[];
12
- style?: import("react").CSSProperties | undefined;
13
- }): JSX.Element;
16
+ ({ children, menuItems, showLowMenu, style, }: contextMenuHandlerProps): JSX.Element;
14
17
  displayName: string;
15
18
  };
16
19
  interface ContextWindowStackProps {
@@ -1 +1 @@
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;;kBAQD,WAAW,EAAE,GAAG,WAAW;mBAC1B,SAAS,EAAE;;QAEpB,WAAW;;CAqEd,CAAC;ACxEF;IACE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,IAAI,OAAO,EAAE,GAAG,IAAI,OAAO,CAAC;CACxC;AAcD,OAAO,MAAM;+BAGV,uBAAuB,GAAG,WAAW;;CAgBvC,CAAC;AE7CF;IACE,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,aAAa,CAAC;IAC5B,QAAQ,EAAE,IAAI,OAAO,EAAE,GAAG,IAAI,OAAO,GAAG,MAAM,CAAC;CAChD;AAED,OAAO,MAAM;gEAQV,kBAAkB,GAAG,WAAW;;CAgJlC,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/ContextWindowStack.tsx","src/src/functions/chkPosition.ts","src/src/components/ContextWindow.tsx","src/src/components/index.ts","src/src/main.ts","src/main.ts"],"sourcesContent":[null,null,null,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;AMED;IACE,QAAQ,EAAE,IAAI,OAAO,EAAE,GAAG,IAAI,OAAO,CAAC;IACtC,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,aAAa,CAAC;CAC7B;AAED,OAAO,MAAM;mDASV,uBAAuB,GAAG,WAAW;;CA2FvC,CAAC;ACrGF;IACE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,IAAI,OAAO,EAAE,GAAG,IAAI,OAAO,CAAC;CACxC;AAcD,OAAO,MAAM;+BAGV,uBAAuB,GAAG,WAAW;;CAgBvC,CAAC;AE7CF;IACE,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,aAAa,CAAC;IAC5B,QAAQ,EAAE,IAAI,OAAO,EAAE,GAAG,IAAI,OAAO,GAAG,MAAM,CAAC;CAChD;AAED,OAAO,MAAM;gEAQV,kBAAkB,GAAG,WAAW;;CAgJlC,CAAC","sources":["src/src/components/interface.ts","src/src/components/ContextSubMenu.tsx","src/src/components/ContextMenu.tsx","src/src/components/LowSubMenu.tsx","src/src/components/LowMenuButton.tsx","src/src/components/LowMenu.tsx","src/src/components/ContextMenuHandler.tsx","src/src/components/ContextWindowStack.tsx","src/src/functions/chkPosition.ts","src/src/components/ContextWindow.tsx","src/src/components/index.ts","src/src/main.ts","src/main.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,null,null,null,null,"export * from './components';\n"],"names":[],"version":3,"file":"context-menu.d.ts.map"}
package/dist/main.css CHANGED
@@ -65,6 +65,64 @@
65
65
  flex-grow: 1;
66
66
  }
67
67
 
68
+ .low-menu {
69
+ z-index: 2;
70
+ -webkit-font-smoothing: antialiased;
71
+ -moz-osx-font-smoothing: grayscale;
72
+ opacity: .5;
73
+ background-color: #111418;
74
+ border: 2px solid #111418;
75
+ border-top-right-radius: 4px;
76
+ border-bottom-right-radius: 4px;
77
+ border-bottom-left-radius: 4px;
78
+ flex-flow: wrap;
79
+ gap: 2px;
80
+ margin: 0;
81
+ font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
82
+ font-size: 9pt;
83
+ transition: opacity .3s linear;
84
+ display: flex;
85
+ position: absolute;
86
+ top: 0;
87
+ box-shadow: 2px 2px 2px rgba(64, 64, 64, .5);
88
+ }
89
+
90
+ .low-menu:hover {
91
+ opacity: 1;
92
+ }
93
+
94
+ .low-menu-item {
95
+ color: #111418;
96
+ cursor: pointer;
97
+ white-space: nowrap;
98
+ background-color: #fbfdf6;
99
+ border: 0;
100
+ border-radius: 4px;
101
+ flex-direction: row;
102
+ justify-content: space-between;
103
+ padding: 0 4px;
104
+ display: flex;
105
+ position: relative;
106
+ }
107
+
108
+ .low-menu-item.disabled {
109
+ cursor: not-allowed;
110
+ background-color: #c8c8c8;
111
+ }
112
+
113
+ .low-menu-item:not(.disabled):hover {
114
+ background-color: #fbe9e6;
115
+ }
116
+
117
+ .low-menu-item .caret-holder {
118
+ align-self: flex-end;
119
+ }
120
+
121
+ .low-menu-item .caret-holder .sub-menu {
122
+ z-index: 1;
123
+ position: relative;
124
+ }
125
+
68
126
  .contextwindow {
69
127
  z-index: 2001;
70
128
  resize: both;
package/dist/main.css.map CHANGED
@@ -1 +1 @@
1
- {"mappings":"AAAA;;;;;;;;;;AAWA;;;;AAIA;;;;;;;;;;;;;AAaA;;;;;AAKA;;;;AAIA;;;;AAIA;;;;AAIA;;;;;AAKA;;;;;AAKA;;;;AAIA;;;;;AAKA;;;;AChEA;;;;;;;;;;;;;;;;;AAiBA;;;;;;;;;;;;AAYA;;;;AAIA;;;;AAIA;;;;;;AAMA;;;;;;;AAOA;;;;;AAKA;;;;;AAKA;;;;;;AAMA","sources":["src/components/ContextMenu.css","src/components/ContextWindow.css"],"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 margin-top: 4px;\n}\n\n.context-menu-item:last-child {\n margin-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\n.context-menu-item-label {\n flex-grow: 1;\n}\n",".contextwindow {\n z-index: 2001;\n border: 1px black solid;\n margin: 0;\n padding: 4px;\n background-color: rgb(250, 250, 250);\n box-shadow: 6px 6px 6px rgb(64, 64, 64, 0.5);\n transition: opacity 0.25s linear;\n justify-content: flex-start;\n position: absolute;\n border-top-left-radius: 8px;\n border-top-right-radius: 8px;\n border-bottom-left-radius: 8px;\n resize: both;\n overflow: auto;\n}\n\n.contextwindow-title {\n text-transform: capitalize;\n border-bottom: 1px black dashed;\n padding-bottom: 4px;\n margin: 0 4px 3px 4px;\n font-size: 18px;\n font-weight: 600;\n flex-grow: 1;\n height: 24px;\n cursor: grab;\n}\n\n.contextwindow-title.moving {\n cursor: grabbing;\n}\n\n.contextwindow-title-text {\n display: inline-block;\n}\n\n.contextwindow-title-close {\n float: right;\n font-size: small;\n cursor: auto;\n}\n\n.contextwindow-body {\n overflow: auto;\n padding-bottom: 8px;\n margin-right: 4px;\n height: calc(100% - 40px);\n}\n\n.contextwindow-body::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n.contextwindow-body::-webkit-scrollbar-track {\n background: white;\n border-radius: 8px;\n}\n\n.contextwindow-body::-webkit-scrollbar-thumb {\n background: lightgrey;\n border: none;\n border-radius: 8px;\n}\n\n.contextwindow-body::-webkit-scrollbar-thumb:hover {\n background: grey;\n}\n"],"names":[],"version":3,"file":"main.css.map"}
1
+ {"mappings":"AAAA;;;;;;;;;;AAWA;;;;AAIA;;;;;;;;;;;;;AAaA;;;;;AAKA;;;;AAIA;;;;AAIA;;;;AAIA;;;;;AAKA;;;;;AAKA;;;;AAIA;;;;;AAKA;;;;AChEA;;;;;;;;;;;;;;;;;;;;;;AAyBA;;;;AAIA;;;;;;;;;;;;;;AAcA;;;;;AAKA;;;;AAIA;;;;AAIA;;;;;ACxDA;;;;;;;;;;;;;;;;;AAiBA;;;;;;;;;;;;AAYA;;;;AAIA;;;;AAIA;;;;;;AAMA;;;;;;;AAOA;;;;;AAKA;;;;;AAKA;;;;;;AAMA","sources":["src/components/ContextMenu.css","src/components/LowMenu.css","src/components/ContextWindow.css"],"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 margin-top: 4px;\n}\n\n.context-menu-item:last-child {\n margin-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\n.context-menu-item-label {\n flex-grow: 1;\n}\n",".low-menu {\n z-index: 2;\n position: absolute;\n top: 0;\n margin: 0px;\n border: 2px solid rgb(17, 20, 24);\n border-top-right-radius: 4px;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n background-color: rgb(17, 20, 24);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',\n 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n font-size: 9pt;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n box-shadow: 2px 2px 2px rgb(64, 64, 64, 0.5);\n opacity: 0.5;\n transition: opacity 0.3s linear;\n display: flex;\n flex-wrap: wrap;\n flex-direction: row;\n gap: 2px;\n row-gap: 2px;\n}\n\n.low-menu:hover {\n opacity: 1;\n}\n\n.low-menu-item {\n background-color: rgb(251, 253, 246);\n border: 0;\n border-radius: 4px;\n color: rgb(17, 20, 24);\n cursor: pointer;\n padding: 0 4px;\n position: relative;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n white-space: nowrap;\n}\n\n.low-menu-item.disabled {\n background-color: rgba(200, 200, 200);\n cursor: not-allowed;\n}\n\n.low-menu-item:not(.disabled):hover {\n background-color: rgb(251, 233, 230);\n}\n\n.low-menu-item .caret-holder {\n align-self: flex-end;\n}\n\n.low-menu-item .caret-holder .sub-menu {\n z-index: 1;\n position: relative;\n}\n",".contextwindow {\n z-index: 2001;\n border: 1px black solid;\n margin: 0;\n padding: 4px;\n background-color: rgb(250, 250, 250);\n box-shadow: 6px 6px 6px rgb(64, 64, 64, 0.5);\n transition: opacity 0.25s linear;\n justify-content: flex-start;\n position: absolute;\n border-top-left-radius: 8px;\n border-top-right-radius: 8px;\n border-bottom-left-radius: 8px;\n resize: both;\n overflow: auto;\n}\n\n.contextwindow-title {\n text-transform: capitalize;\n border-bottom: 1px black dashed;\n padding-bottom: 4px;\n margin: 0 4px 3px 4px;\n font-size: 18px;\n font-weight: 600;\n flex-grow: 1;\n height: 24px;\n cursor: grab;\n}\n\n.contextwindow-title.moving {\n cursor: grabbing;\n}\n\n.contextwindow-title-text {\n display: inline-block;\n}\n\n.contextwindow-title-close {\n float: right;\n font-size: small;\n cursor: auto;\n}\n\n.contextwindow-body {\n overflow: auto;\n padding-bottom: 8px;\n margin-right: 4px;\n height: calc(100% - 40px);\n}\n\n.contextwindow-body::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n.contextwindow-body::-webkit-scrollbar-track {\n background: white;\n border-radius: 8px;\n}\n\n.contextwindow-body::-webkit-scrollbar-thumb {\n background: lightgrey;\n border: none;\n border-radius: 8px;\n}\n\n.contextwindow-body::-webkit-scrollbar-thumb:hover {\n background: grey;\n}\n"],"names":[],"version":3,"file":"main.css.map"}
package/dist/main.js CHANGED
@@ -19,7 +19,7 @@ $parcel$export($b65191f6d0a0a991$exports, "ContextWindowStack", function () { re
19
19
 
20
20
 
21
21
 
22
- const $885a1576aecbe1c6$export$a9c522a6d7beb830 = ({ entries: entries, target: target, toClose: toClose })=>{
22
+ const $6ca59110355c8bf1$export$7e4e6110f96afd7e = ({ entries: entries, target: target, toClose: toClose })=>{
23
23
  const [visible, setVisible] = (0, $duWW8$useState)(false);
24
24
  return /*#__PURE__*/ (0, $duWW8$jsxs)("span", {
25
25
  className: "caret-holder",
@@ -54,7 +54,7 @@ const $885a1576aecbe1c6$export$a9c522a6d7beb830 = ({ entries: entries, target: t
54
54
  ]
55
55
  });
56
56
  };
57
- $885a1576aecbe1c6$export$a9c522a6d7beb830.displayName = "SubMenu";
57
+ $6ca59110355c8bf1$export$7e4e6110f96afd7e.displayName = "ContextSubMenu";
58
58
 
59
59
 
60
60
  const $567ed433af94513f$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, $duWW8$react).forwardRef(({ visible: visible, entries: entries, target: target, xPos: xPos, yPos: yPos, toClose: toClose }, ref)=>{
@@ -70,22 +70,24 @@ const $567ed433af94513f$export$8dc6765e8be191c7 = /*#__PURE__*/ (0, $duWW8$react
70
70
  e.preventDefault();
71
71
  e.stopPropagation();
72
72
  },
73
- children: entries.map((e, i)=>/*#__PURE__*/ (0, $duWW8$jsxs)("div", {
74
- className: `context-menu-item${e.disabled ? " disabled" : ""}`,
75
- onClick: (ev)=>{
73
+ children: entries.map((entry, i)=>/*#__PURE__*/ (0, $duWW8$jsxs)("div", {
74
+ className: `context-menu-item${entry.disabled ? " disabled" : ""}`,
75
+ "aria-label": entry.label,
76
+ "aria-disabled": entry.disabled,
77
+ onMouseDownCapture: (ev)=>{
76
78
  ev.preventDefault();
77
79
  ev.stopPropagation();
78
- e.action && !e.disabled && e.action(target);
79
- !e.disabled && toClose();
80
+ entry.action && !entry.disabled && entry.action(target);
81
+ !entry.disabled && toClose();
80
82
  },
81
83
  children: [
82
84
  /*#__PURE__*/ (0, $duWW8$jsx)("span", {
83
85
  className: "context-menu-item-label",
84
- children: e.label
86
+ children: entry.label
85
87
  }),
86
- e.group && /*#__PURE__*/ (0, $duWW8$jsx)((0, $885a1576aecbe1c6$export$a9c522a6d7beb830), {
88
+ entry.group && /*#__PURE__*/ (0, $duWW8$jsx)((0, $6ca59110355c8bf1$export$7e4e6110f96afd7e), {
87
89
  toClose: toClose,
88
- entries: e.group,
90
+ entries: entry.group,
89
91
  target: target
90
92
  })
91
93
  ]
@@ -96,7 +98,91 @@ $567ed433af94513f$export$8dc6765e8be191c7.displayName = "ContextMenu";
96
98
 
97
99
 
98
100
 
99
- const $1e1c1e9e0b943830$export$ed4f9641643dc7e4 = ({ children: children, menuItems: menuItems, style: style = {
101
+
102
+
103
+
104
+
105
+
106
+
107
+ const $61945e5157f5e5bf$export$251b9f54013cdfac = ({ entry: entry, target: target })=>{
108
+ const [visible, setVisible] = (0, $duWW8$useState)(false);
109
+ if (!entry.group || entry.group.length === 0) return /*#__PURE__*/ (0, $duWW8$jsx)((0, $duWW8$Fragment), {});
110
+ return /*#__PURE__*/ (0, $duWW8$jsxs)("span", {
111
+ "aria-label": `Sub menu for ${entry.label}`,
112
+ className: "caret-holder",
113
+ onMouseEnter: ()=>{
114
+ setVisible(true);
115
+ },
116
+ onMouseLeave: ()=>{
117
+ setVisible(false);
118
+ },
119
+ children: [
120
+ /*#__PURE__*/ (0, $duWW8$jsx)("svg", {
121
+ xmlns: "http://www.w3.org/2000/svg",
122
+ width: "16",
123
+ height: "16",
124
+ fill: "currentColor",
125
+ viewBox: "0 0 16 16",
126
+ children: /*#__PURE__*/ (0, $duWW8$jsx)("path", {
127
+ 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"
128
+ })
129
+ }),
130
+ /*#__PURE__*/ (0, $duWW8$jsx)("div", {
131
+ className: "sub-menu",
132
+ children: /*#__PURE__*/ (0, $duWW8$jsx)((0, $567ed433af94513f$export$8dc6765e8be191c7), {
133
+ visible: visible,
134
+ entries: entry.group,
135
+ target: target,
136
+ xPos: 14,
137
+ yPos: entry.group.length * -21 - 8,
138
+ toClose: ()=>setVisible(false)
139
+ })
140
+ })
141
+ ]
142
+ });
143
+ };
144
+ $61945e5157f5e5bf$export$251b9f54013cdfac.displayName = "LowSubMenu";
145
+
146
+
147
+ const $556d6f9158abfc99$export$aafc28aea571c4bc = ({ entry: entry, target: target })=>{
148
+ return /*#__PURE__*/ (0, $duWW8$jsxs)("div", {
149
+ className: `low-menu-item${entry.disabled ? " disabled" : ""}`,
150
+ "aria-label": entry.label,
151
+ "aria-disabled": entry.disabled,
152
+ onClick: (event)=>{
153
+ event.preventDefault();
154
+ event.stopPropagation();
155
+ entry.action && !entry.disabled && entry.action(target);
156
+ },
157
+ children: [
158
+ /*#__PURE__*/ (0, $duWW8$jsx)("span", {
159
+ className: "low-menu-item-label",
160
+ children: entry.label
161
+ }),
162
+ entry.group && /*#__PURE__*/ (0, $duWW8$jsx)((0, $61945e5157f5e5bf$export$251b9f54013cdfac), {
163
+ entry: entry,
164
+ target: target
165
+ })
166
+ ]
167
+ });
168
+ };
169
+ $556d6f9158abfc99$export$aafc28aea571c4bc.displayName = "LowMenuButton";
170
+
171
+
172
+ const $914758b0c9d59759$export$49e8edc8ebca5f25 = ({ entries: entries, target: target })=>{
173
+ return /*#__PURE__*/ (0, $duWW8$jsx)("div", {
174
+ className: "low-menu",
175
+ "aria-label": "Low context menu",
176
+ children: entries.map((e, i)=>/*#__PURE__*/ (0, $duWW8$jsx)((0, $556d6f9158abfc99$export$aafc28aea571c4bc), {
177
+ entry: e,
178
+ target: target
179
+ }, i))
180
+ });
181
+ };
182
+ $914758b0c9d59759$export$49e8edc8ebca5f25.displayName = "LowMenu";
183
+
184
+
185
+ const $1e1c1e9e0b943830$export$ed4f9641643dc7e4 = ({ children: children, menuItems: menuItems, showLowMenu: showLowMenu = false, style: style = {
100
186
  height: "fit-content",
101
187
  width: "fit-content"
102
188
  } })=>{
@@ -107,6 +193,7 @@ const $1e1c1e9e0b943830$export$ed4f9641643dc7e4 = ({ children: children, menuIte
107
193
  const [menuYPos, setMenuYPos] = (0, $duWW8$useState)(0);
108
194
  const [menuVisible, setMenuVisible] = (0, $duWW8$useState)(false);
109
195
  const [target, setTarget] = (0, $duWW8$useState)(null);
196
+ const [lowTarget, setLowTarget] = (0, $duWW8$useState)(null);
110
197
  // Show menu when context is requested
111
198
  const showMenu = (e)=>{
112
199
  const sel = window.getSelection();
@@ -136,12 +223,12 @@ const $1e1c1e9e0b943830$export$ed4f9641643dc7e4 = ({ children: children, menuIte
136
223
  return /*#__PURE__*/ (0, $duWW8$jsxs)((0, $duWW8$Fragment), {
137
224
  children: [
138
225
  /*#__PURE__*/ (0, $duWW8$jsx)("div", {
139
- onContextMenu: showMenu,
226
+ onContextMenu: showLowMenu ? undefined : showMenu,
140
227
  className: "context-menu-handler",
141
228
  style: style,
142
229
  children: children
143
230
  }),
144
- menuVisible && /*#__PURE__*/ (0, $duWW8$createPortal)(/*#__PURE__*/ (0, $duWW8$jsx)("div", {
231
+ menuVisible && !showLowMenu && /*#__PURE__*/ (0, $duWW8$createPortal)(/*#__PURE__*/ (0, $duWW8$jsx)("div", {
145
232
  style: {
146
233
  position: "absolute",
147
234
  top: 0,
@@ -157,7 +244,25 @@ const $1e1c1e9e0b943830$export$ed4f9641643dc7e4 = ({ children: children, menuIte
157
244
  target: target,
158
245
  toClose: ()=>setMenuVisible(false)
159
246
  })
160
- }), document.body)
247
+ }), document.body),
248
+ showLowMenu && /*#__PURE__*/ (0, $duWW8$jsx)("div", {
249
+ style: {
250
+ position: "relative"
251
+ },
252
+ onMouseEnter: ()=>{
253
+ const sel = window.getSelection();
254
+ const lowSel = sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
255
+ setLowTarget(lowSel);
256
+ },
257
+ onMouseLeave: ()=>{
258
+ setLowTarget(null);
259
+ },
260
+ children: /*#__PURE__*/ (0, $duWW8$jsx)((0, $914758b0c9d59759$export$49e8edc8ebca5f25), {
261
+ entries: menuItems,
262
+ target: lowTarget
263
+ })
264
+ }),
265
+ " "
161
266
  ]
162
267
  });
163
268
  };
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","src/components/ContextWindow.tsx","src/components/ContextWindowStack.tsx","src/functions/chkPosition.ts"],"sourcesContent":["export * from './components';\n","import { ContextMenuHandler } from './ContextMenuHandler';\nimport { ContextWindow } from './ContextWindow';\nimport { ContextWindowStack } from './ContextWindowStack';\nimport { iMenuItem } from './interface';\n\nexport { ContextMenuHandler, ContextWindow, ContextWindowStack };\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.css';\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\nContextMenuHandler.displayName = 'ContextMenuHandler';\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 onContextMenuCapture={(e) => {\n e.preventDefault();\n e.stopPropagation();\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(target);\n !e.disabled && toClose();\n }}\n >\n <span className='context-menu-item-label'>{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\nContextMenu.displayName = 'ContextMenu';\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\nSubMenu.displayName = 'SubMenu';\n","import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport './ContextWindow.css';\nimport { ContextWindowStackContext } from './ContextWindowStack';\nimport { chkPosition } from '../functions/chkPosition';\n\ninterface ContextWindowProps {\n id: string;\n visible: boolean;\n onOpen?: () => void;\n onClose?: () => void;\n title: string;\n style?: React.CSSProperties;\n children: JSX.Element[] | JSX.Element | string;\n}\n\nexport const ContextWindow = ({\n id,\n visible,\n title,\n style,\n children,\n onOpen,\n onClose,\n}: ContextWindowProps): JSX.Element => {\n const windowStack = useContext(ContextWindowStackContext);\n const windowId = useRef<number | null>(null);\n const divRef = useRef<HTMLDivElement | null>(null);\n const windowRef = useRef<HTMLDivElement | null>(null);\n const [windowVisible, setWindowVisible] = useState<boolean>(false);\n const zIndex = useMemo(() => {\n return windowStack?.currentWindows.find((w) => w.windowId === windowId.current)?.zIndex ?? 1;\n }, [windowStack?.currentWindows]);\n\n // Position\n const windowPos = useRef<{ x: number; y: number }>({ x: 0, y: 0 });\n const [moving, setMoving] = useState<boolean>(false);\n\n const move = useCallback((x: number, y: number) => {\n if (windowRef.current && windowPos.current) {\n const window = windowRef.current;\n const pos = windowPos.current;\n pos.x += x;\n pos.y += y;\n window.style.transform = `translate(${pos.x}px, ${pos.y}px)`;\n }\n }, []);\n\n const checkPosition = useCallback(() => {\n const chkPos = chkPosition(windowRef);\n move(chkPos.translateX, chkPos.translateY);\n }, [move]);\n\n const mouseMove = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n move(e.movementX, e.movementY);\n },\n [move],\n );\n\n const mouseUp = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setMoving(false);\n checkPosition();\n document.removeEventListener('mousemove', mouseMove);\n document.removeEventListener('mouseup', mouseUp);\n window.removeEventListener('resize', checkPosition);\n if (e.target && (e.target instanceof HTMLElement || e.target instanceof SVGElement))\n e.target.style.userSelect = 'auto';\n },\n [checkPosition, mouseMove],\n );\n\n // Update visibility\n useEffect(() => {\n if (windowStack) {\n if (visible && !windowVisible) {\n if (!windowId.current) {\n const maxWindowId = Math.max(0, ...windowStack.currentWindows.map((w) => w.windowId));\n windowId.current = maxWindowId + 1;\n }\n windowStack.pushToTop(windowId.current);\n setWindowVisible(visible);\n onOpen && onOpen();\n // Get starting position\n if (divRef.current && windowRef.current) {\n const parentPos = divRef.current.getBoundingClientRect();\n const pos = windowRef.current.getBoundingClientRect();\n const windowHeight = pos.bottom - pos.top;\n windowRef.current.style.left = `${parentPos.left}px`;\n windowRef.current.style.top = `${\n parentPos.bottom + windowHeight < window.innerHeight\n ? parentPos.bottom\n : Math.max(0, parentPos.top - windowHeight)\n }px`;\n windowRef.current.style.transform = '';\n windowPos.current = { x: 0, y: 0 };\n }\n } else if (windowId.current && !visible && windowVisible) {\n setWindowVisible(false);\n }\n }\n }, [onOpen, visible, windowStack, windowVisible]);\n\n return (\n <div\n className='contextwindow-anchor'\n ref={divRef}\n >\n {windowStack &&\n createPortal(\n <div\n id={id}\n className='contextwindow'\n style={{\n ...style,\n opacity: moving ? 0.8 : windowVisible ? 1 : 0,\n visibility: windowVisible ? 'visible' : 'hidden',\n zIndex: zIndex ?? 1,\n minHeight: style?.minHeight ?? '150px',\n minWidth: style?.minWidth ?? '200px',\n maxHeight: style?.maxHeight ?? '1000px',\n maxWidth: style?.maxWidth ?? '1000px',\n }}\n onClickCapture={() => {\n windowId && windowId.current && windowStack.pushToTop(windowId.current);\n }}\n ref={windowRef}\n >\n <div\n className={`contextwindow-title ${moving ? 'moving' : ''}`}\n onMouseDown={(e: React.MouseEvent) => {\n if (e.target && (e.target instanceof HTMLElement || e.target instanceof SVGElement))\n e.target.style.userSelect = 'none';\n setMoving(true);\n windowId && windowId.current && windowStack.pushToTop(windowId.current);\n document.addEventListener('mouseup', mouseUp);\n document.addEventListener('mousemove', mouseMove);\n window.addEventListener('resize', () => checkPosition());\n }}\n >\n <span className='contextwindow-title-text'>{title}</span>\n <span className='contextwindow-title-close'>\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 onClick={onClose}\n aria-label='Close window'\n >\n <path d='M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z' />\n </svg>\n </span>\n </div>\n <div className='contextwindow-body'>\n <div>{children}</div>\n </div>\n </div>,\n document.body,\n )}\n </div>\n );\n};\n\nContextWindow.displayName = 'ContextWindow';\n","import { createContext, useState } from 'react';\n\nexport interface ContextWindowZIndex {\n windowId: number;\n zIndex: number;\n}\n\nexport interface ContextWindowStackContextProps {\n currentWindows: ContextWindowZIndex[];\n pushToTop: (ret: number) => void;\n}\n\nexport const ContextWindowStackContext = createContext<ContextWindowStackContextProps | null>(null);\n\ninterface ContextWindowStackProps {\n id?: string;\n minZIndex?: number;\n children?: JSX.Element[] | JSX.Element;\n}\n\nconst pushToTop = (\n windowId: number,\n minZIndex: number,\n windowList: ContextWindowZIndex[],\n setWindowList: (ret: ContextWindowZIndex[]) => void,\n) => {\n const otherWindows = windowList\n .filter((w) => w.windowId !== windowId)\n .map((w, i) => ({ windowId: w.windowId, zIndex: minZIndex + i }));\n setWindowList([...otherWindows, { windowId, zIndex: minZIndex + otherWindows.length }]);\n};\n\nexport const ContextWindowStack = ({\n minZIndex = 1000,\n children,\n}: ContextWindowStackProps): JSX.Element => {\n const [currentWindows, setCurrentWindows] = useState<ContextWindowZIndex[]>([]);\n\n return (\n <ContextWindowStackContext.Provider\n value={{\n currentWindows: currentWindows.map((w) => ({\n windowId: w.windowId,\n zIndex: minZIndex + w.zIndex,\n })),\n pushToTop: (ret: number) => pushToTop(ret, minZIndex, currentWindows, setCurrentWindows),\n }}\n >\n {children}\n </ContextWindowStackContext.Provider>\n );\n};\n\nContextWindowStack.displayName = 'ContextWindowStack';\n","import { RefObject } from 'react';\n\n/**\n * Check that an existing div is inside the viewport\n * @param divRef Check div is inside view port, and return n\n * @returns \\{ translateX, translateY \\} Amount to move on X and Y axis\n */\nexport const chkPosition = (\n divRef: RefObject<HTMLDivElement>,\n): { translateX: number; translateY: number } => {\n if (!divRef.current) {\n return { translateX: 0, translateY: 0 };\n } else {\n const innerBounce = 16;\n const posn = divRef.current.getBoundingClientRect();\n let translateX = 0;\n if (posn.left < innerBounce) {\n translateX = -posn.left + innerBounce;\n } else if (posn.right > window.innerWidth) {\n translateX = Math.max(-posn.left + innerBounce, window.innerWidth - posn.right - innerBounce);\n }\n let translateY = 0;\n if (posn.top < innerBounce) {\n translateY = -posn.top + innerBounce;\n } else if (posn.bottom > window.innerHeight) {\n translateY = Math.max(\n -posn.top + innerBounce,\n window.innerHeight - posn.bottom - innerBounce,\n );\n }\n return { translateX, translateY };\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/ContextSubMenu.tsx","src/components/LowMenu.tsx","src/components/LowMenuButton.tsx","src/components/LowSubMenu.tsx","src/components/ContextWindow.tsx","src/components/ContextWindowStack.tsx","src/functions/chkPosition.ts"],"sourcesContent":["export * from './components';\n","import { ContextMenuHandler } from './ContextMenuHandler';\nimport { ContextWindow } from './ContextWindow';\nimport { ContextWindowStack } from './ContextWindowStack';\nimport { iMenuItem } from './interface';\n\nexport { ContextMenuHandler, ContextWindow, ContextWindowStack };\nexport type { iMenuItem };\n","import { MouseEvent, useCallback, useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { ContextMenu } from './ContextMenu';\nimport './ContextMenu.css';\nimport { LowMenu } from './LowMenu';\nimport { iMenuItem } from './interface';\n\ninterface contextMenuHandlerProps {\n children: JSX.Element[] | JSX.Element;\n menuItems: iMenuItem[];\n showLowMenu?: boolean;\n lowMenuTarget?: Range | null;\n style?: React.CSSProperties;\n}\n\nexport const ContextMenuHandler = ({\n children,\n menuItems,\n showLowMenu = false,\n style = {\n height: 'fit-content',\n width: 'fit-content',\n },\n}: contextMenuHandlerProps): 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 const [lowTarget, setLowTarget] = 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={showLowMenu ? undefined : showMenu}\n className='context-menu-handler'\n style={style}\n >\n {children}\n </div>\n {menuVisible &&\n !showLowMenu &&\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 {showLowMenu && (\n <div\n style={{ position: 'relative' }}\n onMouseEnter={() => {\n const sel = window.getSelection();\n const lowSel = sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null;\n setLowTarget(lowSel);\n }}\n onMouseLeave={() => {\n setLowTarget(null);\n }}\n >\n <LowMenu\n entries={menuItems}\n target={lowTarget}\n />\n </div>\n )}{' '}\n </>\n );\n};\n\nContextMenuHandler.displayName = 'ContextMenuHandler';\n","import React from 'react';\nimport { ContextSubMenu } from './ContextSubMenu';\nimport { iMenuItem } from './interface';\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 onContextMenuCapture={(e) => {\n e.preventDefault();\n e.stopPropagation();\n }}\n >\n {entries.map((entry, i) => (\n <div\n key={i}\n className={`context-menu-item${entry.disabled ? ' disabled' : ''}`}\n aria-label={entry.label}\n aria-disabled={entry.disabled}\n onMouseDownCapture={(ev) => {\n ev.preventDefault();\n ev.stopPropagation();\n entry.action && !entry.disabled && entry.action(target);\n !entry.disabled && toClose();\n }}\n >\n <span className='context-menu-item-label'>{entry.label}</span>\n {entry.group && (\n <ContextSubMenu\n toClose={toClose}\n entries={entry.group}\n target={target}\n />\n )}\n </div>\n ))}\n </div>\n );\n },\n);\n\nContextMenu.displayName = 'ContextMenu';\n","import { useState } from 'react';\nimport { ContextMenu } from './ContextMenu';\nimport { iMenuItem } from './interface';\n\nexport interface ContextSubMenuProps {\n entries: iMenuItem[];\n target: Range | null;\n toClose: () => void;\n lowMenu?: boolean;\n}\n\nexport const ContextSubMenu = ({ entries, target, toClose }: ContextSubMenuProps): 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\nContextSubMenu.displayName = 'ContextSubMenu';\n","import { iMenuItem } from './interface';\nimport './LowMenu.css';\nimport { LowMenuButton } from './LowMenuButton';\n\ninterface LowMenuProps {\n entries: iMenuItem[];\n target: Range | null;\n}\n\nexport const LowMenu = ({ entries, target }: LowMenuProps): JSX.Element => {\n return (\n <div\n className='low-menu'\n aria-label='Low context menu'\n >\n {entries.map((e, i) => (\n <LowMenuButton\n key={i}\n entry={e}\n target={target}\n />\n ))}\n </div>\n );\n};\n\nLowMenu.displayName = 'LowMenu';\n","import { LowSubMenu } from './LowSubMenu';\nimport { iMenuItem } from './interface';\n\ninterface LowMenuButtonProps {\n entry: iMenuItem;\n target: Range | null;\n}\nexport const LowMenuButton = ({ entry, target }: LowMenuButtonProps) => {\n return (\n <div\n className={`low-menu-item${entry.disabled ? ' disabled' : ''}`}\n aria-label={entry.label}\n aria-disabled={entry.disabled}\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n entry.action && !entry.disabled && entry.action(target);\n }}\n >\n <span className='low-menu-item-label'>{entry.label}</span>\n {entry.group && (\n <LowSubMenu\n entry={entry}\n target={target}\n />\n )}\n </div>\n );\n};\n\nLowMenuButton.displayName = 'LowMenuButton';\n","import { useState } from 'react';\nimport { ContextMenu } from './ContextMenu';\nimport { iMenuItem } from './interface';\n\nexport interface LowSubMenuProps {\n entry: iMenuItem;\n target: Range | null;\n lowMenu?: boolean;\n}\n\nexport const LowSubMenu = ({ entry, target }: LowSubMenuProps): JSX.Element => {\n const [visible, setVisible] = useState<boolean>(false);\n if (!entry.group || entry.group.length === 0) return <></>;\n return (\n <span\n aria-label={`Sub menu for ${entry.label}`}\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={entry.group}\n target={target}\n xPos={14}\n yPos={entry.group.length * -21 - 8}\n toClose={() => setVisible(false)}\n />\n </div>\n </span>\n );\n};\n\nLowSubMenu.displayName = 'LowSubMenu';\n","import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport './ContextWindow.css';\nimport { ContextWindowStackContext } from './ContextWindowStack';\nimport { chkPosition } from '../functions/chkPosition';\n\ninterface ContextWindowProps {\n id: string;\n visible: boolean;\n onOpen?: () => void;\n onClose?: () => void;\n title: string;\n style?: React.CSSProperties;\n children: JSX.Element[] | JSX.Element | string;\n}\n\nexport const ContextWindow = ({\n id,\n visible,\n title,\n style,\n children,\n onOpen,\n onClose,\n}: ContextWindowProps): JSX.Element => {\n const windowStack = useContext(ContextWindowStackContext);\n const windowId = useRef<number | null>(null);\n const divRef = useRef<HTMLDivElement | null>(null);\n const windowRef = useRef<HTMLDivElement | null>(null);\n const [windowVisible, setWindowVisible] = useState<boolean>(false);\n const zIndex = useMemo(() => {\n return windowStack?.currentWindows.find((w) => w.windowId === windowId.current)?.zIndex ?? 1;\n }, [windowStack?.currentWindows]);\n\n // Position\n const windowPos = useRef<{ x: number; y: number }>({ x: 0, y: 0 });\n const [moving, setMoving] = useState<boolean>(false);\n\n const move = useCallback((x: number, y: number) => {\n if (windowRef.current && windowPos.current) {\n const window = windowRef.current;\n const pos = windowPos.current;\n pos.x += x;\n pos.y += y;\n window.style.transform = `translate(${pos.x}px, ${pos.y}px)`;\n }\n }, []);\n\n const checkPosition = useCallback(() => {\n const chkPos = chkPosition(windowRef);\n move(chkPos.translateX, chkPos.translateY);\n }, [move]);\n\n const mouseMove = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n move(e.movementX, e.movementY);\n },\n [move],\n );\n\n const mouseUp = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setMoving(false);\n checkPosition();\n document.removeEventListener('mousemove', mouseMove);\n document.removeEventListener('mouseup', mouseUp);\n window.removeEventListener('resize', checkPosition);\n if (e.target && (e.target instanceof HTMLElement || e.target instanceof SVGElement))\n e.target.style.userSelect = 'auto';\n },\n [checkPosition, mouseMove],\n );\n\n // Update visibility\n useEffect(() => {\n if (windowStack) {\n if (visible && !windowVisible) {\n if (!windowId.current) {\n const maxWindowId = Math.max(0, ...windowStack.currentWindows.map((w) => w.windowId));\n windowId.current = maxWindowId + 1;\n }\n windowStack.pushToTop(windowId.current);\n setWindowVisible(visible);\n onOpen && onOpen();\n // Get starting position\n if (divRef.current && windowRef.current) {\n const parentPos = divRef.current.getBoundingClientRect();\n const pos = windowRef.current.getBoundingClientRect();\n const windowHeight = pos.bottom - pos.top;\n windowRef.current.style.left = `${parentPos.left}px`;\n windowRef.current.style.top = `${\n parentPos.bottom + windowHeight < window.innerHeight\n ? parentPos.bottom\n : Math.max(0, parentPos.top - windowHeight)\n }px`;\n windowRef.current.style.transform = '';\n windowPos.current = { x: 0, y: 0 };\n }\n } else if (windowId.current && !visible && windowVisible) {\n setWindowVisible(false);\n }\n }\n }, [onOpen, visible, windowStack, windowVisible]);\n\n return (\n <div\n className='contextwindow-anchor'\n ref={divRef}\n >\n {windowStack &&\n createPortal(\n <div\n id={id}\n className='contextwindow'\n style={{\n ...style,\n opacity: moving ? 0.8 : windowVisible ? 1 : 0,\n visibility: windowVisible ? 'visible' : 'hidden',\n zIndex: zIndex ?? 1,\n minHeight: style?.minHeight ?? '150px',\n minWidth: style?.minWidth ?? '200px',\n maxHeight: style?.maxHeight ?? '1000px',\n maxWidth: style?.maxWidth ?? '1000px',\n }}\n onClickCapture={() => {\n windowId && windowId.current && windowStack.pushToTop(windowId.current);\n }}\n ref={windowRef}\n >\n <div\n className={`contextwindow-title ${moving ? 'moving' : ''}`}\n onMouseDown={(e: React.MouseEvent) => {\n if (e.target && (e.target instanceof HTMLElement || e.target instanceof SVGElement))\n e.target.style.userSelect = 'none';\n setMoving(true);\n windowId && windowId.current && windowStack.pushToTop(windowId.current);\n document.addEventListener('mouseup', mouseUp);\n document.addEventListener('mousemove', mouseMove);\n window.addEventListener('resize', () => checkPosition());\n }}\n >\n <span className='contextwindow-title-text'>{title}</span>\n <span className='contextwindow-title-close'>\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 onClick={onClose}\n aria-label='Close window'\n >\n <path d='M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z' />\n </svg>\n </span>\n </div>\n <div className='contextwindow-body'>\n <div>{children}</div>\n </div>\n </div>,\n document.body,\n )}\n </div>\n );\n};\n\nContextWindow.displayName = 'ContextWindow';\n","import { createContext, useState } from 'react';\n\nexport interface ContextWindowZIndex {\n windowId: number;\n zIndex: number;\n}\n\nexport interface ContextWindowStackContextProps {\n currentWindows: ContextWindowZIndex[];\n pushToTop: (ret: number) => void;\n}\n\nexport const ContextWindowStackContext = createContext<ContextWindowStackContextProps | null>(null);\n\ninterface ContextWindowStackProps {\n id?: string;\n minZIndex?: number;\n children?: JSX.Element[] | JSX.Element;\n}\n\nconst pushToTop = (\n windowId: number,\n minZIndex: number,\n windowList: ContextWindowZIndex[],\n setWindowList: (ret: ContextWindowZIndex[]) => void,\n) => {\n const otherWindows = windowList\n .filter((w) => w.windowId !== windowId)\n .map((w, i) => ({ windowId: w.windowId, zIndex: minZIndex + i }));\n setWindowList([...otherWindows, { windowId, zIndex: minZIndex + otherWindows.length }]);\n};\n\nexport const ContextWindowStack = ({\n minZIndex = 1000,\n children,\n}: ContextWindowStackProps): JSX.Element => {\n const [currentWindows, setCurrentWindows] = useState<ContextWindowZIndex[]>([]);\n\n return (\n <ContextWindowStackContext.Provider\n value={{\n currentWindows: currentWindows.map((w) => ({\n windowId: w.windowId,\n zIndex: minZIndex + w.zIndex,\n })),\n pushToTop: (ret: number) => pushToTop(ret, minZIndex, currentWindows, setCurrentWindows),\n }}\n >\n {children}\n </ContextWindowStackContext.Provider>\n );\n};\n\nContextWindowStack.displayName = 'ContextWindowStack';\n","import { RefObject } from 'react';\n\n/**\n * Check that an existing div is inside the viewport\n * @param divRef Check div is inside view port, and return n\n * @returns \\{ translateX, translateY \\} Amount to move on X and Y axis\n */\nexport const chkPosition = (\n divRef: RefObject<HTMLDivElement>,\n): { translateX: number; translateY: number } => {\n if (!divRef.current) {\n return { translateX: 0, translateY: 0 };\n } else {\n const innerBounce = 16;\n const posn = divRef.current.getBoundingClientRect();\n let translateX = 0;\n if (posn.left < innerBounce) {\n translateX = -posn.left + innerBounce;\n } else if (posn.right > window.innerWidth) {\n translateX = Math.max(-posn.left + innerBounce, window.innerWidth - posn.right - innerBounce);\n }\n let translateY = 0;\n if (posn.top < innerBounce) {\n translateY = -posn.top + innerBounce;\n } else if (posn.bottom > window.innerHeight) {\n translateY = Math.max(\n -posn.top + innerBounce,\n window.innerHeight - posn.bottom - innerBounce,\n );\n }\n return { translateX, translateY };\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.1.5",
3
+ "version": "1.2.0",
4
4
  "description": "REACT Typescript Context menu component",
5
5
  "author": "Paul Thomas <@PaulDThomas>",
6
6
  "private": false,