import { createContext, Dispatch, FC, PropsWithChildren, SetStateAction, useCallback, useContext, useEffect, useState, } from 'react' import customLocalStorage from '@/infrastructure/local-storage' import getMeta from '@/utils/meta' import { useUnstableStoreSync } from '@/shared/hooks/use-unstable-store-sync' import { sendMB } from '@/infrastructure/event-tracking' import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context' import { getVisualEditorStorageKey } from '@/features/source-editor/utils/visual-editor' // Context value type export type EditorPropertiesContextValue = { showVisual: boolean setShowVisual: Dispatch> showVisualForFile: (filename: string) => boolean showSymbolPalette: boolean setShowSymbolPalette: Dispatch> toggleSymbolPalette: () => void opening: boolean setOpening: Dispatch> trackChanges: boolean setTrackChanges: Dispatch> wantTrackChanges: boolean setWantTrackChanges: Dispatch> errorState: boolean setErrorState: Dispatch> } export const EditorPropertiesContext = createContext< EditorPropertiesContextValue | undefined >(undefined) function migrateTexVisualMode(): boolean { const projectId = getMeta('ol-project_id') const editorModeKey = `editor.mode.${projectId}` const editorModeVal = customLocalStorage.getItem(editorModeKey) if (editorModeVal) { customLocalStorage.removeItem(editorModeKey) return editorModeVal === 'rich-text' } return false } export function showVisualForFile(filename: string): boolean { const key = getVisualEditorStorageKey(filename) const stored = customLocalStorage.getItem(key) if (stored !== null) { return stored === 'visual' } if (key === 'editor.lastUsedMode') { return migrateTexVisualMode() } return false } export const EditorPropertiesProvider: FC = ({ children, }) => { const { openDocName } = useEditorOpenDocContext() const [showVisual, setShowVisualState] = useState(() => openDocName != null ? showVisualForFile(openDocName) : false ) useEffect(() => { setShowVisualState( openDocName != null ? showVisualForFile(openDocName) : false ) }, [openDocName]) const setShowVisual: Dispatch> = useCallback( value => { setShowVisualState(prev => { const actual = typeof value === 'function' ? value(prev) : value if (openDocName != null) { const key = getVisualEditorStorageKey(openDocName) customLocalStorage.setItem(key, actual ? 'visual' : 'code') } return actual }) }, [openDocName] ) // Sync the showVisual state with the exposed store useUnstableStoreSync('editor.showVisual', showVisual) const [showSymbolPalette, setShowSymbolPalette] = useState(false) const toggleSymbolPalette = useCallback(() => { setShowSymbolPalette(show => { const newValue = !show sendMB(newValue ? 'symbol-palette-show' : 'symbol-palette-hide') return newValue }) }, [setShowSymbolPalette]) const [opening, setOpening] = useState(true) const [trackChanges, setTrackChanges] = useState(false) const [wantTrackChanges, setWantTrackChanges] = useState(false) const [errorState, setErrorState] = useState(false) const value = { showVisual, setShowVisual, showVisualForFile, showSymbolPalette, setShowSymbolPalette, toggleSymbolPalette, opening, setOpening, trackChanges, setTrackChanges, wantTrackChanges, setWantTrackChanges, errorState, setErrorState, } return ( {children} ) } export const useEditorPropertiesContext = (): EditorPropertiesContextValue => { const context = useContext(EditorPropertiesContext) if (!context) { throw new Error( 'useEditorPropertiesContext is only available inside EditorPropertiesContext.Provider' ) } return context }