UNPKG

6.59 kBJavaScriptView Raw
1/*
2 * Copyright 2016 Palantir Technologies, Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16import { __assign, __decorate, __extends, __rest } from "tslib";
17import classNames from "classnames";
18import * as React from "react";
19import * as ReactDOM from "react-dom";
20import { polyfill } from "react-lifecycles-compat";
21import { AbstractPureComponent2, Classes, Position } from "../../common";
22import { Popover } from "../popover/popover";
23var POPPER_MODIFIERS = {
24 preventOverflow: { boundariesElement: "viewport" },
25};
26var TRANSITION_DURATION = 100;
27/* istanbul ignore next */
28/** @deprecated use ContextMenu2 */
29var ContextMenu = /** @class */ (function (_super) {
30 __extends(ContextMenu, _super);
31 function ContextMenu() {
32 var _this = _super !== null && _super.apply(this, arguments) || this;
33 _this.state = {
34 isDarkTheme: false,
35 isOpen: false,
36 };
37 _this.cancelContextMenu = function (e) { return e.preventDefault(); };
38 _this.handleBackdropContextMenu = function (e) {
39 // React function to remove from the event pool, useful when using a event within a callback
40 e.persist();
41 e.preventDefault();
42 // wait for backdrop to disappear so we can find the "real" element at event coordinates.
43 // timeout duration is equivalent to transition duration so we know it's animated out.
44 _this.setTimeout(function () {
45 // retrigger context menu event at the element beneath the backdrop.
46 // if it has a `contextmenu` event handler then it'll be invoked.
47 // if it doesn't, no native menu will show (at least on OSX) :(
48 var newTarget = document.elementFromPoint(e.clientX, e.clientY);
49 var view = e.view, newEventInit = __rest(e, ["view"]);
50 newTarget === null || newTarget === void 0 ? void 0 : newTarget.dispatchEvent(new MouseEvent("contextmenu", newEventInit));
51 }, TRANSITION_DURATION);
52 };
53 _this.handlePopoverInteraction = function (nextOpenState) {
54 if (!nextOpenState) {
55 // delay the actual hiding till the event queue clears
56 // to avoid flicker of opening twice
57 _this.requestAnimationFrame(function () { return _this.hide(); });
58 }
59 };
60 return _this;
61 }
62 ContextMenu.prototype.render = function () {
63 var _a;
64 // prevent right-clicking in a context menu
65 var content = React.createElement("div", { onContextMenu: this.cancelContextMenu }, this.state.menu);
66 var popoverClassName = classNames((_a = {}, _a[Classes.DARK] = this.state.isDarkTheme, _a));
67 // HACKHACK: workaround until we have access to Popper#scheduleUpdate().
68 // https://github.com/palantir/blueprint/issues/692
69 // Generate key based on offset so a new Popover instance is created
70 // when offset changes, to force recomputing position.
71 var key = this.state.offset === undefined ? "" : this.state.offset.left + "x" + this.state.offset.top;
72 // wrap the popover in a positioned div to make sure it is properly
73 // offset on the screen.
74 /* eslint-disable deprecation/deprecation */
75 return (React.createElement("div", { className: Classes.CONTEXT_MENU_POPOVER_TARGET, style: this.state.offset },
76 React.createElement(Popover, __assign({}, this.props, { backdropProps: { onContextMenu: this.handleBackdropContextMenu }, content: content, enforceFocus: false, key: key, hasBackdrop: true, isOpen: this.state.isOpen, minimal: true, modifiers: POPPER_MODIFIERS, onInteraction: this.handlePopoverInteraction, position: Position.RIGHT_TOP, popoverClassName: popoverClassName, target: React.createElement("div", null), transitionDuration: TRANSITION_DURATION }))));
77 /* eslint-enable deprecation/deprecation */
78 };
79 ContextMenu.prototype.show = function (menu, offset, onClose, isDarkTheme) {
80 if (isDarkTheme === void 0) { isDarkTheme = false; }
81 this.setState({ isOpen: true, menu: menu, offset: offset, onClose: onClose, isDarkTheme: isDarkTheme });
82 };
83 ContextMenu.prototype.hide = function () {
84 var _a, _b;
85 (_b = (_a = this.state).onClose) === null || _b === void 0 ? void 0 : _b.call(_a);
86 this.setState({ isOpen: false, onClose: undefined });
87 };
88 ContextMenu = __decorate([
89 polyfill
90 ], ContextMenu);
91 return ContextMenu;
92}(AbstractPureComponent2));
93var contextMenuElement;
94// eslint-disable-next-line deprecation/deprecation
95var contextMenu;
96/**
97 * Show the given menu element at the given offset from the top-left corner of the viewport.
98 * The menu will appear below-right of this point and will flip to below-left if there is not enough
99 * room onscreen. The optional callback will be invoked when this menu closes.
100 */
101export function show(menu, offset, onClose, isDarkTheme) {
102 if (contextMenuElement === undefined) {
103 contextMenuElement = document.createElement("div");
104 contextMenuElement.classList.add(Classes.CONTEXT_MENU);
105 document.body.appendChild(contextMenuElement);
106 /* eslint-disable deprecation/deprecation */
107 contextMenu = ReactDOM.render(React.createElement(ContextMenu, { onClosed: remove }), contextMenuElement);
108 /* eslint-enable deprecation/deprecation */
109 }
110 contextMenu.show(menu, offset, onClose, isDarkTheme);
111}
112/** Hide the open context menu. */
113export function hide() {
114 contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.hide();
115}
116/** Return whether a context menu is currently open. */
117export function isOpen() {
118 return contextMenu != null && contextMenu.state.isOpen;
119}
120function remove() {
121 if (contextMenuElement != null) {
122 ReactDOM.unmountComponentAtNode(contextMenuElement);
123 contextMenuElement.remove();
124 contextMenuElement = undefined;
125 contextMenu = undefined;
126 }
127}
128//# sourceMappingURL=contextMenu.js.map
\No newline at end of file