only show hint when a new node is created

This commit is contained in:
Ryan Di 2025-03-19 20:00:19 +11:00
parent 56a0b33101
commit d0274ad5d3
4 changed files with 49 additions and 85 deletions

View file

@ -121,7 +121,6 @@ export const getDefaultAppState = (): Omit<
isCropping: false, isCropping: false,
croppingElementId: null, croppingElementId: null,
searchMatches: [], searchMatches: [],
showShapeSwitchPanel: false,
}; };
}; };
@ -246,7 +245,6 @@ const APP_STATE_STORAGE_CONF = (<
isCropping: { browser: false, export: false, server: false }, isCropping: { browser: false, export: false, server: false },
croppingElementId: { browser: false, export: false, server: false }, croppingElementId: { browser: false, export: false, server: false },
searchMatches: { browser: false, export: false, server: false }, searchMatches: { browser: false, export: false, server: false },
showShapeSwitchPanel: { browser: false, export: false, server: false },
}); });
const _clearAppStateForStorage = < const _clearAppStateForStorage = <

View file

@ -391,7 +391,7 @@ import {
getMinTextElementWidth, getMinTextElementWidth,
} from "../element/textMeasurements"; } from "../element/textMeasurements";
import ShapeSwitch from "./ShapeSwitch"; import ShapeSwitch, { shapeSwitchAtom } from "./ShapeSwitch";
import { activeConfirmDialogAtom } from "./ActiveConfirmDialog"; import { activeConfirmDialogAtom } from "./ActiveConfirmDialog";
import BraveMeasureTextError from "./BraveMeasureTextError"; import BraveMeasureTextError from "./BraveMeasureTextError";
@ -4113,24 +4113,11 @@ class App extends React.Component<AppProps, AppState> {
selectedElements.length === 1 && selectedElements.length === 1 &&
(isGenericSwitchable || isLinearSwitchable) (isGenericSwitchable || isLinearSwitchable)
) { ) {
if (this.state.showShapeSwitchPanel && event.key === KEYS.ESCAPE) { if (event.key === KEYS.ESCAPE) {
this.setState({ editorJotaiStore.set(shapeSwitchAtom, null);
showShapeSwitchPanel: false, } else if (event.key === KEYS.SLASH || event.key === KEYS.TAB) {
}); editorJotaiStore.set(shapeSwitchAtom, "panel");
return;
}
if (event.key === KEYS.SLASH || event.key === KEYS.TAB) {
if (!this.state.showShapeSwitchPanel) {
flushSync(() =>
this.setState({
showShapeSwitchPanel: true,
}),
);
}
if (this.state.showShapeSwitchPanel) {
if (isGenericSwitchable) { if (isGenericSwitchable) {
const index = ["rectangle", "diamond", "ellipse"].indexOf( const index = ["rectangle", "diamond", "ellipse"].indexOf(
selectedElements[0].type, selectedElements[0].type,
@ -4140,20 +4127,11 @@ class App extends React.Component<AppProps, AppState> {
] as ToolType; ] as ToolType;
this.setActiveTool({ type: nextType }); this.setActiveTool({ type: nextType });
} else if (isLinearSwitchable) { } else if (isLinearSwitchable) {
const index = ["arrow", "line"].indexOf( const index = ["arrow", "line"].indexOf(selectedElements[0].type);
selectedElements[0].type,
);
const nextType = ["arrow", "line"][(index + 1) % 2] as ToolType; const nextType = ["arrow", "line"][(index + 1) % 2] as ToolType;
this.setActiveTool({ type: nextType }); this.setActiveTool({ type: nextType });
} }
} }
return;
}
this.setState({
showShapeSwitchPanel: false,
});
} }
if ( if (
@ -4717,6 +4695,8 @@ class App extends React.Component<AppProps, AppState> {
canvasOffsets: this.getEditorUIOffsets(), canvasOffsets: this.getEditorUIOffsets(),
}); });
} }
editorJotaiStore.set(shapeSwitchAtom, "hint");
} }
this.flowChartCreator.clear(); this.flowChartCreator.clear();
@ -8985,7 +8965,6 @@ class App extends React.Component<AppProps, AppState> {
cursorButton: "up", cursorButton: "up",
snapLines: updateStable(prevState.snapLines, []), snapLines: updateStable(prevState.snapLines, []),
originSnapOffset: null, originSnapOffset: null,
showShapeSwitchPanel: false,
})); }));
this.lastPointerMoveCoords = null; this.lastPointerMoveCoords = null;

View file

@ -4,16 +4,13 @@ import clsx from "clsx";
import { pointFrom, pointRotateRads } from "@excalidraw/math"; import { pointFrom, pointRotateRads } from "@excalidraw/math";
import { editorJotaiStore, atom } from "../editor-jotai";
import { getElementAbsoluteCoords } from "../element"; import { getElementAbsoluteCoords } from "../element";
import { sceneCoordsToViewportCoords } from "../utils"; import { sceneCoordsToViewportCoords } from "../utils";
import { getSelectedElements } from "../scene"; import { getSelectedElements } from "../scene";
import { trackEvent } from "../analytics"; import { trackEvent } from "../analytics";
import { import { isArrowElement, isLinearElement } from "../element/typeChecks";
isArrowElement,
isGenericSwitchableElement,
isLinearElement,
isLinearSwitchableElement,
} from "../element/typeChecks";
import { t } from "../i18n"; import { t } from "../i18n";
import "./ShapeSwitch.scss"; import "./ShapeSwitch.scss";
@ -34,48 +31,29 @@ import type { ToolType } from "../types";
const GAP_HORIZONTAL = 8; const GAP_HORIZONTAL = 8;
const GAP_VERTICAL = 10; const GAP_VERTICAL = 10;
export const shapeSwitchAtom = atom<"hint" | "panel" | null>(null);
const ShapeSwitch = ({ app }: { app: App }) => { const ShapeSwitch = ({ app }: { app: App }) => {
const shapeSwitchAtomValue = editorJotaiStore.get(shapeSwitchAtom);
if (!shapeSwitchAtomValue) {
return null;
}
const selectedElements = getSelectedElements( const selectedElements = getSelectedElements(
app.scene.getNonDeletedElementsMap(), app.scene.getNonDeletedElementsMap(),
app.state, app.state,
); );
const firstElement = selectedElements[0]; const firstElement = selectedElements[0];
useEffect(() => {
return app.setState({ showShapeSwitchPanel: false });
}, [app]);
const isGeneric = firstElement && isGenericSwitchableElement(firstElement);
const isLinear = firstElement && isLinearSwitchableElement(firstElement);
const isGenericInChart =
isGeneric &&
app.scene
.getNonDeletedElements()
.some(
(el) =>
el.type === "arrow" &&
(el.startBinding?.elementId === firstElement.id ||
el.endBinding?.elementId === firstElement.id),
);
const isLinearInChart =
isLinear &&
isArrowElement(firstElement) &&
(firstElement.startBinding || firstElement.endBinding);
if (firstElement && selectedElements.length === 1) { if (firstElement && selectedElements.length === 1) {
if (isGeneric) { switch (shapeSwitchAtomValue) {
return app.state.showShapeSwitchPanel ? ( case "hint":
<Panel app={app} element={firstElement} /> return <Hint app={app} element={firstElement} />;
) : isGenericInChart ? ( case "panel":
<Hint app={app} element={firstElement} /> return <Panel app={app} element={firstElement} />;
) : null; default:
} return null;
if (isLinear) {
return app.state.showShapeSwitchPanel ? (
<Panel app={app} element={firstElement} />
) : isLinearInChart ? (
<Hint app={app} element={firstElement} />
) : null;
} }
} }
@ -109,9 +87,14 @@ const Hint = ({ app, element }: { app: App; element: ExcalidrawElement }) => {
hintRef.current?.classList.remove("animation"); hintRef.current?.classList.remove("animation");
}; };
if (hintRef.current) { const hint = hintRef.current;
hintRef.current.addEventListener("animationend", listener);
if (hint) {
hint.addEventListener("animationend", listener);
editorJotaiStore.set(shapeSwitchAtom, null);
} }
return () => hint?.removeEventListener("animationend", listener);
}, [element.id]); }, [element.id]);
return ( return (
@ -171,6 +154,12 @@ const Panel = ({ app, element }: { app: App; element: ExcalidrawElement }) => {
["ellipse", "4", EllipseIcon], ["ellipse", "4", EllipseIcon],
]; ];
useEffect(() => {
return () => {
editorJotaiStore.set(shapeSwitchAtom, null);
};
}, []);
return ( return (
<div <div
style={{ style={{

View file

@ -410,8 +410,6 @@ export interface AppState {
croppingElementId: ExcalidrawElement["id"] | null; croppingElementId: ExcalidrawElement["id"] | null;
searchMatches: readonly SearchMatch[]; searchMatches: readonly SearchMatch[];
showShapeSwitchPanel: boolean;
} }
type SearchMatch = { type SearchMatch = {