Skip to content

Commit

Permalink
[4285] Fix direct edit when the palette is closed
Browse files Browse the repository at this point in the history
Bug: #4285
Signed-off-by: Michaël Charfadi <[email protected]>
  • Loading branch information
mcharfadi committed Dec 16, 2024
1 parent 4a63ce3 commit 0d1515d
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,26 @@ export const useDiagramDelete = (): UseDiagramDeleteValue => {
}, [deleteElementsData, deleteElementsError]);

const onDelete = useCallback((event: React.KeyboardEvent<Element>) => {
const { key } = event;
/*If a modifier key is hit alone, do nothing*/
const { key, target } = event;
const isTextField = event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement;
if ((event.altKey && key === 'Alt') || (event.shiftKey && key === 'Shift') || isTextField) {
console.log('onDelete');
/*If a modifier key is hit alone, do nothing*/
if ((event.altKey && key === 'Alt') || (event.shiftKey && key === 'Shift') || isTextField || readOnly) {
return;
}
/*If the palette is opened, do nothing*/
if (
key === 'Delete' &&
!(
(target as HTMLElement).classList.contains('react-flow__node') ||
(target as HTMLElement).classList.contains('react-flow__edge')
)
) {
return;
}
event.preventDefault();

if (key === 'Delete' && editingContextId && diagramId && !readOnly) {
console.log('onDelete2');
const nodeToDeleteIds: string[] = getNodes()
.filter((node) => node.selected)
.map((node) => node.id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,30 @@ export const useDiagramDirectEdit = (): UseDiagramDirectEditValue => {

const onDirectEdit = useCallback(
(event: React.KeyboardEvent<Element>) => {
const { key } = event;
const { key, target } = event;
/*If a modifier key is hit alone, do nothing*/
const isTextField = event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement;
if ((event.altKey && key === 'Alt') || (event.shiftKey && key === 'Shift') || isTextField || readOnly) {
if ((event.altKey && key === 'Alt') || (event.shiftKey && key === 'Shift') || readOnly) {
return;
}

/*When the palette is opened, allow direct edit only with F2 so we can type in the palette search field*/
if (
key !== 'F2' &&
!(
(target as HTMLElement).classList.contains('react-flow__node') ||
(target as HTMLElement).classList.contains('react-flow__edge')
)
) {
return;
}

event.preventDefault();
const validFirstInputChar =
!event.metaKey && !event.ctrlKey && key.length === 1 && directEditActivationValidCharacters.test(key);

let currentlyEditedLabelId: string | undefined | null;
let isLabelEditable: boolean = false;
const nodeData: NodeData | undefined = getNodes().find((node) => node.selected)?.data;

if (nodeData) {
if (nodeData.insideLabel) {
currentlyEditedLabelId = nodeData.insideLabel.id;
Expand All @@ -51,6 +61,7 @@ export const useDiagramDirectEdit = (): UseDiagramDirectEditValue => {
}
isLabelEditable = nodeData.labelEditable;
}

if (!currentlyEditedLabelId) {
currentlyEditedLabelId = getEdges().find((edge) => edge.selected)?.data?.label?.id;
isLabelEditable = getEdges().find((edge) => edge.selected)?.data?.centerLabelEditable || false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,14 @@ export const MultiLabelEdge = memo(
markerEnd={selected ? `${markerEnd?.slice(0, markerEnd.length - 2)}--selected')` : markerEnd}
markerStart={selected ? `${markerStart?.slice(0, markerStart.length - 2)}--selected')` : markerStart}
/>
{selected ? (
<DiagramElementPalette
diagramElementId={id}
targetObjectId={data?.targetObjectId ?? ''}
labelId={label ? label.id : null}
/>
) : null}
<EdgeLabelRenderer>
{selected ? (
<DiagramElementPalette
diagramElementId={id}
targetObjectId={data?.targetObjectId ?? ''}
labelId={label ? label.id : null}
/>
) : null}
{beginLabel && (
<div style={labelContainerStyle(`${sourceLabelTranslation} translate(${sourceX}px,${sourceY}px)`)}>
<Label diagramElementId={id} label={beginLabel} faded={!!faded} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,9 @@ import { useDiagramElementPalette } from './useDiagramElementPalette';
export const DiagramElementPalette = memo(
({ diagramElementId, targetObjectId, labelId }: DiagramElementPaletteProps) => {
const { readOnly } = useContext<DiagramContextValue>(DiagramContext);
const { isOpened, x, y, hideDiagramElementPalette } = useDiagramElementPalette();
const { isOpened, x, y } = useDiagramElementPalette();
const { setCurrentlyEditedLabelId, currentlyEditedLabelId } = useDiagramDirectEdit();

//If the Palette search field has the focus on, the useKeyPress from reactflow ignore the key pressed event.
const onEscape = () => {
hideDiagramElementPalette();
};

if (readOnly) {
return null;
}
Expand All @@ -49,7 +44,6 @@ export const DiagramElementPalette = memo(
diagramElementId={diagramElementId}
targetObjectId={targetObjectId}
onDirectEditClick={handleDirectEditClick}
onEscape={onEscape}
/>
</PalettePortal>
) : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
* Obeo - initial API and implementation
*******************************************************************************/

import { useKeyPress } from '@xyflow/react';
import { memo, useContext, useEffect } from 'react';
import { memo, useContext } from 'react';
import { DiagramContext } from '../../contexts/DiagramContext';
import { DiagramContextValue } from '../../contexts/DiagramContext.types';
import { DiagramPaletteProps } from './DiagramPalette.types';
Expand All @@ -22,24 +21,12 @@ import { useDiagramPalette } from './useDiagramPalette';

export const DiagramPalette = memo(({ diagramElementId, targetObjectId }: DiagramPaletteProps) => {
const { readOnly } = useContext<DiagramContextValue>(DiagramContext);
const { isOpened, x, y, hideDiagramPalette } = useDiagramPalette();

const escapePressed = useKeyPress('Escape');
useEffect(() => {
if (escapePressed) {
hideDiagramPalette();
}
}, [escapePressed, hideDiagramPalette]);
const { isOpened, x, y } = useDiagramPalette();

if (readOnly) {
return null;
}

//If the Palette search field has the focus on, the useKeyPress from reactflow ignore the key pressed event.
const onEscape = () => {
hideDiagramPalette();
};

return isOpened && x && y ? (
<PalettePortal>
<Palette
Expand All @@ -48,7 +35,6 @@ export const DiagramPalette = memo(({ diagramElementId, targetObjectId }: Diagra
diagramElementId={diagramElementId}
targetObjectId={targetObjectId}
onDirectEditClick={() => {}}
onEscape={onEscape}
/>
</PalettePortal>
) : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ import Box from '@mui/material/Box';
import Divider from '@mui/material/Divider';
import Paper from '@mui/material/Paper';
import { Edge, Node, useStoreApi, useViewport, XYPosition } from '@xyflow/react';
import React, { useEffect, useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import Draggable, { DraggableData } from 'react-draggable';
import { makeStyles } from 'tss-react/mui';
import { EdgeData, NodeData } from '../DiagramRenderer.types';
import { useGroupPalette } from './group-tool/useGroupPalette';
import {
GQLPalette,
GQLPaletteDivider,
Expand All @@ -34,6 +35,8 @@ import { PaletteQuickAccessToolBar } from './quick-access-tool/PaletteQuickAcces
import { PaletteSearchField } from './search/PaletteSearchField';
import { PaletteSearchResult } from './search/PaletteSearchResult';
import { PaletteToolList } from './tool-list/PaletteToolList';
import { useDiagramElementPalette } from './useDiagramElementPalette';
import { useDiagramPalette } from './useDiagramPalette';
import { usePalette } from './usePalette';

const usePaletteStyle = makeStyles<PaletteStyleProps>()((theme, props) => ({
Expand Down Expand Up @@ -104,7 +107,6 @@ export const Palette = ({
diagramElementId,
targetObjectId,
onDirectEditClick,
onEscape,
}: PaletteProps) => {
const { domNode, nodeLookup, edgeLookup } = useStoreApi<Node<NodeData>, Edge<EdgeData>>().getState();
const { x: viewportWidth, y: viewportHeight } = computeDraggableBounds(domNode?.getBoundingClientRect());
Expand Down Expand Up @@ -134,6 +136,41 @@ export const Palette = ({

const shouldRender = palette && (getPaletteToolCount(palette) > 0 || !!diagramElement);

const { hideDiagramPalette } = useDiagramPalette();
const { hideDiagramElementPalette } = useDiagramElementPalette();
const { hideGroupPalette } = useGroupPalette();

const closeAllPalettes = useCallback(() => {
hideDiagramPalette();
hideDiagramElementPalette();
hideGroupPalette();
}, [hideDiagramPalette, hideDiagramElementPalette, hideGroupPalette]);

const store = useStoreApi<Node<NodeData>, Edge<EdgeData>>();

const onKeyDown = useCallback((event: React.KeyboardEvent<Element>) => {
const { key } = event;
if (key === 'Escape') {
// Stop propagating the event in order to keep the node/edge selected
event.stopPropagation();

closeAllPalettes();

//Set the focus from the palette to the node/edge
const selectedNode = store.getState().nodes.filter((node) => node.selected);
const selectedEdges = store.getState().edges.filter((edge) => edge.selected);
if (selectedNode.length + selectedEdges.length === 1) {
const selectedElement = selectedNode[0] || selectedEdges[0];
if (selectedElement) {
let domElement = document.querySelector(`[data-id='${selectedElement.id}']`);
if (domElement) {
(domElement as HTMLElement).focus();
}
}
}
}
}, []);

if (!shouldRender) {
return null;
}
Expand Down Expand Up @@ -166,16 +203,13 @@ export const Palette = ({
className={classes.palette}
data-testid="Palette"
elevation={3}
onKeyDown={onKeyDown}
onClick={(event) => event.stopPropagation()}>
<Box id="tool-palette-header" className={classes.paletteHeader}>
<DragIndicatorIcon />
</Box>
<Divider />
<PaletteSearchField
onValueChanged={onSearchFieldValueChanged}
onEscape={onEscape}
onDirectEditClick={onDirectEditClick}
/>
<PaletteSearchField onValueChanged={onSearchFieldValueChanged} />
<PaletteQuickAccessToolBar
diagramElementId={diagramElementId}
onToolClick={handleToolClick}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import InputAdornment from '@mui/material/InputAdornment';
import TextField from '@mui/material/TextField';
import { useState } from 'react';
import { PaletteSearchFieldProps, PaletteSearchFieldState } from './PaletteSearchField.types';
export const PaletteSearchField = ({ onValueChanged, onEscape, onDirectEditClick }: PaletteSearchFieldProps) => {
export const PaletteSearchField = ({ onValueChanged }: PaletteSearchFieldProps) => {
const [state, setState] = useState<PaletteSearchFieldState>({ value: '' });

const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
Expand All @@ -32,21 +32,11 @@ export const PaletteSearchField = ({ onValueChanged, onEscape, onDirectEditClick
onValueChanged('');
};

const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>): void => {
const { key } = event;
if (key === 'Escape' && onEscape) {
onEscape();
} else if (key === 'F2') {
onDirectEditClick();
}
};

return (
<TextField
autoFocus={true}
value={state.value}
size="small"
onKeyDown={handleKeyDown}
onClick={(event) => event.stopPropagation()}
placeholder="Search Tool"
InputProps={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@

export interface PaletteSearchFieldProps {
onValueChanged: (newValue: string) => void;
onEscape?: () => void;
onDirectEditClick: () => void;
}

export interface PaletteSearchFieldState {
Expand Down

0 comments on commit 0d1515d

Please sign in to comment.