diff --git a/package-lock.json b/package-lock.json index efc9d48..5bb1226 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@commitlint/cli": "^20.0.0", "@commitlint/config-conventional": "^20.0.0", "@release-it/conventional-changelog": "^10.0.1", - "@types/chrome": "^0.1.12", + "@types/chrome": "^0.1.36", "@types/jest": "^30.0.0", "husky": "^9.1.7", "jest": "^30.1.3", diff --git a/package.json b/package.json index 8317bac..32dc0d6 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "@commitlint/cli": "^20.0.0", "@commitlint/config-conventional": "^20.0.0", "@release-it/conventional-changelog": "^10.0.1", - "@types/chrome": "^0.1.12", + "@types/chrome": "^0.1.36", "@types/jest": "^30.0.0", "husky": "^9.1.7", "jest": "^30.1.3", diff --git a/src/sidebar.ts b/src/sidebar.ts index b5dbfaa..db2e919 100644 --- a/src/sidebar.ts +++ b/src/sidebar.ts @@ -6,6 +6,7 @@ type Color = string | ColorArray; type ColorArray = chrome.extensionTypes.ColorArray; type OpenOptions = chrome.sidePanel.OpenOptions; +type CloseOptions = chrome.sidePanel.CloseOptions; type PanelOptions = chrome.sidePanel.PanelOptions; type PanelBehavior = chrome.sidePanel.PanelBehavior; type IconDetails = opr.sidebarAction.IconDetails; @@ -19,6 +20,8 @@ const isAvailableOperaSidebar = (): boolean => globalThis?.opr?.sidebarAction != // Chromium standard const sidePanel = (): typeof chrome.sidePanel | undefined => browser().sidePanel; +export class SidebarError extends Error {} + // Methods export const getSidebarOptions = (tabId?: number): Promise => callWithPromise(cb => { @@ -56,8 +59,22 @@ export const canOpenSidebar = (): boolean => { return false; }; +export const canCloseSidebar = (): boolean => { + if (sidePanel()) { + return true; + } + + const sb = (sidebarAction() as FirefoxSidebarAction) || undefined; + + if (sb) { + return !!sb.close; + } + + return false; +}; + export const openSidebar = (options: OpenOptions): Promise => - callWithPromise(cb => { + callWithPromise(async cb => { const sp = sidePanel(); if (sp) { @@ -67,12 +84,39 @@ export const openSidebar = (options: OpenOptions): Promise => const sb = sidebarAction() as FirefoxSidebarAction | undefined; if (sb?.open) { - return sb.open(); + const result = sb.open(); + + if (result instanceof Promise) { + await result; + } + + return cb(); + } + + throw new SidebarError("The sidebarAction.open API is not supported in this browser"); + }); + +export const closeSidebar = (options: CloseOptions): Promise => + callWithPromise(async cb => { + const sp = sidePanel(); + + if (sp) { + return sp.close(options, cb); } - console.warn("The sidebar open API is not supported in this browser"); + const sb = sidebarAction() as FirefoxSidebarAction | undefined; + + if (sb?.close) { + const result = sb.close(); - cb(); + if (result instanceof Promise) { + await result; + } + + return cb(); + } + + throw new SidebarError("The sidebarAction.close API is not supported in this browser"); }); export const setSidebarOptions = (options?: PanelOptions): Promise => @@ -80,9 +124,7 @@ export const setSidebarOptions = (options?: PanelOptions): Promise => const sp = sidePanel(); if (!sp) { - console.warn("The chrome.sidePanel.setOptions API is not supported for this browser"); - - return cb(); + throw new SidebarError("The chrome.sidePanel.setOptions API is not supported for this browser"); } sp.setOptions(options || {}, cb); @@ -93,12 +135,44 @@ export const setSidebarBehavior = (behavior?: PanelBehavior): Promise => const sp = sidePanel(); if (!sp) { - console.warn("The chrome.sidePanel.setPanelBehavior API is not supported in this browser"); + throw new SidebarError("The chrome.sidePanel.setPanelBehavior API is not supported in this browser"); + } + + sp.setPanelBehavior(behavior || {}, cb); + }); + +export const isOpenSidebar = (windowId?: number): Promise => + callWithPromise(async cb => { + const sb = sidebarAction() as FirefoxSidebarAction | undefined; + + if (sb?.isOpen) { + const result = sb.isOpen({windowId}); + + if (result instanceof Promise) { + return cb(await result); + } else { + return cb(result); + } + } + + throw new SidebarError("The sidebarAction.isOpen API is not supported in this browser"); + }); + +export const toggleSidebar = (): Promise => + callWithPromise(async cb => { + const sb = sidebarAction() as FirefoxSidebarAction | undefined; + + if (sb?.toggle) { + const result = sb.toggle(); + + if (result instanceof Promise) { + await result; + } return cb(); } - sp.setPanelBehavior(behavior || {}, cb); + throw new SidebarError("The sidebarAction.toggle API is not supported in this browser"); }); // Customs methods @@ -153,19 +227,16 @@ export const setSidebarTitle = (title: string | number, tabId?: number): Promise callWithPromise(async cb => { const sb = sidebarAction(); - if (!sb) { - console.warn("The sidebarAction.setTitle API is supported only in Opera or Firefox"); + if (sb?.setTitle) { + const result = sb.setTitle({tabId, title: title.toString()}); + if (result instanceof Promise) { + await result; + } return cb(); } - const result = sb.setTitle({tabId, title: title.toString()}); - - if (result instanceof Promise) { - await result; - } - - cb(); + throw new SidebarError("The sidebarAction.setTitle API is supported only in Opera or Firefox"); }); export const setSidebarBadgeText = (text: string | number, tabId?: number): Promise => @@ -178,9 +249,7 @@ export const setSidebarBadgeText = (text: string | number, tabId?: number): Prom return cb(); } - console.warn("The opr.sidebarAction.setBadgeText API is supported only in Opera"); - - cb(); + throw new SidebarError("The sidebarAction.setBadgeText API is supported only in Opera"); }); export const clearSidebarBadgeText = (tabId?: number): Promise => setSidebarBadgeText("", tabId); @@ -211,9 +280,7 @@ export const setSidebarIcon = (details: IconDetails): Promise => return cb(); } - console.warn("The sidebarAction.setIcon API is supported only in Opera or Firefox"); - - cb(); + throw new SidebarError("The sidebarAction.setIcon API is supported only in Opera or Firefox"); }); export const setSidebarBadgeTextColor = (color: Color, tabId?: number): Promise => @@ -226,9 +293,7 @@ export const setSidebarBadgeTextColor = (color: Color, tabId?: number): Promise< return cb(); } - console.warn("The opr.sidebarAction.setBadgeTextColor API is supported only in Opera"); - - cb(); + throw new SidebarError("The sidebarAction.setBadgeTextColor API is supported only in Opera"); }); export const setSidebarBadgeBgColor = (color: Color, tabId?: number): Promise => @@ -241,9 +306,7 @@ export const setSidebarBadgeBgColor = (color: Color, tabId?: number): Promise => @@ -258,7 +321,7 @@ export const getSidebarTitle = (tabId?: number): Promise => return (sb as any).getTitle({tabId}); } - throw new Error("The sidebarAction.getTitle API not available"); + throw new SidebarError("The sidebarAction.getTitle API not available"); }); export const getSidebarBadgeText = (tabId?: number): Promise => @@ -269,7 +332,7 @@ export const getSidebarBadgeText = (tabId?: number): Promise => return sb.getBadgeText({tabId}, cb); } - throw new Error("The opr.sidebarAction.getBadgeText API is supported only in Opera"); + throw new SidebarError("The sidebarAction.getBadgeText API is supported only in Opera"); }); export const getSidebarBadgeTextColor = (tabId?: number): Promise => @@ -280,7 +343,7 @@ export const getSidebarBadgeTextColor = (tabId?: number): Promise => return sb.getBadgeTextColor({tabId}, cb); } - throw new Error("The opr.sidebarAction.getBadgeTextColor API is supported only in Opera"); + throw new SidebarError("The sidebarAction.getBadgeTextColor API is supported only in Opera"); }); export const getSidebarBadgeBgColor = (tabId?: number): Promise => @@ -291,5 +354,5 @@ export const getSidebarBadgeBgColor = (tabId?: number): Promise => return sb.getBadgeBackgroundColor({tabId}, cb); } - throw new Error("The opr.sidebarAction.getBadgeBackgroundColor API is supported only in Opera"); + throw new SidebarError("The sidebarAction.getBadgeBackgroundColor API is supported only in Opera"); });