UNPKG

gemma-menu

Version:

A pie/radial menu component for React

76 lines (66 loc) 6.57 kB
import React, { useState } from 'react'; function styleInject(css, ref) { if ( ref === void 0 ) ref = {}; var insertAt = ref.insertAt; if (!css || typeof document === 'undefined') { return; } var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; if (insertAt === 'top') { if (head.firstChild) { head.insertBefore(style, head.firstChild); } else { head.appendChild(style); } } else { head.appendChild(style); } if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } } var css_248z = "[data-pie-menu] {\n position: fixed;\n left: var(--pie-x, 0);\n top: var(--pie-y, 0);\n margin: 0;\n -webkit-font-smoothing: antialiased;\n box-sizing: border-box;\n pointer-events: auto;\n width: var(--radius-outer, 300px);\n height: var(--radius-outer, 300px);\n border-radius: 100%;\n z-index: 5;\n touch-action: none;\n user-select: none;\n opacity: 1;\n transform: translate(-50%, -50%);\n animation: appear 250ms both;\n box-shadow: 1px 0.9px 2.3px -3px rgba(20, 10, 0, 0.02),\n 2.4px 2.2px 5.5px -3px rgba(20, 10, 0, 0.025),\n 4.5px 4.1px 10.4px -3px rgba(20, 10, 0, 0.03),\n 8px 7.4px 18.5px -3px rgba(20, 10, 0, 0.035),\n 15px 13.8px 34.7px -3px rgba(20, 0, 10, 0.04),\n 36px 33px 83px -3px rgba(20, 10, 0, 0.1);\n}\n\n[data-pie-menu] > ul {\n pointer-events: auto;\n -webkit-font-smoothing: antialiased;\n padding: 0;\n list-style: none;\n margin: 0;\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n border-radius: inherit;\n overflow: hidden;\n position: relative;\n user-select: none;\n}\n\n[data-pie-kind='bubble'] {\n box-shadow: none;\n}\n[data-pie-kind='bubble'] [data-pie-item-content] {\n transition: 0.3s;\n}\n\n[data-pie-kind='bubble'] [data-pie-item] {\n background: none !important;\n}\n\n[data-pie-kind='bubble'] [data-pie-item-active] > * > * {\n transition: 250ms;\n}\n\n[data-pie-kind='bubble'] [data-pie-item-active]:hover > * > * {\n scale: 1.2;\n}\n\n[data-pie-label] {\n opacity: 1;\n font-weight: bold;\n position: absolute;\n height: var(--radius-inner, 30%);\n width: var(--radius-inner, 30%);\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n border-radius: inherit;\n background-color: white;\n z-index: 10;\n pointer-events: none;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);\n}\n\n[data-pie-item] {\n --pie-item-rotation: calc(var(--pie-item-angle) * var(--pie-item-index));\n --pie-item-skew: calc(90deg - var(--pie-item-angle));\n transform: rotate(var(--pie-item-rotation)) skew(var(--pie-item-skew));\n pointer-events: auto;\n list-style: none;\n user-select: none;\n position: absolute;\n bottom: 50%;\n right: 50%;\n width: 100%;\n height: 100%;\n transform-origin: 100% 100%;\n overflow: hidden;\n transition: background 250ms ease 0s;\n background-color: var(--bg-color);\n}\n\n[data-pie-item-content] {\n position: absolute;\n height: var(--pie-item-length);\n bottom: 0px;\n right: 0px;\n display: flex;\n align-items: center;\n justify-content: center;\n transform-origin: bottom right;\n transform: skew(calc(var(--pie-item-skew) * -1))\n rotate(calc(-90deg + var(--pie-item-angle) / 2))\n translate(50%, calc(var(--pie-item-offset) * -1));\n}\n\n[data-pie-item-content] > * {\n position: absolute;\n transform: rotate(calc(var(--pie-item-rotation) * -1))\n rotate(calc(90deg + var(--pie-item-angle) / 2 * -1));\n}\n\n[data-pie-item-active='true'] {\n background-color: var(--active-color) !important;\n}\n\n@keyframes appear {\n from {\n opacity: 0;\n transform: translate(-50%, -50%) scale(0.8);\n }\n to {\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n }\n}\n"; styleInject(css_248z); const Menu = (props) => { var _a; const { isOpen = false, children, position, kind = 'wheel', outerRadius = 300, innerRadius = 100, backgroundColor, activeColor } = props; const [activeItem, setActiveItem] = useState(null); const angle = 360 / children.length; const handleSetActive = (e) => { const target = e.target; if (target.hasAttribute('data-pie-item')) { const index = parseInt(target.getAttribute('data-pie-item-index') || '0'); setActiveItem(index); } }; return (React.createElement(React.Fragment, null, isOpen && (React.createElement("div", { "data-pie-menu": true, "data-pie-kind": kind, style: { '--pie-x': (position === null || position === void 0 ? void 0 : position.x) + 'px', '--pie-y': (position === null || position === void 0 ? void 0 : position.y) + 'px', '--radius-outer': outerRadius + 'px' } }, React.createElement("div", { "data-pie-label": true, style: { '--radius-inner': innerRadius + 'px' } }, activeItem !== null && ((_a = children[activeItem]) === null || _a === void 0 ? void 0 : _a.props.label)), React.createElement("ul", { onMouseMove: (e) => handleSetActive(e), role: "menu", "aria-label": "radial menu" }, children === null || children === void 0 ? void 0 : children.map((child, index) => React.cloneElement(child, { index, angle, isActive: index === activeItem, length: (outerRadius - innerRadius) / 2, offset: innerRadius / 2, backgroundColor: backgroundColor || child.props.backgroundColor || '#fafafa', activeColor: activeColor || child.props.activeColor || '#efefef' }))))))); }; const MenuItem = (props) => { const { children, label, action, close, index, isActive, angle, length, offset, backgroundColor, activeColor } = props; return (React.createElement("li", { "data-pie-item": true, "data-pie-item-index": index, "data-pie-item-active": isActive, style: { '--pie-item-index': index, '--pie-item-angle': angle + 'deg', '--pie-item-length': length + 'px', '--pie-item-offset': offset + 'px', '--bg-color': backgroundColor, '--active-color': activeColor }, role: "menuitem", "aria-label": label, onMouseEnter: action, onMouseUp: close, onClick: close, tabIndex: index !== undefined ? index + 1 : undefined }, React.createElement("div", { "data-pie-item-content": true }, children))); }; export { Menu, MenuItem };