@itwin/core-react
Version:
A react component library of iTwin.js UI general purpose components
184 lines • 7.83 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module RadialMenu
*/
import "./RadialMenu.scss";
import classnames from "classnames";
import * as React from "react";
import { Key } from "ts-key-enum";
import { Icon } from "../icons/IconComponent.js";
import { Point } from "../utils/Point.js";
import { AnnularSector, Annulus } from "./Annulus.js";
/** A context menu arranged in a radial layout.
* @public
* @deprecated in 4.14.0. Use {@link ContextMenu} or {@link https://itwinui.bentley.com/docs/dropdownmenu iTwinUI dropdown menu} instead.
*/
export class RadialMenu extends React.Component {
constructor(props) {
super(props);
this._root = null;
this._selectedButton = null;
this.state = {
sectors: [],
};
this._handleKeyUp = (event) => {
if (event.key === Key.Escape.valueOf() && this.props.onEsc)
this.props.onEsc(event);
};
this._handleClick = (event) => {
if (event.target instanceof HTMLElement &&
this._root &&
!event.target.contains(this._root) &&
this.props.onBlur)
this.props.onBlur(event);
};
/** Manually call onSelect of highlighted button. */
this.select = () => {
if (this._selectedButton)
this._selectedButton.select();
};
this._generateAnnularSectors = () => {
const n = React.Children.count(this.props.children);
const angle = (2 * Math.PI) / n;
const outer = this.props.outerRadius;
const inner = this.props.innerRadius;
const offset = -Math.PI / 8;
const annulus = new Annulus(new Point(outer + 1, outer + 1), inner + 1, outer - 1);
const sectors = [];
for (let i = 0; i < n; i++) {
sectors.push(new AnnularSector(annulus, angle * i + offset, angle * (i + 1) + offset));
}
this.setState({ sectors });
};
}
render() {
const width = 2 * (this.props.outerRadius + 1);
let x = this.props.left, y = this.props.top;
if (this.props.left &&
this.props.top &&
typeof this.props.left === "number" &&
typeof this.props.top === "number") {
x = this.props.left;
y = this.props.top;
if (x < 0)
x = 0;
if (x > window.innerWidth - width)
x = window.innerWidth - width;
if (y < 0)
y = 0;
if (y > window.innerHeight - width)
y = window.innerHeight - width;
}
const divStyle = {
left: x,
top: y,
...this.props.style,
};
return (React.createElement("div", { ref: (el) => {
this._root = el;
}, className: classnames("core-radial-menu", { opened: this.props.opened }, this.props.className), style: divStyle, "data-testid": "core-radial-menu" },
React.createElement("svg", { xmlns: "http://w3.org/2000/svg", version: "1.1", width: width, height: width, className: "core-radial-menu-container" }, React.Children.map(this.props.children, (child, index) => {
if (!child || typeof child !== "object" || !("props" in child))
return child;
const childElement = child;
return React.cloneElement(childElement, {
key: index,
ref: (el) => {
if (this.props.selected === index)
this._selectedButton = el;
},
selected: index === this.props.selected,
labelRotate: childElement.props.labelRotate || this.props.labelRotate,
annularSector: this.state.sectors[index],
});
}))));
}
componentDidMount() {
this._generateAnnularSectors();
setTimeout(() => {
window.addEventListener("keyup", this._handleKeyUp);
window.addEventListener("mouseup", this._handleClick);
});
}
componentWillUnmount() {
window.removeEventListener("keyup", this._handleKeyUp);
window.removeEventListener("mouseup", this._handleClick);
}
/** @internal */
componentDidUpdate(prevProps) {
if (prevProps.innerRadius !== this.props.innerRadius ||
prevProps.outerRadius !== this.props.outerRadius) {
this._generateAnnularSectors();
}
}
}
RadialMenu.defaultProps = {
labelRotate: false,
selected: -1,
};
/** Button for use within a [[RadialMenu]]
* @public
* @deprecated in 4.14.0. Component used in a deprecated component {@link RadialMenu}.
*/
export class RadialButton extends React.Component {
constructor(props) {
super(props);
this.state = {
hover: this.props.selected || false,
};
/** Manually call this.props.onSelect */
this.select = () => {
if (this.props.onSelect)
this.props.onSelect(undefined);
};
this._handleClick = (event) => {
if (this.props.onSelect)
this.props.onSelect(event);
};
this._handleMouseOver = (_event) => {
this.setState({ hover: true });
};
this._handleMouseOut = (_event) => {
this.setState({ hover: false });
};
}
render() {
const sector = this.props.annularSector;
let p = new Point();
let size = 0;
let t = "";
let path = "";
if (sector) {
size = sector.start.p1.getDistanceTo(sector.end.p2) * 2;
path = sector.path;
const parent = sector.parent;
const { x: cx, y: cy } = parent.center;
const r = (parent.inner.radius + parent.outer.radius) / 2;
const angle = (sector.startAngle + sector.endAngle) / 2;
p = new Point(cx + r * Math.cos(angle), cy + r * Math.sin(angle));
if (this.props.labelRotate) {
let a = (angle * 180) / Math.PI + 90;
while (a > 180)
a -= 360;
while (a < -180)
a += 360;
if (a > 90)
a -= 180;
if (a < -90)
a += 180;
t = `rotate(${a} ${p.x}, ${p.y})`;
}
}
return (React.createElement("g", { onMouseOver: this._handleMouseOver, onMouseOut: this._handleMouseOut, onClick: this._handleClick },
React.createElement("path", { className: classnames("core-radial-menu-sector", { selected: this.state.hover }, this.props.className), style: this.props.style, d: path }),
React.createElement("foreignObject", { transform: t, x: p.x - size / 2, y: p.y - 16, width: size, height: size, className: "core-radial-menu-button-svg" },
React.createElement("div", { xmlns: "http://www.w3.org/1999/xhtml", className: "core-radial-menu-button-container" },
React.createElement("div", { className: "core-radial-menu-button-icon" },
React.createElement(Icon, { iconSpec: this.props.icon })),
React.createElement("div", { className: "core-radial-menu-button-content" }, this.props.children)))));
}
}
//# sourceMappingURL=RadialMenu.js.map