mylingo3d
Version:
Lingo3D is a React/Vue 3d game development framework that ships with a complete visual editor
85 lines • 4.43 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
import { Fragment } from "preact";
import { useEffect, useState } from "preact/hooks";
import Loaded from "../../display/core/Loaded";
import { isMeshItem } from "../../display/core/MeshItem";
import Dummy, { dummyTypeMap } from "../../display/Dummy";
import { onSelectionTarget } from "../../events/onSelectionTarget";
import { DUMMY_URL, YBOT_URL } from "../../globals";
import { setSceneGraphExpanded } from "../../states/useSceneGraphExpanded";
import { setSceneGraphTarget } from "../../states/useSceneGraphTarget";
import { addSelectionFrozen, clearSelectionFrozen } from "../../states/useSelectionFrozen";
import downloadBlob from "../../api/files/downloadBlob";
import ContextMenu from "../component/ContextMenu";
import MenuItem from "../component/ContextMenu/MenuItem";
import { useSelectionFrozen, useSelectionTarget } from "../states";
const traverseUp = (obj, expandedSet) => {
expandedSet.add(obj);
const nextParent = obj.userData.manager?.parent?.outerObject3d ?? obj.parent;
nextParent && traverseUp(nextParent, expandedSet);
};
const search = (n, target) => {
const name = n.toLowerCase();
let found;
if (target instanceof Loaded)
target.loadedGroup.traverse((item) => {
if (found)
return;
item.name.toLowerCase().includes(name) && (found = item);
});
else
target.outerObject3d.traverse((item) => {
if (found)
return;
item.name.toLowerCase().includes(name) && (found = item);
});
if (!found)
return;
const expandedSet = new Set();
traverseUp(found, expandedSet);
setSceneGraphExpanded(expandedSet);
setSceneGraphTarget(found);
};
const SceneGraphContextMenu = () => {
const [data, setData] = useState(undefined);
const [showSearch, setShowSearch] = useState(false);
const [selectionTarget] = useSelectionTarget();
const [[selectionFrozen]] = useSelectionFrozen();
useEffect(() => {
let [clientX, clientY] = [0, 0];
const cb = (e) => ([clientX, clientY] = [e.clientX, e.clientY]);
document.addEventListener("mousemove", cb);
const handle = onSelectionTarget(({ target, rightClick }) => {
rightClick && setData({ x: clientX, y: clientY, target });
});
return () => {
handle.cancel();
document.removeEventListener("mousemove", cb);
};
}, []);
useEffect(() => {
!data && setShowSearch(false);
}, [data]);
if (!data)
return null;
return (_jsx(ContextMenu, { data: data, setData: setData, children: showSearch ? (_jsx("input", { ref: (el) => el?.focus(), style: { all: "unset", padding: 6 }, onKeyDown: (e) => {
e.stopPropagation();
if (e.key !== "Enter" && e.key !== "Escape")
return;
e.key === "Enter" &&
selectionTarget &&
search(e.target.value, selectionTarget);
setData(undefined);
} })) : (_jsxs(Fragment, { children: [data.target && (_jsxs(Fragment, { children: [_jsx(MenuItem, { setData: undefined, onClick: () => setShowSearch(true), children: "Search children" }), _jsx(MenuItem, { setData: setData, onClick: () => isMeshItem(selectionTarget) &&
addSelectionFrozen(selectionTarget), children: "Freeze selection" }), selectionTarget instanceof Dummy &&
dummyTypeMap.has(selectionTarget) && (_jsx(MenuItem, { setData: setData, onClick: async () => {
const url = dummyTypeMap.get(selectionTarget) === "dummy"
? YBOT_URL
: DUMMY_URL +
"readyplayerme/reference.fbx";
const res = await fetch(url);
downloadBlob("model.fbx", await res.blob());
}, children: "Download for Mixamo" }))] })), _jsx(MenuItem, { setData: setData, disabled: !selectionFrozen.size, onClick: () => clearSelectionFrozen(), children: "Unfreeze all" })] })) }));
};
export default SceneGraphContextMenu;
//# sourceMappingURL=SceneGraphContextMenu.js.map