Files
overleaf-cep/services/web/frontend/js/features/ide-react/context/editor-properties-context.tsx
Eric Mc Sween 628e05a278 Merge pull request #32884 from overleaf/em-editor-switch-by-filetype
[web] Split editor mode preference by file type

GitOrigin-RevId: 2574623c9c1c88cc66de72c19cffb4428a632e96
2026-04-21 08:06:23 +00:00

146 lines
4.1 KiB
TypeScript

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<SetStateAction<boolean>>
showVisualForFile: (filename: string) => boolean
showSymbolPalette: boolean
setShowSymbolPalette: Dispatch<SetStateAction<boolean>>
toggleSymbolPalette: () => void
opening: boolean
setOpening: Dispatch<SetStateAction<boolean>>
trackChanges: boolean
setTrackChanges: Dispatch<SetStateAction<boolean>>
wantTrackChanges: boolean
setWantTrackChanges: Dispatch<SetStateAction<boolean>>
errorState: boolean
setErrorState: Dispatch<SetStateAction<boolean>>
}
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<PropsWithChildren> = ({
children,
}) => {
const { openDocName } = useEditorOpenDocContext()
const [showVisual, setShowVisualState] = useState(() =>
openDocName != null ? showVisualForFile(openDocName) : false
)
useEffect(() => {
setShowVisualState(
openDocName != null ? showVisualForFile(openDocName) : false
)
}, [openDocName])
const setShowVisual: Dispatch<SetStateAction<boolean>> = 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 (
<EditorPropertiesContext.Provider value={value}>
{children}
</EditorPropertiesContext.Provider>
)
}
export const useEditorPropertiesContext = (): EditorPropertiesContextValue => {
const context = useContext(EditorPropertiesContext)
if (!context) {
throw new Error(
'useEditorPropertiesContext is only available inside EditorPropertiesContext.Provider'
)
}
return context
}