123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- import { css } from '@emotion/css';
- import React, { useCallback, useEffect, useState } from 'react';
- import { first } from 'rxjs/operators';
- import { ContextMenu, MenuItem } from '@grafana/ui';
- import { Scene } from '../../../features/canvas/runtime/scene';
- import { LayerActionID } from './types';
- type Props = {
- scene: Scene;
- };
- type AnchorPoint = {
- x: number;
- y: number;
- };
- export const CanvasContextMenu = ({ scene }: Props) => {
- const [isMenuVisible, setIsMenuVisible] = useState<boolean>(false);
- const [anchorPoint, setAnchorPoint] = useState<AnchorPoint>({ x: 0, y: 0 });
- const styles = getStyles();
- const selectedElements = scene.selecto?.getSelectedTargets();
- const handleContextMenu = useCallback(
- (event) => {
- event.preventDefault();
- if (event.currentTarget) {
- scene.select({ targets: [event.currentTarget as HTMLElement | SVGElement] });
- }
- setAnchorPoint({ x: event.pageX, y: event.pageY });
- setIsMenuVisible(true);
- },
- [scene]
- );
- useEffect(() => {
- if (selectedElements && selectedElements.length === 1) {
- const element = selectedElements[0];
- element.addEventListener('contextmenu', handleContextMenu);
- }
- }, [selectedElements, handleContextMenu]);
- if (!selectedElements) {
- return <></>;
- }
- const closeContextMenu = () => {
- setIsMenuVisible(false);
- };
- const renderMenuItems = () => {
- return (
- <>
- <MenuItem
- label="Delete"
- onClick={() => {
- contextMenuAction(LayerActionID.Delete);
- closeContextMenu();
- }}
- className={styles.menuItem}
- />
- <MenuItem
- label="Duplicate"
- onClick={() => {
- contextMenuAction(LayerActionID.Duplicate);
- closeContextMenu();
- }}
- className={styles.menuItem}
- />
- <MenuItem
- label="Bring to front"
- onClick={() => {
- contextMenuAction(LayerActionID.MoveTop);
- closeContextMenu();
- }}
- className={styles.menuItem}
- />
- <MenuItem
- label="Send to back"
- onClick={() => {
- contextMenuAction(LayerActionID.MoveBottom);
- closeContextMenu();
- }}
- className={styles.menuItem}
- />
- </>
- );
- };
- const contextMenuAction = (actionType: string) => {
- scene.selection.pipe(first()).subscribe((currentSelectedElements) => {
- const currentSelectedElement = currentSelectedElements[0];
- const currentLayer = currentSelectedElement.parent!;
- switch (actionType) {
- case LayerActionID.Delete:
- currentLayer.doAction(LayerActionID.Delete, currentSelectedElement);
- break;
- case LayerActionID.Duplicate:
- currentLayer.doAction(LayerActionID.Duplicate, currentSelectedElement);
- break;
- case LayerActionID.MoveTop:
- currentLayer.doAction(LayerActionID.MoveTop, currentSelectedElement);
- break;
- case LayerActionID.MoveBottom:
- currentLayer.doAction(LayerActionID.MoveBottom, currentSelectedElement);
- break;
- }
- });
- };
- if (isMenuVisible) {
- return (
- <div
- onContextMenu={(event) => {
- event.preventDefault();
- closeContextMenu();
- }}
- >
- <ContextMenu
- x={anchorPoint.x}
- y={anchorPoint.y}
- onClose={closeContextMenu}
- renderMenuItems={renderMenuItems}
- focusOnOpen={false}
- />
- </div>
- );
- }
- return <></>;
- };
- const getStyles = () => ({
- menuItem: css`
- max-width: 60ch;
- overflow: hidden;
- `,
- });
|