From e015b180a86e6b0632f393448f7e4e7f92e23d8e Mon Sep 17 00:00:00 2001 From: Ammar Ahmed Date: Fri, 22 Dec 2023 08:23:42 +0500 Subject: [PATCH] mobile: push changes --- apps/mobile/app/navigation/tabs-holder.js | 4 +- .../app/screens/editor/tiptap/commands.ts | 3 - .../screens/editor/tiptap/editor-events.ts | 2 +- .../editor/tiptap/use-editor-events.ts | 27 +- .../app/screens/editor/tiptap/use-editor.ts | 140 +++++++--- .../screens/editor/tiptap/use-tab-store.ts | 245 +++++++++++------- .../mobile/app/screens/editor/tiptap/utils.ts | 19 ++ packages/editor-mobile/src/App.tsx | 9 - .../editor-mobile/src/components/editor.tsx | 8 +- .../src/components/statusbar.tsx | 1 + .../src/hooks/useEditorController.ts | 6 +- .../editor-mobile/src/hooks/useTabStore.ts | 55 ++-- 12 files changed, 320 insertions(+), 199 deletions(-) diff --git a/apps/mobile/app/navigation/tabs-holder.js b/apps/mobile/app/navigation/tabs-holder.js index 2f5f9c10f..3d7d305b6 100644 --- a/apps/mobile/app/navigation/tabs-holder.js +++ b/apps/mobile/app/navigation/tabs-holder.js @@ -511,8 +511,8 @@ const onChangeTab = async (obj) => { editorState().movedAway = false; editorState().isFocused = true; activateKeepAwake(); - console.log(editorState().currentlyEditing, "currentlyEditing..."); - if (!editorState().currentlyEditing) { + + if (!useTabStore.getState().getCurrentNoteId()) { eSendEvent(eOnLoadNote, { newNote: true }); diff --git a/apps/mobile/app/screens/editor/tiptap/commands.ts b/apps/mobile/app/screens/editor/tiptap/commands.ts index 5bbf39cee..3df438b12 100644 --- a/apps/mobile/app/screens/editor/tiptap/commands.ts +++ b/apps/mobile/app/screens/editor/tiptap/commands.ts @@ -75,7 +75,6 @@ class Commands { } focus = async (tabId: number) => { - console.log("focus"); if (!this.ref.current) return; if (Platform.OS === "android") { //this.ref.current?.requestFocus(); @@ -103,7 +102,6 @@ class Commands { ); clearContent = async (tabId: number) => { - console.log("clearContent"); this.previousSettings = null; await this.doAsync( ` @@ -134,7 +132,6 @@ if (typeof statusBar !== "undefined") { saved: string, tabId: number ) => { - console.log("setStatus"); await this.doAsync( ` const statusBar = statusBars[${tabId}]; diff --git a/apps/mobile/app/screens/editor/tiptap/editor-events.ts b/apps/mobile/app/screens/editor/tiptap/editor-events.ts index c80127381..f78e74063 100644 --- a/apps/mobile/app/screens/editor/tiptap/editor-events.ts +++ b/apps/mobile/app/screens/editor/tiptap/editor-events.ts @@ -39,6 +39,6 @@ export const EventTypes = { copyToClipboard: "editor-events:copy-to-clipboard", getAttachmentData: "editor-events:get-attachment-data", tabsChanged: "editor-events:tabs-changed", - showTabs: "editor-events:showTabs", + showTabs: "editor-events:show-tabs", tabFocused: "editor-events:tab-focused" }; diff --git a/apps/mobile/app/screens/editor/tiptap/use-editor-events.ts b/apps/mobile/app/screens/editor/tiptap/use-editor-events.ts index 9be60354d..9ac6c4b71 100644 --- a/apps/mobile/app/screens/editor/tiptap/use-editor-events.ts +++ b/apps/mobile/app/screens/editor/tiptap/use-editor-events.ts @@ -518,11 +518,11 @@ export const useEditorEvents = ( break; } case EventTypes.tabsChanged: { - useTabStore.setState({ - tabs: (editorMessage.value as any)?.tabs, - currentTab: (editorMessage.value as any)?.currentTab - }); - console.log("tabs updated..."); + // useTabStore.setState({ + // tabs: (editorMessage.value as any)?.tabs, + // currentTab: (editorMessage.value as any)?.currentTab + // }); + // console.log("Tabs updated"); break; } case EventTypes.showTabs: { @@ -531,13 +531,16 @@ export const useEditorEvents = ( } case EventTypes.tabFocused: { // Reload the note - const note = await db.notes.note(editorMessage.noteId); - if (note) { - eSendEvent(eOnLoadNote, { - item: note, - forced: true - }); - } + console.log("Focused tab", editorMessage.tabId); + eSendEvent("tabsFocused", editorMessage.tabId); + + // const note = await db.notes.note(editorMessage.noteId); + // if (note) { + // eSendEvent(eOnLoadNote, { + // item: note, + // forced: true + // }); + // } // TODO // Handle any updates that occured in an note while the tab was not focused. // If editor has no content, reload the note, because it might be an app reload diff --git a/apps/mobile/app/screens/editor/tiptap/use-editor.ts b/apps/mobile/app/screens/editor/tiptap/use-editor.ts index 0920fe77f..fdde552f4 100644 --- a/apps/mobile/app/screens/editor/tiptap/use-editor.ts +++ b/apps/mobile/app/screens/editor/tiptap/use-editor.ts @@ -55,7 +55,7 @@ import { onNoteCreated } from "../../notes/common"; import Commands from "./commands"; import { SessionHistory } from "./session-history"; import { EditorState, SavePayload } from "./types"; -import { useTabStore } from "./use-tab-store"; +import { syncTabs, useTabStore } from "./use-tab-store"; import { EditorEvents, clearAppState, @@ -63,7 +63,8 @@ import { getAppState, isContentInvalid, isEditorLoaded, - post + post, + waitForEvent } from "./utils"; // Keep a fixed session id, dont' change it when a new note is opened, session id can stay the same always I think once the app is opened. DONE @@ -117,6 +118,7 @@ export const useEditor = ( const lock = useRef(false); const currentLoadingNoteId = useRef(); const loadingState = useRef(); + const lastTabFocused = useRef(0); const postMessage = useCallback( async (type: string, data: T, tabId?: number, waitFor = 300) => await post( @@ -146,6 +148,16 @@ export const useEditor = ( } }, [commands, tags]); + useEffect(() => { + const event = eSubscribeEvent("tabsFocused", (tabId) => { + lastTabFocused.current = tabId as number; + console.log(tabId); + }); + return () => { + event.unsubscribe(); + }; + }); + const overlay = useCallback( (show: boolean, data = { type: "new" }) => { eSendEvent( @@ -191,10 +203,10 @@ export const useEditor = ( lastContentChangeTime.current = 0; resetContent && (await commands.clearContent(tabId)); resetContent && (await commands.clearTags(tabId)); - - useTabStore.getState().updateTab(tabId, { - noteId: undefined - }); + // TODO ? + // useTabStore.getState().updateTab(tabId, { + // noteId: undefined + // }); }, [commands, editorSessionHistory, postMessage] ); @@ -248,9 +260,11 @@ export const useEditor = ( } // If note is edited, the tab becomes a persistent tab automatically. - useTabStore.getState().updateTab(tabId, { - previewTab: false - }); + if (useTabStore.getState().getTab(tabId)?.previewTab) { + useTabStore.getState().updateTab(tabId, { + previewTab: false + }); + } if (!locked) { id = await db.notes?.add(noteData); @@ -369,8 +383,10 @@ export const useEditor = ( } if (event.newNote) { + console.log("Create new note"); useTabStore.getState().focusEmptyTab(); const tabId = useTabStore.getState().currentTab; + console.log("empty tab", tabId); currentNotes.current && (await reset(tabId)); setTimeout(() => { if (state.current?.ready) commands.focus(tabId); @@ -379,21 +395,33 @@ export const useEditor = ( } else { if (!event.item) return; const item = event.item; - - // If note was already opened in a tab, focus that tab. + console.log("load note called again...", event.forced, event.item.id); + // If note was already opened in a tab, focus that tab and return. Once the tab is focused + // the note will load. if (useTabStore.getState().hasTabForNote(event.item.id)) { const tabId = useTabStore.getState().getTabForNote(event.item.id); if (typeof tabId === "number") { + useTabStore.getState().updateTab(tabId, { + readonly: event.item.readonly + }); useTabStore.getState().focusTab(tabId); } + } else { + console.log("opening note in preview tab"); + // Otherwise we focus the preview tab or create one to open the note in. + useTabStore.getState().focusPreviewTab(event.item.id, { + readonly: event.item.readonly, + locked: false + }); } - - // Otherwise we focus the preview tab or create one to open the note in. - useTabStore.getState().focusPreviewTab(event.item.id, { - readonly: event.item.readonly, - locked: false - }); const tabId = useTabStore.getState().currentTab; + console.log(lastTabFocused.current, tabId); + if (lastTabFocused.current !== tabId) { + if ((await waitForEvent("tabsFocused", 1000)) !== tabId) { + console.log("tab id did not match after focus in 1000ms"); + return; + } + } // If note is already loaded and forced reload is not requested, return. if (!event.forced && currentNotes.current[item.id]) return; @@ -410,8 +438,8 @@ export const useEditor = ( if ( currentNotes.current[item.id] && loadingState.current && - currentContents.current?.data && - loadingState.current === currentContents.current?.data + currentContents.current[item.id]?.data && + loadingState.current === currentContents.current[item.id]?.data ) { return; } @@ -437,10 +465,10 @@ export const useEditor = ( await postMessage(EditorEvents.title, item.title, tabId); loadingState.current = currentContents.current[item.id]?.data; - if (currentContents.current?.data) { + if (currentContents.current[item.id]?.data) { await postMessage( EditorEvents.html, - currentContents.current?.data, + currentContents.current[item.id]?.data, tabId, 10000 ); @@ -561,7 +589,12 @@ export const useEditor = ( ignoreEdit: boolean; tabId: number; }) => { - if (lock.current || currentLoadingNoteId.current === noteId) return; + if ( + lock.current || + (currentLoadingNoteId.current && + currentLoadingNoteId.current === noteId) + ) + return; lastContentChangeTime.current = Date.now(); @@ -602,6 +635,7 @@ export const useEditor = ( const restoreEditorState = useCallback(async () => { const appState = getAppState(); + console.log(appState, "appState"); if (!appState) return; state.current.isRestoringState = true; state.current.currentlyEditing = true; @@ -610,25 +644,9 @@ export const useEditor = ( if (!DDS.isTab) { tabBarRef.current?.goToPage(1, false); } - if (appState.note) { - if (useSettingStore.getState().isAppLoading) { - const remove = useSettingStore.subscribe((state) => { - if (!state.isAppLoading && appState.note) { - loadNote({ - item: appState.note - }); - remove(); - } - }); - } else { - loadNote({ - item: appState.note - }); - } - } clearAppState(); state.current.isRestoringState = false; - }, [loadNote]); + }, []); useEffect(() => { eSubscribeEvent(eOnLoadNote + editorId, loadNote); @@ -653,9 +671,16 @@ export const useEditor = ( useTabStore.getState().currentTab )) ) { + console.log( + "ready failed....", + sessionIdRef.current, + useTabStore.getState().currentTab + ); eSendEvent("webview_reset", "onReady"); return false; } else { + console.log("onReady", "sync tabs"); + syncTabs(); isDefaultEditor && restoreEditorState(); return true; } @@ -677,9 +702,42 @@ export const useEditor = ( } overlay(false); + // TODO: Improve handling this on app launch from a link etc. const noteId = useTabStore.getState().getCurrentNoteId(); - if (noteId && currentNotes.current[noteId]) { - loadNote({ ...currentNotes.current[noteId], forced: true }); + + if (noteId) { + if (useSettingStore.getState().isAppLoading) { + const unsub = useSettingStore.subscribe(async (s) => { + if (!s.isAppLoading) { + try { + const note = await db.notes.note(noteId); + if (note) { + loadNote({ item: note, forced: true }); + } else { + console.log("new note after app load"); + loadNote({ newNote: true }); + if (tabBarRef.current?.page === 1) { + state.current.currentlyEditing = false; + } + } + unsub(); + } catch (e) { + console.log(e); + } + } + }); + } else { + const note = await db.notes.note(noteId); + if (note) { + loadNote({ item: note, forced: true }); + } else { + console.log("new note"); + loadNote({ newNote: true }); + if (tabBarRef.current?.page === 1) { + state.current.currentlyEditing = false; + } + } + } } }); }); diff --git a/apps/mobile/app/screens/editor/tiptap/use-tab-store.ts b/apps/mobile/app/screens/editor/tiptap/use-tab-store.ts index 461ff84be..72edbb8c7 100644 --- a/apps/mobile/app/screens/editor/tiptap/use-tab-store.ts +++ b/apps/mobile/app/screens/editor/tiptap/use-tab-store.ts @@ -17,7 +17,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ import create from "zustand"; +import { persist, StateStorage } from "zustand/middleware"; import { editorController } from "./utils"; +import { MMKV } from "../../../common/database/mmkv"; export type TabItem = { id: number; @@ -37,104 +39,163 @@ export type TabStore = { ) => void; removeTab: (index: number) => void; moveTab: (index: number, toIndex: number) => void; - newTab: (noteId?: string) => void; + newTab: (noteId?: string, previewTab?: boolean) => void; focusTab: (id: number) => void; getNoteIdForTab: (id: number) => string | undefined; getTabForNote: (noteId: string) => number | undefined; hasTabForNote: (noteId: string) => boolean; focusEmptyTab: () => void; getCurrentNoteId: () => string | undefined; + getTab: (tabId: number) => TabItem | undefined; }; -export const useTabStore = create((set, get) => ({ - tabs: [ - { - id: 0 - } - ], - currentTab: 0, - updateTab: (id: number, options: Omit, "id">) => { - if (!options) return; - const index = get().tabs.findIndex((t) => t.id === id); - if (index == -1) return; - const tabs = [...get().tabs]; - tabs[index] = { - ...tabs[index], - ...options - }; - - set({ - tabs: tabs - }); - - editorController.current?.commands.doAsync(` - globalThis.tabStore.getState().updateTab(${id}, ${JSON.stringify(options)}); -`); - }, - focusPreviewTab: (noteId: string, options: Omit, "id">) => { - const index = get().tabs.findIndex((t) => t.previewTab); - if (index === -1) return get().newTab(noteId); - const tabs = [...get().tabs]; - tabs[index] = { - ...tabs[index], - noteId: noteId, - ...options - }; - set({ - currentTab: tabs[index].id - }); - - editorController.current?.commands.doAsync(` - globalThis.tabStore.getState().focusPreviewTab(${ - noteId ? `"${noteId}"` : "" - }, ${JSON.stringify(options || {})}); -`); - }, - removeTab: (index: number) => { - editorController.current?.commands.doAsync(` - globalThis.tabStore.getState().removeTab(${index}); - `); - }, - newTab: (noteId?: string) => { - editorController.current?.commands.doAsync(` - globalThis.tabStore.getState().newTab(${noteId ? `"${noteId}"` : ""}); - `); - }, - focusEmptyTab: () => { - const index = get().tabs.findIndex((t) => !t.noteId); - if (index === -1) return get().newTab(); - const tabs = [...get().tabs]; - tabs[index] = { - ...tabs[index] - }; - set({ - currentTab: tabs[index].id - }); - - editorController.current?.commands.doAsync(` - globalThis.tabStore.getState().focusEmptyTab(); -`); - }, - moveTab: (index: number, toIndex: number) => { - editorController.current?.commands.doAsync(` - globalThis.tabStore.getState().moveTab(${index}, ${toIndex}); - `); - }, - focusTab: (id: number) => { - editorController.current?.commands.doAsync(` - globalThis.tabStore.getState().focusTab(${id}); - `); - }, - getNoteIdForTab: (id: number) => { - return get().tabs.find((t) => t.id === id)?.noteId; - }, - hasTabForNote: (noteId: string) => { - return typeof get().tabs.find((t) => t.noteId === noteId)?.id === "number"; - }, - getTabForNote: (noteId: string) => { - return get().tabs.find((t) => t.noteId === noteId)?.id; - }, - getCurrentNoteId: () => { - return get().tabs.find((t) => t.id === get().currentTab)?.noteId; +function getId(id: number, tabs: TabItem[]): number { + const exists = tabs.find((t) => t.id === id); + if (exists) { + return getId(id + 1, tabs); } -})); + return id; +} + +export function syncTabs() { + editorController.current?.commands.doAsync(` + globalThis.tabStore?.setState({ + tabs: ${JSON.stringify(useTabStore.getState().tabs)}, + currentTab: ${useTabStore.getState().currentTab} + }); +`); +} + +export const useTabStore = create( + persist( + (set, get) => ({ + tabs: [ + { + id: 0 + } + ], + currentTab: 0, + updateTab: (id: number, options: Omit, "id">) => { + if (!options) return; + const index = get().tabs.findIndex((t) => t.id === id); + if (index == -1) return; + const tabs = [...get().tabs]; + tabs[index] = { + ...tabs[index], + ...options + }; + + set({ + tabs: tabs + }); + syncTabs(); + }, + focusPreviewTab: ( + noteId: string, + options: Omit, "id" | "noteId"> + ) => { + const index = get().tabs.findIndex((t) => t.previewTab); + if (index === -1) return get().newTab(noteId, true); + const tabs = [...get().tabs]; + tabs[index] = { + ...tabs[index], + previewTab: true, + ...options, + noteId: noteId + }; + console.log("focus preview", noteId); + set({ + tabs: tabs, + currentTab: tabs[index].id + }); + + syncTabs(); + }, + removeTab: (id: number) => { + const index = get().tabs.findIndex((t) => t.id === id); + + if (index > -1) { + const isFocused = id === get().currentTab; + const nextTabs = get().tabs.slice(); + nextTabs.splice(index, 1); + + if (nextTabs.length === 0) { + nextTabs.push({ + id: 0 + }); + } + + set({ + tabs: nextTabs, + currentTab: isFocused + ? nextTabs[nextTabs.length - 1].id + : get().currentTab + }); + syncTabs(); + } + }, + newTab: (noteId?: string, previewTab?: boolean) => { + const id = getId(get().tabs.length, get().tabs); + const nextTabs = [ + ...get().tabs, + { + id: id, + noteId, + previewTab: previewTab + } + ]; + set({ + tabs: nextTabs, + currentTab: id + }); + console.log("new tab"); + syncTabs(); + }, + focusEmptyTab: () => { + const index = get().tabs.findIndex((t) => !t.noteId); + if (index === -1) return get().newTab(); + console.log("focus empty tab", get().tabs[index]); + set({ + currentTab: get().tabs[index].id + }); + + syncTabs(); + }, + moveTab: (index: number, toIndex: number) => { + const tabs = get().tabs.slice(); + tabs.splice(toIndex, 0, tabs.slice(index, 1)[0]); + set({ + tabs: tabs + }); + syncTabs(); + }, + focusTab: (id: number) => { + set({ + currentTab: id + }); + syncTabs(); + }, + getNoteIdForTab: (id: number) => { + return get().tabs.find((t) => t.id === id)?.noteId; + }, + hasTabForNote: (noteId: string) => { + return ( + typeof get().tabs.find((t) => t.noteId === noteId)?.id === "number" + ); + }, + getTabForNote: (noteId: string) => { + return get().tabs.find((t) => t.noteId === noteId)?.id; + }, + getCurrentNoteId: () => { + return get().tabs.find((t) => t.id === get().currentTab)?.noteId; + }, + getTab: (tabId) => { + return get().tabs.find((t) => t.id === tabId); + } + }), + { + name: "tabs-storage", + getStorage: () => MMKV as unknown as StateStorage + } + ) +); diff --git a/apps/mobile/app/screens/editor/tiptap/utils.ts b/apps/mobile/app/screens/editor/tiptap/utils.ts index 5ebbefe4f..355fb3562 100644 --- a/apps/mobile/app/screens/editor/tiptap/utils.ts +++ b/apps/mobile/app/screens/editor/tiptap/utils.ts @@ -112,6 +112,25 @@ export const getResponse = async ( }; eSubscribeEvent(type, callback); setTimeout(() => { + eUnSubscribeEvent(type, callback); + resolve(false); + }, waitFor); + }); +}; + +export const waitForEvent = async ( + type: string, + waitFor = 300 +): Promise => { + return new Promise((resolve) => { + const callback = (data: any) => { + eUnSubscribeEvent(type, callback); + resolve(data); + }; + eSubscribeEvent(type, callback); + setTimeout(() => { + console.log("return.."); + eUnSubscribeEvent(type, callback); resolve(false); }, waitFor); }); diff --git a/packages/editor-mobile/src/App.tsx b/packages/editor-mobile/src/App.tsx index 8965b774b..f60d6d3a5 100644 --- a/packages/editor-mobile/src/App.tsx +++ b/packages/editor-mobile/src/App.tsx @@ -40,15 +40,6 @@ function App(): JSX.Element { const tabs = useTabStore((state) => state.tabs); const currentTab = useTabStore((state) => state.currentTab); - useEffect(() => { - post(EventTypes.tabsChanged, { - tabs: tabs, - currentTab: currentTab - }); - }, [tabs, currentTab]); - - logger("info", "opened tabs count", tabs); - return ( diff --git a/packages/editor-mobile/src/components/editor.tsx b/packages/editor-mobile/src/components/editor.tsx index ac36fb71d..d050baf5b 100644 --- a/packages/editor-mobile/src/components/editor.tsx +++ b/packages/editor-mobile/src/components/editor.tsx @@ -135,7 +135,6 @@ const Tiptap = ({ settings }: { settings: Settings }) => { useLayoutEffect(() => { setLayout(true); - const updateScrollPosition = (state: TabStore) => { if (state.currentTab === tab.id) { const position = state.scrollPosition[tab?.id]; @@ -150,19 +149,20 @@ const Tiptap = ({ settings }: { settings: Settings }) => { EventTypes.tabFocused, !!globalThis.editorControllers[tab.id]?.content.current, tab.id, - tab.noteId + state.getCurrentNoteId() ); } }; updateScrollPosition(useTabStore.getState()); - const unsub = useTabStore.subscribe((state) => { + const unsub = useTabStore.subscribe((state, prevState) => { + if (state.currentTab === prevState.currentTab) return; updateScrollPosition(state); }); return () => { unsub(); }; - }, [tab.id, tab.noteId]); + }, [tab.id]); const onClickEmptyArea: React.MouseEventHandler = useCallback( (event) => { diff --git a/packages/editor-mobile/src/components/statusbar.tsx b/packages/editor-mobile/src/components/statusbar.tsx index c465e4e57..03c3ab59e 100644 --- a/packages/editor-mobile/src/components/statusbar.tsx +++ b/packages/editor-mobile/src/components/statusbar.tsx @@ -37,6 +37,7 @@ function StatusBar({ container }: { container: RefObject }) { set: setStatus, updateWords: () => { const editor = editors[tab.id]; + if (!editor) return; const words = getTotalWords(editor as Editor) + " words"; if (currentWords.current === words) return; setWords(words); diff --git a/packages/editor-mobile/src/hooks/useEditorController.ts b/packages/editor-mobile/src/hooks/useEditorController.ts index e6d2be1de..732d8593a 100644 --- a/packages/editor-mobile/src/hooks/useEditorController.ts +++ b/packages/editor-mobile/src/hooks/useEditorController.ts @@ -194,8 +194,7 @@ export function useEditorController(update: () => void): EditorController { const type = message.type; const value = message.value; - if (message.tabId !== tab.id) { - logger("info", "tab id not matched"); + if (message.tabId !== tab.id && type !== "native:status") { return; } @@ -204,7 +203,8 @@ export function useEditorController(update: () => void): EditorController { "webview message for tab", message.type, tab.id, - message.tabId + message.tabId, + useTabStore.getState().currentTab ); const editor = editors[tab.id]; diff --git a/packages/editor-mobile/src/hooks/useTabStore.ts b/packages/editor-mobile/src/hooks/useTabStore.ts index 2c5ad5d80..387050f19 100644 --- a/packages/editor-mobile/src/hooks/useTabStore.ts +++ b/packages/editor-mobile/src/hooks/useTabStore.ts @@ -40,7 +40,7 @@ export type TabStore = { updateTab: (id: number, options: Omit, "id">) => void; removeTab: (index: number) => void; moveTab: (index: number, toIndex: number) => void; - newTab: (noteId?: string) => void; + newTab: (noteId?: string, previewTab?: boolean) => void; focusTab: (id: number) => void; setScrollPosition: (id: number, position: number) => void; getNoteIdForTab: (id: number) => string | undefined; @@ -51,6 +51,8 @@ export type TabStore = { noteId: string, options: Omit, "id"> ) => void; + getCurrentNoteId: () => string | undefined; + getTab: (tabId: number) => TabItem | undefined; }; function getId(id: number, tabs: TabItem[]): number { @@ -85,43 +87,25 @@ export const useTabStore = create( }); }, removeTab: (index: number) => { - const tab = get().tabs.findIndex((t) => t.id === index); - - if (tab > -1) { - const isFocused = get().tabs[tab].id === get().currentTab; - - const nextTabs = get().tabs.slice(); - nextTabs.splice(tab, 1); - - if (nextTabs.length === 0) { - nextTabs.push({ - id: 0 - }); - } - - const scrollPosition = { ...get().scrollPosition }; - if (scrollPosition[get().tabs[tab].id]) { - delete scrollPosition[get().tabs[tab].id]; - } - - globalThis.editorControllers[get().tabs[tab].id] = undefined; - - set({ - tabs: nextTabs, - currentTab: isFocused - ? nextTabs[nextTabs.length - 1].id - : get().currentTab, - scrollPosition - }); + const scrollPosition = { ...get().scrollPosition }; + if (scrollPosition[index]) { + delete scrollPosition[index]; } + globalThis.editorControllers[index] = undefined; + globalThis.editors[index] = null; + + set({ + scrollPosition + }); }, focusPreviewTab: (noteId: string, options) => { const index = get().tabs.findIndex((t) => t.previewTab); - if (index == -1) return get().newTab(noteId); + if (index == -1) return get().newTab(noteId, true); const tabs = [...get().tabs]; tabs[index] = { ...tabs[index], noteId: noteId, + previewTab: true, ...options }; @@ -140,13 +124,14 @@ export const useTabStore = create( currentTab: tabs[index].id }); }, - newTab: (noteId?: string) => { + newTab: (noteId?: string, previewTab?: boolean) => { const id = getId(get().tabs.length, get().tabs); const nextTabs = [ ...get().tabs, { id: id, - noteId + noteId, + previewTab: previewTab } ]; set({ @@ -184,6 +169,12 @@ export const useTabStore = create( }, getTabForNote: (noteId: string) => { return get().tabs.find((t) => t.noteId === noteId)?.id; + }, + getCurrentNoteId: () => { + return get().tabs.find((t) => t.id === get().currentTab)?.noteId; + }, + getTab: (tabId) => { + return get().tabs.find((t) => t.id === tabId); } }), {