I'm building a browser extension using react, vite, typescript. The extension has side-panel and fullscreen tabs. Only on fullscreeen tabs, I need to create a button/icon that appears only when side-panel is closed. So, when I open side-panel it hides the button and when I close side-panel it shows the button. I found a way to check if the side-panel is closed or open using this code.
const contexts: chrome.runtime.ExtensionContext[] = await chrome.runtime.getContexts({ contextTypes: ["SIDE_PANEL"] });
if contexts.length > 0
it means that side-panel is open, otherwise, it is closed. I added this logic in useEffect
hook, and it works fine. The problem is that I need to run this code again every time side-panel opens or closes so it can check side-panel status and show/hide it if needed. I tried using focus and blur events but unfortunately it doesn't work in Chrome browser although it works in Edge. I come up with an idea that I can use chrome.runtime.sendMessage
to trigger the code and run function again. In my main component index.tsx
in useEffect
I can send the message and it will trigger the code and hide the button. But then, I need to send the same message when side-panel closes. I tried to do it in useEffect
return function but it didn't work for me.
Is there any way to sendMessage
when side-panel closes? Or maybe, there is better options to implement the logic of showing and hiding the icon?
Full code of the button component is below
import { useEffect, useState } from "react";
import { logosHooks } from "@/hooks/logos-hooks";
import { cn } from "@/lib/utils";
const SidePanelTrigger = () => {
const logo = logosHooks.useLogoIcon();
const [show, setShow] = useState(false);
useEffect(() => {
const checkPanelState = async() => {
const contexts: chrome.runtime.ExtensionContext[] = await chrome.runtime.getContexts({ contextTypes: ["SIDE_PANEL"] });
setShow(contexts.length !== 0);
}
checkPanelState();
}, []);
const handleOpenSidepanel = () => {
chrome.runtime.sendMessage({ action: "openSidePanel" });
}
return (
<button
className={cn(
"flex fixed top-[200px] z-10 -right-[10px] bg-primary rounded-l-sm justify-center items-center transition-all duration-300 hover:right-0 p-3 shadow-lg cursor-pointer",
show && "hidden"
)}
onClick={handleOpenSidepanel}
>
Button
</button>
);
};
export default SidePanelTrigger;
I changed a little bit the code and managed to fix that.
The solution that worked for me is using ResizeObserver
. Every time side-panel opens or closes it changes the width of the active tab. I attached my checkPanelState
function that checks if side-panel is closed or open to resizing event using ResizeObserver
. I also added debounce to optimize the code.
Full code of the component is below
import { useEffect, useState } from "react";
import { logosHooks } from "@/hooks/logos-hooks";
import { cn, debounce } from "@/lib/utils";
const SidePanelTrigger = () => {
const logo = logosHooks.useLogoIcon();
const [show, setShow] = useState(false);
useEffect(() => {
const checkPanelState = async() => {
// @ts-ignore
const contexts: chrome.runtime.ExtensionContext[] = await chrome.runtime.getContexts({ contextTypes: ["SIDE_PANEL"] });
setShow(contexts.length === 0);
}
const debouncedCheck = debounce(checkPanelState, 50);
const resizeObserver = new ResizeObserver(debouncedCheck);
resizeObserver.observe(document.body);
return () => resizeObserver.disconnect();
}, []);
const handleOpenSidepanel = () => {
setShow(false)
chrome.runtime.sendMessage({ action: "openSidePanel" });
}
return (
<button
className={cn(
"hidden fixed top-[200px] z-10 -right-[10px] bg-primary rounded-l-sm justify-center items-center transition-all duration-300 hover:right-0 p-3 shadow-lg cursor-pointer",
show && "flex"
)}
onClick={handleOpenSidepanel}
>
Button
</button>
);
};
export default SidePanelTrigger;