Files
webstudio/app/canvas/shared/active-element.ts
T
Oleg Isonen 8e8372067f ensure focus from wrapper component #8
fixes the case that setSelectedInstance can be called before the instance actually renders
2022-03-30 22:26:44 +01:00

63 lines
1.9 KiB
TypeScript

import { useCallback, useEffect } from "react";
import { type Instance } from "@webstudio-is/sdk";
import { findInstanceById } from "~/shared/tree-utils";
import {
useSelectedInstance,
useSelectedElement,
useRootInstance,
} from "./nano-values";
import { publish, useSubscribe } from "./pubsub";
const eventOptions = {
passive: true,
};
export const useActiveElementTracking = () => {
const [rootInstance] = useRootInstance();
const [selectedInstance, setSelectedInstance] = useSelectedInstance();
const [selectedElement, setSelectedElement] = useSelectedElement();
useSubscribe("focusElement", (id: Instance["id"]) => {
const element = document.getElementById(id);
element?.focus();
select(element);
});
const select = useCallback(
(element: Element | null) => {
if (element === null || rootInstance === undefined) return;
const id = element?.id;
if (!id) return;
if (selectedElement?.id === id) return;
const instance = findInstanceById(rootInstance, element.id);
if (instance === undefined) return;
setSelectedInstance(instance);
setSelectedElement(element);
},
[rootInstance, selectedElement, setSelectedElement, setSelectedInstance]
);
useEffect(() => {
const handleFocus = () => {
select(document.activeElement);
};
window.addEventListener("focus", handleFocus, eventOptions);
const handleClick = (event: MouseEvent) => {
// Notify in general that document was clicked
// e.g. to hide the side panel
publish<"clickCanvas">({ type: "clickCanvas" });
if (event.target instanceof Element) select(event.target);
};
window.addEventListener("click", handleClick, eventOptions);
return () => {
window.removeEventListener("focus", handleFocus);
window.removeEventListener("click", handleClick);
};
}, [select]);
return selectedInstance;
};