B: Fix contextmenu animations

This commit is contained in:
Ivan 2025-02-05 12:03:54 +03:00
parent 507faf4689
commit f1bdb70a76
2 changed files with 31 additions and 34 deletions

View File

@ -1,6 +1,6 @@
'use client'; 'use client';
import { useEffect, useRef, useState } from 'react'; import { useRef } from 'react';
import { useMutatingOss } from '@/backend/oss/useMutatingOss'; import { useMutatingOss } from '@/backend/oss/useMutatingOss';
import { import {
@ -22,12 +22,13 @@ import { prepareTooltip } from '@/utils/labels';
import { useOssEdit } from '../OssEditContext'; import { useOssEdit } from '../OssEditContext';
export interface ContextMenuData { export interface ContextMenuData {
operation: IOperation; operation?: IOperation;
cursorX: number; cursorX: number;
cursorY: number; cursorY: number;
} }
interface NodeContextMenuProps extends ContextMenuData { interface NodeContextMenuProps extends ContextMenuData {
isOpen: boolean;
onHide: () => void; onHide: () => void;
onDelete: (target: OperationID) => void; onDelete: (target: OperationID) => void;
onCreateInput: (target: OperationID) => void; onCreateInput: (target: OperationID) => void;
@ -38,6 +39,7 @@ interface NodeContextMenuProps extends ContextMenuData {
} }
function NodeContextMenu({ function NodeContextMenu({
isOpen,
operation, operation,
cursorX, cursorX,
cursorY, cursorY,
@ -52,10 +54,9 @@ function NodeContextMenu({
const controller = useOssEdit(); const controller = useOssEdit();
const isProcessing = useMutatingOss(); const isProcessing = useMutatingOss();
const [isOpen, setIsOpen] = useState(false);
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
const readyForSynthesis = (() => { const readyForSynthesis = (() => {
if (operation.operation_type !== OperationType.SYNTHESIS) { if (operation?.operation_type !== OperationType.SYNTHESIS) {
return false; return false;
} }
if (operation.result) { if (operation.result) {
@ -75,47 +76,40 @@ function NodeContextMenu({
return true; return true;
})(); })();
function handleHide() { useClickedOutside(isOpen, ref, onHide);
setIsOpen(false);
onHide();
}
useClickedOutside(isOpen, ref, handleHide);
useEffect(() => setIsOpen(true), []);
function handleOpenSchema() { function handleOpenSchema() {
controller.navigateOperationSchema(operation.id); if (operation) controller.navigateOperationSchema(operation.id);
} }
function handleEditSchema() { function handleEditSchema() {
handleHide(); onHide();
onEditSchema(operation.id); if (operation) onEditSchema(operation.id);
} }
function handleEditOperation() { function handleEditOperation() {
handleHide(); onHide();
onEditOperation(operation.id); if (operation) onEditOperation(operation.id);
} }
function handleDeleteOperation() { function handleDeleteOperation() {
handleHide(); onHide();
onDelete(operation.id); if (operation) onDelete(operation.id);
} }
function handleCreateSchema() { function handleCreateSchema() {
handleHide(); onHide();
onCreateInput(operation.id); if (operation) onCreateInput(operation.id);
} }
function handleRunSynthesis() { function handleRunSynthesis() {
handleHide(); onHide();
onExecuteOperation(operation.id); if (operation) onExecuteOperation(operation.id);
} }
function handleRelocateConstituents() { function handleRelocateConstituents() {
handleHide(); onHide();
onRelocateConstituents(operation.id); if (operation) onRelocateConstituents(operation.id);
} }
return ( return (
@ -133,7 +127,7 @@ function NodeContextMenu({
onClick={handleEditOperation} onClick={handleEditOperation}
/> />
{operation.result ? ( {operation?.result ? (
<DropdownButton <DropdownButton
text='Открыть схему' text='Открыть схему'
titleHtml={prepareTooltip('Открыть привязанную КС', 'Двойной клик')} titleHtml={prepareTooltip('Открыть привязанную КС', 'Двойной клик')}
@ -142,7 +136,7 @@ function NodeContextMenu({
onClick={handleOpenSchema} onClick={handleOpenSchema}
/> />
) : null} ) : null}
{controller.isMutable && !operation.result && operation.operation_type === OperationType.INPUT ? ( {controller.isMutable && !operation?.result && operation?.operation_type === OperationType.INPUT ? (
<DropdownButton <DropdownButton
text='Создать схему' text='Создать схему'
title='Создать пустую схему для загрузки' title='Создать пустую схему для загрузки'
@ -151,16 +145,16 @@ function NodeContextMenu({
onClick={handleCreateSchema} onClick={handleCreateSchema}
/> />
) : null} ) : null}
{controller.isMutable && operation.operation_type === OperationType.INPUT ? ( {controller.isMutable && operation?.operation_type === OperationType.INPUT ? (
<DropdownButton <DropdownButton
text={!operation.result ? 'Загрузить схему' : 'Изменить схему'} text={!operation?.result ? 'Загрузить схему' : 'Изменить схему'}
title='Выбрать схему для загрузки' title='Выбрать схему для загрузки'
icon={<IconConnect size='1rem' className='icon-primary' />} icon={<IconConnect size='1rem' className='icon-primary' />}
disabled={isProcessing} disabled={isProcessing}
onClick={handleEditSchema} onClick={handleEditSchema}
/> />
) : null} ) : null}
{controller.isMutable && !operation.result && operation.operation_type === OperationType.SYNTHESIS ? ( {controller.isMutable && !operation?.result && operation?.operation_type === OperationType.SYNTHESIS ? (
<DropdownButton <DropdownButton
text='Активировать синтез' text='Активировать синтез'
titleHtml={ titleHtml={
@ -174,7 +168,7 @@ function NodeContextMenu({
/> />
) : null} ) : null}
{controller.isMutable && operation.result ? ( {controller.isMutable && operation?.result ? (
<DropdownButton <DropdownButton
text='Конституенты' text='Конституенты'
titleHtml='Перенос конституент</br>между схемами' titleHtml='Перенос конституент</br>между схемами'
@ -187,7 +181,7 @@ function NodeContextMenu({
<DropdownButton <DropdownButton
text='Удалить операцию' text='Удалить операцию'
icon={<IconDestroy size='1rem' className='icon-red' />} icon={<IconDestroy size='1rem' className='icon-red' />}
disabled={!controller.isMutable || isProcessing || !controller.canDelete(operation.id)} disabled={!controller.isMutable || isProcessing || !operation || !controller.canDelete(operation.id)}
onClick={handleDeleteOperation} onClick={handleDeleteOperation}
/> />
</Dropdown> </Dropdown>

View File

@ -63,7 +63,8 @@ function OssFlow() {
const [nodes, setNodes, onNodesChange] = useNodesState([]); const [nodes, setNodes, onNodesChange] = useNodesState([]);
const [edges, setEdges, onEdgesChange] = useEdgesState([]); const [edges, setEdges, onEdgesChange] = useEdgesState([]);
const [toggleReset, setToggleReset] = useState(false); const [toggleReset, setToggleReset] = useState(false);
const [menuProps, setMenuProps] = useState<ContextMenuData | undefined>(undefined); const [menuProps, setMenuProps] = useState<ContextMenuData>({ operation: undefined, cursorX: 0, cursorY: 0 });
const [isContextMenuOpen, setIsContextMenuOpen] = useState(false);
function onSelectionChange({ nodes }: { nodes: Node[] }) { function onSelectionChange({ nodes }: { nodes: Node[] }) {
const ids = nodes.map(node => Number(node.id)); const ids = nodes.map(node => Number(node.id));
@ -243,12 +244,13 @@ function OssFlow() {
cursorX: event.clientX, cursorX: event.clientX,
cursorY: event.clientY cursorY: event.clientY
}); });
setIsContextMenuOpen(true);
controller.setShowTooltip(false); controller.setShowTooltip(false);
} }
function handleContextMenuHide() { function handleContextMenuHide() {
controller.setShowTooltip(true); controller.setShowTooltip(true);
setMenuProps(undefined); setIsContextMenuOpen(false);
} }
function handleCanvasClick() { function handleCanvasClick() {
@ -308,6 +310,7 @@ function OssFlow() {
</Overlay> </Overlay>
{menuProps ? ( {menuProps ? (
<NodeContextMenu <NodeContextMenu
isOpen={isContextMenuOpen}
onHide={handleContextMenuHide} onHide={handleContextMenuHide}
onDelete={handleDeleteOperation} onDelete={handleDeleteOperation}
onCreateInput={handleInputCreate} onCreateInput={handleInputCreate}