import React from "react" ; import { Provider } from "polar-shared/src/util/Providers" ; import { createObservableStore , SetStore } from '../react/store/ObservableStore' ; import { arrayStream } from "polar-shared/src/util/ArrayStreams" ; export interface TabDescriptor { readonly title : string ; readonly icon ? : React . ReactNode ; readonly tabContentIndex : number ; readonly url : string ; } export interface TabContentDescriptor { readonly url : string | undefined ; } interface IBrowserTabsStore { readonly activeTab : number | undefined ; readonly tabs : ReadonlyArray < TabDescriptor > ; readonly tabContents : ReadonlyArray < TabContentDescriptor > ; } interface IBrowserTabsCallbacks { readonly setActiveTab : ( id : number ) => void ; readonly addTab : ( tabDescriptor : TabDescriptor ) => void ; readonly removeTab : ( id : number ) => void ; readonly swapTabs : ( id1 : number , id2 : number ) => void ; } function createInitialTabs ( ) { return [ { tabContentIndex : 0 , title : "Polar: Document Repository" , url : "/" } ] ; } function createInitialTabContents ( ) { return [ { url : "/" } ] ; } const initialStore = { activeTab : 0 , tabs : createInitialTabs ( ) , tabContents : createInitialTabContents ( ) } ; interface Mutation { readonly activeTab : number ; readonly tabs : ReadonlyArray < TabDescriptor > ; readonly tabContents : ReadonlyArray < TabContentDescriptor > ; } interface Mutator { readonly doUpdate : ( mutation : Mutation ) => void ; } function mutatorFactory ( storeProvider , setStore ) { function doUpdate ( mutation ) { setStore ( mutation ) ; } return { doUpdate } ; } function callbacksFactory ( storeProvider , setStore , mutator ) { return React . useMemo ( ( ) : IBrowserTabsCallbacks => { function setActiveTab ( activeTab ) { const store = storeProvider ( ) ; setStore ( { ... store , activeTab } ) ; } function addTab ( tabDescriptor ) { const store = storeProvider ( ) ; function computeExistingTab ( ) { return arrayStream ( store . tabContents ) . withIndex ( ) . filter ( ( current ) => current . value . url === tabDescriptor . url ) . first ( ) ; } const doTabMutation = ( newStore ) => { setStore ( newStore ) ; } ; const existingTab = computeExistingTab ( ) ; if ( existingTab ) { doTabMutation ( { ... store , activeTab : existingTab . index } ) ; return ; } const newTabDescriptor = { ... tabDescriptor , tabContentIndex : store . tabContents . length } ; const tabs = [ ... store . tabs , newTabDescriptor ] ; const tabContents = [ ... store . tabContents , { url : tabDescriptor . url } ] ; const activeTab = tabs . length - 1 ; doTabMutation ( { ... store , activeTab , tabs , tabContents } ) ; } function removeTab ( id ) { const store = storeProvider ( ) ; function computeTabs ( ) { const tabs = [ ... store . tabs ] ; tabs . splice ( id , 1 ) ; return tabs ; } function computeTabContents ( ) { const tabContentIndex = store . tabs [ id ] . tabContentIndex ; const tabContents = [ ... store . tabContents ] as any [ ] ; tabContents [ tabContentIndex ] . url = undefined ; return tabContents ; } const tabs = computeTabs ( ) ; const tabContents = computeTabContents ( ) ; setStore ( { ... store , tabs , tabContents } ) ; } function swapTabs ( id1 , id2 ) { const store = storeProvider ( ) ; const tabs = [ ... store . tabs ] ; [ tabs [ id1 ] , tabs [ id2 ] ] = [ tabs [ id2 ] , tabs [ id1 ] ] ; setStore ( { ... store , tabs } ) ; } return { addTab , removeTab , setActiveTab , swapTabs } ; } , [ storeProvider , setStore ] ) ; } export function createBrowserTabsStore ( ) { return createObservableStore < IBrowserTabsStore , Mutator , IBrowserTabsCallbacks > ( { initialValue : initialStore , mutatorFactory , callbacksFactory } ) ; } export const [ BrowserTabsStoreProvider , useBrowserTabsStore , useBrowserTabsCallbacks ] = createBrowserTabsStore ( ) ;