refactor(react/type_widgets): extract context menu to separate file

This commit is contained in:
Elian Doran 2025-10-04 09:15:15 +03:00
parent 3256c14a20
commit d076d54170
No known key found for this signature in database
4 changed files with 88 additions and 73 deletions

View File

@ -1,17 +1,14 @@
import { useCallback, useEffect, useState } from "preact/hooks";
import { useEffect, useMemo, useState } from "preact/hooks";
import { useNoteProperty } from "../../react/hooks";
import froca from "../../../services/froca";
import contextMenu from "../../../menus/context_menu";
import { t } from "../../../services/i18n";
import appContext from "../../../components/app_context";
import dialog from "../../../services/dialog";
import server from "../../../services/server";
import { JsPlumbItem } from "./jsplumb";
import FNote from "../../../entities/fnote";
import RelationMapApi, { MapDataNoteEntry } from "./api";
import { RefObject } from "preact";
import NoteLink from "../../react/NoteLink";
import { idToNoteId, noteIdToId } from "./utils";
import { buildNoteContextMenuHandler } from "./context_menu";
const NOTE_BOX_SOURCE_CONFIG = {
filter: ".endpoint",
@ -40,48 +37,8 @@ export function NoteBox({ noteId, x, y, mapApiRef }: NoteBoxProps) {
froca.getNote(noteId).then(setNote);
}, [ noteId ]);
const contextMenuHandler = useCallback((e: MouseEvent) => {
e.preventDefault();
contextMenu.show({
x: e.pageX,
y: e.pageY,
items: [
{
title: t("relation_map.open_in_new_tab"),
uiIcon: "bx bx-empty",
handler: () => appContext.tabManager.openTabWithNoteWithHoisting(noteId)
},
{
title: t("relation_map.remove_note"),
uiIcon: "bx bx-trash",
handler: async () => {
if (!note) return;
const result = await dialog.confirmDeleteNoteBoxWithNote(note.title);
if (typeof result !== "object" || !result.confirmed) return;
mapApiRef.current?.removeItem(noteId, result.isDeleteNoteChecked);
}
},
{
title: t("relation_map.edit_title"),
uiIcon: "bx bx-pencil",
handler: async () => {
const title = await dialog.prompt({
title: t("relation_map.rename_note"),
message: t("relation_map.enter_new_title"),
defaultValue: note?.title,
});
if (!title) {
return;
}
await server.put(`notes/${noteId}/title`, { title });
}
}
],
selectMenuItemHandler() {}
})
const contextMenuHandler = useMemo(() => {
return buildNoteContextMenuHandler(note, mapApiRef);
}, [ note ]);
return note && (

View File

@ -14,7 +14,7 @@ import { CreateChildrenResponse, RelationMapPostResponse, RelationMapRelation }
import RelationMapApi, { MapData, MapDataNoteEntry } from "./api";
import setupOverlays, { uniDirectionalOverlays } from "./overlays";
import { JsPlumb } from "./jsplumb";
import { noteIdToId } from "./utils";
import { getMousePosition, getZoom, noteIdToId } from "./utils";
import { NoteBox } from "./NoteBox";
interface Clipboard {
@ -304,28 +304,3 @@ function useNoteCreation({ ntxId, note, containerRef, mapApiRef }: {
}, []);
return onClickHandler;
}
function getZoom(container: HTMLDivElement) {
const transform = window.getComputedStyle(container).transform;
if (transform === "none") {
return 1;
}
const matrixRegex = /matrix\((-?\d*\.?\d+),\s*0,\s*0,\s*-?\d*\.?\d+,\s*-?\d*\.?\d+,\s*-?\d*\.?\d+\)/;
const matches = transform.match(matrixRegex);
if (!matches) {
throw new Error(t("relation_map.cannot_match_transform", { transform }));
}
return parseFloat(matches[1]);
}
function getMousePosition(evt: MouseEvent, container: HTMLDivElement, zoom: number) {
const rect = container.getBoundingClientRect();
return {
x: ((evt.clientX ?? 0) - rect.left) / zoom,
y: ((evt.clientY ?? 0) - rect.top) / zoom
};
}

View File

@ -0,0 +1,56 @@
import { RefObject } from "preact";
import appContext from "../../../components/app_context";
import FNote from "../../../entities/fnote";
import contextMenu from "../../../menus/context_menu";
import dialog from "../../../services/dialog";
import { t } from "../../../services/i18n";
import server from "../../../services/server";
import RelationMapApi from "./api";
export function buildNoteContextMenuHandler(note: FNote | null | undefined, mapApiRef: RefObject<RelationMapApi>) {
return (e: MouseEvent) => {
if (!note) return;
e.preventDefault();
contextMenu.show({
x: e.pageX,
y: e.pageY,
items: [
{
title: t("relation_map.open_in_new_tab"),
uiIcon: "bx bx-empty",
handler: () => appContext.tabManager.openTabWithNoteWithHoisting(note.noteId)
},
{
title: t("relation_map.remove_note"),
uiIcon: "bx bx-trash",
handler: async () => {
if (!note) return;
const result = await dialog.confirmDeleteNoteBoxWithNote(note.title);
if (typeof result !== "object" || !result.confirmed) return;
mapApiRef.current?.removeItem(note.noteId, result.isDeleteNoteChecked);
}
},
{
title: t("relation_map.edit_title"),
uiIcon: "bx bx-pencil",
handler: async () => {
const title = await dialog.prompt({
title: t("relation_map.rename_note"),
message: t("relation_map.enter_new_title"),
defaultValue: note?.title,
});
if (!title) {
return;
}
await server.put(`notes/${note.noteId}/title`, { title });
}
}
],
selectMenuItemHandler() {}
})
};
}

View File

@ -1,3 +1,5 @@
import { t } from "../../../services/i18n";
export function noteIdToId(noteId: string) {
return `rel-map-note-${noteId}`;
}
@ -5,3 +7,28 @@ export function noteIdToId(noteId: string) {
export function idToNoteId(id: string) {
return id.substr(13);
}
export function getZoom(container: HTMLDivElement) {
const transform = window.getComputedStyle(container).transform;
if (transform === "none") {
return 1;
}
const matrixRegex = /matrix\((-?\d*\.?\d+),\s*0,\s*0,\s*-?\d*\.?\d+,\s*-?\d*\.?\d+,\s*-?\d*\.?\d+\)/;
const matches = transform.match(matrixRegex);
if (!matches) {
throw new Error(t("relation_map.cannot_match_transform", { transform }));
}
return parseFloat(matches[1]);
}
export function getMousePosition(evt: MouseEvent, container: HTMLDivElement, zoom: number) {
const rect = container.getBoundingClientRect();
return {
x: ((evt.clientX ?? 0) - rect.left) / zoom,
y: ((evt.clientY ?? 0) - rect.top) / zoom
};
}