mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Migrate layout context to TypeScript (#15275)
Migrate layout context to TypeScript GitOrigin-RevId: ce453bfb67f7c36176fa24144413b556cd3c117e
This commit is contained in:
parent
ec085a0807
commit
3be937c503
10 changed files with 80 additions and 109 deletions
|
@ -18,7 +18,7 @@ const MessageList = lazy(() => import('./message-list'))
|
|||
const ChatPane = React.memo(function ChatPane() {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const { chatIsOpen } = useLayoutContext({ chatIsOpen: PropTypes.bool })
|
||||
const { chatIsOpen } = useLayoutContext()
|
||||
const user = useUserContext({
|
||||
id: PropTypes.string.isRequired,
|
||||
})
|
||||
|
|
|
@ -136,7 +136,7 @@ export function ChatProvider({ children }) {
|
|||
_id: PropTypes.string.isRequired,
|
||||
})
|
||||
|
||||
const { chatIsOpen } = useLayoutContext({ chatIsOpen: PropTypes.bool })
|
||||
const { chatIsOpen } = useLayoutContext()
|
||||
|
||||
const {
|
||||
hasFocus: windowHasFocus,
|
||||
|
|
|
@ -12,9 +12,7 @@ export default function SettingsOverallTheme() {
|
|||
const overallThemes = getMeta('ol-overallThemes') as
|
||||
| OverallThemeMeta[]
|
||||
| undefined
|
||||
const { loadingStyleSheet } = useLayoutContext() as {
|
||||
loadingStyleSheet: boolean
|
||||
}
|
||||
const { loadingStyleSheet } = useLayoutContext()
|
||||
const { overallTheme, setOverallTheme } = useProjectSettingsContext()
|
||||
|
||||
const options: Array<Option<OverallTheme>> = useMemo(
|
||||
|
|
|
@ -23,17 +23,6 @@ const editorContextPropTypes = {
|
|||
permissionsLevel: PropTypes.string,
|
||||
}
|
||||
|
||||
const layoutContextPropTypes = {
|
||||
chatIsOpen: PropTypes.bool,
|
||||
setChatIsOpen: PropTypes.func.isRequired,
|
||||
reviewPanelOpen: PropTypes.bool,
|
||||
setReviewPanelOpen: PropTypes.func.isRequired,
|
||||
view: PropTypes.string,
|
||||
setView: PropTypes.func.isRequired,
|
||||
setLeftMenuShown: PropTypes.func.isRequired,
|
||||
pdfLayout: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
const chatContextPropTypes = {
|
||||
markMessagesAsRead: PropTypes.func.isRequired,
|
||||
unreadMessageCount: PropTypes.number.isRequired,
|
||||
|
@ -70,7 +59,7 @@ const EditorNavigationToolbarRoot = React.memo(
|
|||
view,
|
||||
setView,
|
||||
setLeftMenuShown,
|
||||
} = useLayoutContext(layoutContextPropTypes)
|
||||
} = useLayoutContext()
|
||||
|
||||
const { markMessagesAsRead, unreadMessageCount } =
|
||||
useChatContext(chatContextPropTypes)
|
||||
|
|
|
@ -107,7 +107,7 @@ function LayoutDropdownButton() {
|
|||
changeLayout,
|
||||
view,
|
||||
pdfLayout,
|
||||
} = useLayoutContext(layoutContextPropTypes)
|
||||
} = useLayoutContext()
|
||||
|
||||
const handleDetach = useCallback(() => {
|
||||
detach()
|
||||
|
@ -250,13 +250,3 @@ IconCheckmark.propTypes = {
|
|||
view: PropTypes.string,
|
||||
detachRole: PropTypes.string,
|
||||
}
|
||||
|
||||
const layoutContextPropTypes = {
|
||||
reattach: PropTypes.func.isRequired,
|
||||
detach: PropTypes.func.isRequired,
|
||||
changeLayout: PropTypes.func.isRequired,
|
||||
detachIsLinked: PropTypes.bool,
|
||||
detachRole: PropTypes.string,
|
||||
pdfLayout: PropTypes.string.isRequired,
|
||||
view: PropTypes.string,
|
||||
}
|
||||
|
|
|
@ -211,7 +211,7 @@ const editorContextPropTypes = {
|
|||
const isMac = /Mac/.test(window.navigator?.platform)
|
||||
|
||||
export function useSelectableEntity(id, isFile) {
|
||||
const { view, setView } = useLayoutContext(layoutContextPropTypes)
|
||||
const { view, setView } = useLayoutContext()
|
||||
const { setContextMenuCoords } = useFileTreeMainContext()
|
||||
const {
|
||||
selectedEntityIds,
|
||||
|
@ -288,11 +288,6 @@ export function useSelectableEntity(id, isFile) {
|
|||
return { isSelected, props }
|
||||
}
|
||||
|
||||
const layoutContextPropTypes = {
|
||||
view: PropTypes.string,
|
||||
setView: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export function useFileTreeSelectable() {
|
||||
const context = useContext(FileTreeSelectableContext)
|
||||
|
||||
|
|
|
@ -22,7 +22,9 @@ type ConnectionContextValue = {
|
|||
registerUserActivity: () => void
|
||||
}
|
||||
|
||||
const ConnectionContext = createContext<ConnectionContextValue | null>(null)
|
||||
const ConnectionContext = createContext<ConnectionContextValue | undefined>(
|
||||
undefined
|
||||
)
|
||||
|
||||
export const ConnectionProvider: FC = ({ children }) => {
|
||||
const [connectionManager] = useState(() => new ConnectionManager())
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import PropTypes from 'prop-types'
|
||||
import { useLayoutContext } from '../../../shared/context/layout-context'
|
||||
import PdfSynctexControls from './pdf-synctex-controls'
|
||||
|
||||
export function DefaultSynctexControl() {
|
||||
const { detachRole } = useLayoutContext(layoutContextPropTypes)
|
||||
const { detachRole } = useLayoutContext()
|
||||
if (!detachRole) {
|
||||
return <PdfSynctexControls />
|
||||
}
|
||||
|
@ -11,9 +10,7 @@ export function DefaultSynctexControl() {
|
|||
}
|
||||
|
||||
export function DetacherSynctexControl() {
|
||||
const { detachRole, detachIsLinked } = useLayoutContext(
|
||||
layoutContextPropTypes
|
||||
)
|
||||
const { detachRole, detachIsLinked } = useLayoutContext()
|
||||
if (detachRole === 'detacher' && detachIsLinked) {
|
||||
return <PdfSynctexControls />
|
||||
}
|
||||
|
@ -21,16 +18,9 @@ export function DetacherSynctexControl() {
|
|||
}
|
||||
|
||||
export function DetachedSynctexControl() {
|
||||
const { detachRole, detachIsLinked } = useLayoutContext(
|
||||
layoutContextPropTypes
|
||||
)
|
||||
const { detachRole, detachIsLinked } = useLayoutContext()
|
||||
if (detachRole === 'detached' && detachIsLinked) {
|
||||
return <PdfSynctexControls />
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const layoutContextPropTypes = {
|
||||
detachRole: PropTypes.string,
|
||||
detachIsLinked: PropTypes.bool,
|
||||
}
|
||||
|
|
|
@ -4,104 +4,108 @@ import {
|
|||
useCallback,
|
||||
useMemo,
|
||||
useEffect,
|
||||
Dispatch,
|
||||
SetStateAction,
|
||||
FC,
|
||||
} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import useScopeValue from '../hooks/use-scope-value'
|
||||
import useDetachLayout from '../hooks/use-detach-layout'
|
||||
import { useIdeContext } from './ide-context'
|
||||
import localStorage from '../../infrastructure/local-storage'
|
||||
import getMeta from '../../utils/meta'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
import { BinaryFile } from '@/features/file-view/types/binary-file'
|
||||
|
||||
export type IdeLayout = 'sideBySide' | 'flat'
|
||||
export type IdeView = 'editor' | 'file' | 'pdf' | 'history'
|
||||
|
||||
type LayoutContextValue = {
|
||||
reattach: () => void
|
||||
detach: () => void
|
||||
detachIsLinked: boolean
|
||||
detachRole: 'detacher' | 'detached' | null
|
||||
changeLayout: (newLayout: IdeLayout, newView?: IdeView) => void
|
||||
view: IdeView
|
||||
setView: (view: IdeView) => void
|
||||
chatIsOpen: boolean
|
||||
setChatIsOpen: Dispatch<SetStateAction<LayoutContextValue['chatIsOpen']>>
|
||||
reviewPanelOpen: boolean
|
||||
setReviewPanelOpen: Dispatch<
|
||||
SetStateAction<LayoutContextValue['reviewPanelOpen']>
|
||||
>
|
||||
leftMenuShown: boolean
|
||||
setLeftMenuShown: Dispatch<
|
||||
SetStateAction<LayoutContextValue['leftMenuShown']>
|
||||
>
|
||||
loadingStyleSheet: boolean
|
||||
setLoadingStyleSheet: Dispatch<
|
||||
SetStateAction<LayoutContextValue['loadingStyleSheet']>
|
||||
>
|
||||
pdfLayout: IdeLayout
|
||||
pdfPreviewOpen: boolean
|
||||
}
|
||||
|
||||
const debugPdfDetach = getMeta('ol-debugPdfDetach')
|
||||
|
||||
export const LayoutContext = createContext()
|
||||
export const LayoutContext = createContext<LayoutContextValue | undefined>(
|
||||
undefined
|
||||
)
|
||||
|
||||
LayoutContext.Provider.propTypes = {
|
||||
value: PropTypes.shape({
|
||||
reattach: PropTypes.func.isRequired,
|
||||
detach: PropTypes.func.isRequired,
|
||||
detachIsLinked: PropTypes.bool,
|
||||
detachRole: PropTypes.string,
|
||||
changeLayout: PropTypes.func.isRequired,
|
||||
view: PropTypes.oneOf(['editor', 'file', 'pdf', 'history']),
|
||||
setView: PropTypes.func.isRequired,
|
||||
chatIsOpen: PropTypes.bool,
|
||||
setChatIsOpen: PropTypes.func.isRequired,
|
||||
reviewPanelOpen: PropTypes.bool,
|
||||
setReviewPanelOpen: PropTypes.func.isRequired,
|
||||
leftMenuShown: PropTypes.bool,
|
||||
setLeftMenuShown: PropTypes.func.isRequired,
|
||||
pdfLayout: PropTypes.oneOf(['sideBySide', 'flat']).isRequired,
|
||||
pdfPreviewOpen: PropTypes.bool,
|
||||
}).isRequired,
|
||||
}
|
||||
|
||||
function setLayoutInLocalStorage(pdfLayout) {
|
||||
function setLayoutInLocalStorage(pdfLayout: IdeLayout) {
|
||||
localStorage.setItem(
|
||||
'pdf.layout',
|
||||
pdfLayout === 'sideBySide' ? 'split' : 'flat'
|
||||
)
|
||||
}
|
||||
|
||||
export function LayoutProvider({ children }) {
|
||||
const { $scope } = useIdeContext()
|
||||
|
||||
export const LayoutProvider: FC = ({ children }) => {
|
||||
// what to show in the "flat" view (editor or pdf)
|
||||
const [view, _setView] = useScopeValue('ui.view')
|
||||
const [view, _setView] = useScopeValue<IdeView>('ui.view')
|
||||
const [toggleHistory] = useScopeValue<() => void>('toggleHistory')
|
||||
const [openFile] = useScopeValue<BinaryFile | null>('openFile')
|
||||
|
||||
const setView = useCallback(
|
||||
value => {
|
||||
(value: IdeView) => {
|
||||
_setView(oldValue => {
|
||||
// ensure that the "history:toggle" event is broadcast when switching in or out of history view
|
||||
if (value === 'history' || oldValue === 'history') {
|
||||
$scope.toggleHistory()
|
||||
toggleHistory()
|
||||
}
|
||||
|
||||
if (value === 'editor' && $scope.openFile) {
|
||||
if (value === 'editor' && openFile) {
|
||||
// if a file is currently opened, ensure the view is 'file' instead of
|
||||
// 'editor' when the 'editor' view is requested. This is to ensure
|
||||
// that the entity selected in the file tree is the one visible and
|
||||
// that docs don't take precendence over files.
|
||||
// that docs don't take precedence over files.
|
||||
return 'file'
|
||||
}
|
||||
|
||||
return value
|
||||
})
|
||||
},
|
||||
[$scope, _setView]
|
||||
[_setView, openFile, toggleHistory]
|
||||
)
|
||||
|
||||
// whether the chat pane is open
|
||||
const [chatIsOpen, setChatIsOpen] = useScopeValue('ui.chatOpen')
|
||||
const [chatIsOpen, setChatIsOpen] = useScopeValue<boolean>('ui.chatOpen')
|
||||
|
||||
// whether the review pane is open
|
||||
const [reviewPanelOpen, setReviewPanelOpen] =
|
||||
useScopeValue('ui.reviewPanelOpen')
|
||||
|
||||
// whether the menu pane is open
|
||||
const [leftMenuShown, setLeftMenuShown] = useScopeValue('ui.leftMenuShown')
|
||||
const [leftMenuShown, setLeftMenuShown] =
|
||||
useScopeValue<boolean>('ui.leftMenuShown')
|
||||
|
||||
// whether to display the editor and preview side-by-side or full-width ("flat")
|
||||
const [pdfLayout, setPdfLayout] = useScopeValue('ui.pdfLayout')
|
||||
const [pdfLayout, setPdfLayout] = useScopeValue<IdeLayout>('ui.pdfLayout')
|
||||
|
||||
// whether stylesheet on theme is loading
|
||||
const [loadingStyleSheet, setLoadingStyleSheet] = useScopeValue(
|
||||
const [loadingStyleSheet, setLoadingStyleSheet] = useScopeValue<boolean>(
|
||||
'ui.loadingStyleSheet'
|
||||
)
|
||||
|
||||
// switch to either side-by-side or flat (full-width) layout
|
||||
const switchLayout = useCallback(() => {
|
||||
setPdfLayout(layout => {
|
||||
const newLayout = layout === 'sideBySide' ? 'flat' : 'sideBySide'
|
||||
setView(newLayout === 'sideBySide' ? 'editor' : 'pdf')
|
||||
setPdfLayout(newLayout)
|
||||
setLayoutInLocalStorage(newLayout)
|
||||
})
|
||||
}, [setPdfLayout, setView])
|
||||
|
||||
const changeLayout = useCallback(
|
||||
(newLayout, newView) => {
|
||||
(newLayout: IdeLayout, newView: IdeView = 'editor') => {
|
||||
setPdfLayout(newLayout)
|
||||
setView(newLayout === 'sideBySide' ? 'editor' : newView)
|
||||
setLayoutInLocalStorage(newLayout)
|
||||
|
@ -151,7 +155,7 @@ export function LayoutProvider({ children }) {
|
|||
changeLayout,
|
||||
])
|
||||
|
||||
const value = useMemo(
|
||||
const value = useMemo<LayoutContextValue>(
|
||||
() => ({
|
||||
reattach,
|
||||
detach,
|
||||
|
@ -170,7 +174,6 @@ export function LayoutProvider({ children }) {
|
|||
setReviewPanelOpen,
|
||||
setLoadingStyleSheet,
|
||||
setView,
|
||||
switchLayout,
|
||||
view,
|
||||
}),
|
||||
[
|
||||
|
@ -191,7 +194,6 @@ export function LayoutProvider({ children }) {
|
|||
setReviewPanelOpen,
|
||||
setLoadingStyleSheet,
|
||||
setView,
|
||||
switchLayout,
|
||||
view,
|
||||
]
|
||||
)
|
||||
|
@ -201,12 +203,10 @@ export function LayoutProvider({ children }) {
|
|||
)
|
||||
}
|
||||
|
||||
LayoutProvider.propTypes = {
|
||||
children: PropTypes.any,
|
||||
}
|
||||
|
||||
export function useLayoutContext(propTypes) {
|
||||
const data = useContext(LayoutContext)
|
||||
PropTypes.checkPropTypes(propTypes, data, 'data', 'LayoutContext.Provider')
|
||||
return data
|
||||
export function useLayoutContext() {
|
||||
const context = useContext(LayoutContext)
|
||||
if (!context) {
|
||||
throw new Error('useLayoutContext is only available inside LayoutProvider')
|
||||
}
|
||||
return context
|
||||
}
|
|
@ -2,7 +2,11 @@ import localStorage from '../../../../frontend/js/infrastructure/local-storage'
|
|||
import PdfPreview from '../../../../frontend/js/features/pdf-preview/components/pdf-preview'
|
||||
import { EditorProviders } from '../../helpers/editor-providers'
|
||||
import { mockScope } from './scope'
|
||||
import { useLayoutContext } from '../../../../frontend/js/shared/context/layout-context'
|
||||
import {
|
||||
IdeLayout,
|
||||
IdeView,
|
||||
useLayoutContext,
|
||||
} from '../../../../frontend/js/shared/context/layout-context'
|
||||
import { FC, useEffect } from 'react'
|
||||
|
||||
const storeAndFireEvent = (win: typeof window, key: string, value: unknown) => {
|
||||
|
@ -10,7 +14,10 @@ const storeAndFireEvent = (win: typeof window, key: string, value: unknown) => {
|
|||
win.dispatchEvent(new StorageEvent('storage', { key }))
|
||||
}
|
||||
|
||||
const Layout: FC<{ layout: string; view?: string }> = ({ layout, view }) => {
|
||||
const Layout: FC<{ layout: IdeLayout; view?: IdeView }> = ({
|
||||
layout,
|
||||
view,
|
||||
}) => {
|
||||
const { changeLayout } = useLayoutContext()
|
||||
|
||||
useEffect(() => {
|
||||
|
|
Loading…
Reference in a new issue