mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-06-02 05:41:33 +02:00
Merge pull request #23940 from overleaf/td-react-18
Upgrade to React 18 GitOrigin-RevId: 9b81936e6eea2bccd97fe5c2c5841f0b946371b8
This commit is contained in:
Generated
+1179
-1101
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
import { mount } from 'cypress/react'
|
||||
import { mount } from 'cypress/react18'
|
||||
|
||||
// eslint-disable-next-line no-unused-vars,@typescript-eslint/no-namespace
|
||||
declare global {
|
||||
|
||||
@@ -190,7 +190,7 @@ export const ChatContext = createContext<
|
||||
| undefined
|
||||
>(undefined)
|
||||
|
||||
export const ChatProvider: FC = ({ children }) => {
|
||||
export const ChatProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const chatEnabled = getMeta('ol-chatEnabled')
|
||||
|
||||
const clientId = useRef<string>()
|
||||
@@ -283,7 +283,7 @@ export const ChatProvider: FC = ({ children }) => {
|
||||
])
|
||||
|
||||
const sendMessage = useCallback(
|
||||
content => {
|
||||
(content: string) => {
|
||||
if (!chatEnabled) {
|
||||
debugConsole.warn(`chat is disabled, won't send message`)
|
||||
return
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ export default function DictionaryModalContent({
|
||||
const { isError, runAsync } = useAsync()
|
||||
|
||||
const handleRemove = useCallback(
|
||||
word => {
|
||||
(word: string) => {
|
||||
runAsync(postJSON('/spelling/unlearn', { body: { word } }))
|
||||
.then(() => {
|
||||
setLearnedWords(prevLearnedWords => {
|
||||
|
||||
+5
-3
@@ -9,17 +9,19 @@ export const EditorLeftMenuContext = createContext<
|
||||
EditorLeftMenuState | undefined
|
||||
>(undefined)
|
||||
|
||||
export const EditorLeftMenuProvider: FC = ({ children }) => {
|
||||
export const EditorLeftMenuProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [value, setValue] = useState<EditorLeftMenuState>(() => ({
|
||||
settingToFocus: undefined,
|
||||
}))
|
||||
|
||||
useEventListener(
|
||||
'ui.focus-setting',
|
||||
useCallback(event => {
|
||||
useCallback((event: CustomEvent<string>) => {
|
||||
setValue(value => ({
|
||||
...value,
|
||||
settingToFocus: (event as CustomEvent<string>).detail,
|
||||
settingToFocus: event.detail,
|
||||
}))
|
||||
}, [])
|
||||
)
|
||||
|
||||
+3
-1
@@ -37,7 +37,9 @@ export const ProjectSettingsContext = createContext<
|
||||
ProjectSettingsContextValue | undefined
|
||||
>(undefined)
|
||||
|
||||
export const ProjectSettingsProvider: FC = ({ children }) => {
|
||||
export const ProjectSettingsProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const {
|
||||
compiler,
|
||||
setCompiler,
|
||||
|
||||
+2
-2
@@ -56,7 +56,7 @@ const EditorNavigationToolbarRoot = React.memo(
|
||||
}, [chatIsOpen, setChatIsOpen, markMessagesAsRead])
|
||||
|
||||
const toggleReviewPanelOpen = useCallback(
|
||||
event => {
|
||||
(event: any) => {
|
||||
event.preventDefault()
|
||||
eventTracking.sendMB('navigation-clicked-review', {
|
||||
action: isOpentoString(!reviewPanelOpen),
|
||||
@@ -93,7 +93,7 @@ const EditorNavigationToolbarRoot = React.memo(
|
||||
}, [setLeftMenuShown])
|
||||
|
||||
const goToUser = useCallback(
|
||||
user => {
|
||||
(user: any) => {
|
||||
if (user.doc && typeof user.row === 'number') {
|
||||
openDoc(user.doc, { gotoLine: user.row + 1 })
|
||||
}
|
||||
|
||||
@@ -9,13 +9,15 @@ import { FC } from 'react'
|
||||
// FileTreeActionable: global UI state for actions (rename, delete, etc.)
|
||||
// FileTreeMutable: provides entities mutation operations
|
||||
// FileTreeSelectable: handles selection and multi-selection
|
||||
const FileTreeContext: FC<{
|
||||
refProviders: Record<string, boolean>
|
||||
setRefProviderEnabled: (provider: string, value: boolean) => void
|
||||
setStartedFreeTrial: (value: boolean) => void
|
||||
onSelect: () => void
|
||||
fileTreeContainer?: HTMLDivElement
|
||||
}> = ({
|
||||
const FileTreeContext: FC<
|
||||
React.PropsWithChildren<{
|
||||
refProviders: Record<string, boolean>
|
||||
setRefProviderEnabled: (provider: string, value: boolean) => void
|
||||
setStartedFreeTrial: (value: boolean) => void
|
||||
onSelect: () => void
|
||||
fileTreeContainer?: HTMLDivElement
|
||||
}>
|
||||
> = ({
|
||||
refProviders,
|
||||
setRefProviderEnabled,
|
||||
setStartedFreeTrial,
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ export default function FileTreeImportFromProject() {
|
||||
|
||||
// use the basename of a path as the file name
|
||||
const setNameFromPath = useCallback(
|
||||
path => {
|
||||
(path: string) => {
|
||||
const filename = path.split('/').pop()
|
||||
|
||||
if (filename) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useFileTreeSelectable } from '../contexts/file-tree-selectable'
|
||||
import { FC, useCallback } from 'react'
|
||||
|
||||
const FileTreeInner: FC = ({ children }) => {
|
||||
const FileTreeInner: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const { setIsRootFolderSelected, selectedEntityIds, select } =
|
||||
useFileTreeSelectable()
|
||||
|
||||
|
||||
@@ -218,7 +218,9 @@ function fileTreeActionableReducer(state: State, action: Action) {
|
||||
}
|
||||
}
|
||||
|
||||
export const FileTreeActionableProvider: FC = ({ children }) => {
|
||||
export const FileTreeActionableProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { _id: projectId } = useProjectContext()
|
||||
const { fileTreeReadOnly } = useFileTreeData()
|
||||
const { indexAllReferences } = useReferencesContext()
|
||||
@@ -400,7 +402,7 @@ export const FileTreeActionableProvider: FC = ({ children }) => {
|
||||
}, [fileTreeData, selectedEntityIds])
|
||||
|
||||
const finishCreatingEntity = useCallback(
|
||||
entity => {
|
||||
(entity: any) => {
|
||||
const error = validateCreate(fileTreeData, parentFolderId, entity)
|
||||
if (error) {
|
||||
return Promise.reject(error)
|
||||
@@ -412,7 +414,7 @@ export const FileTreeActionableProvider: FC = ({ children }) => {
|
||||
)
|
||||
|
||||
const finishCreatingFolder = useCallback(
|
||||
name => {
|
||||
(name: any) => {
|
||||
dispatch({ type: ACTION_TYPES.CREATING_FOLDER })
|
||||
return finishCreatingEntity({ endpoint: 'folder', name })
|
||||
.then(() => {
|
||||
@@ -425,7 +427,7 @@ export const FileTreeActionableProvider: FC = ({ children }) => {
|
||||
[finishCreatingEntity]
|
||||
)
|
||||
|
||||
const startCreatingFile = useCallback(newFileCreateMode => {
|
||||
const startCreatingFile = useCallback((newFileCreateMode: any) => {
|
||||
dispatch({ type: ACTION_TYPES.START_CREATE_FILE, newFileCreateMode })
|
||||
}, [])
|
||||
|
||||
@@ -438,7 +440,7 @@ export const FileTreeActionableProvider: FC = ({ children }) => {
|
||||
}, [startCreatingFile])
|
||||
|
||||
const finishCreatingDocOrFile = useCallback(
|
||||
entity => {
|
||||
(entity: any) => {
|
||||
dispatch({ type: ACTION_TYPES.CREATING_FILE })
|
||||
|
||||
return finishCreatingEntity(entity)
|
||||
@@ -453,7 +455,7 @@ export const FileTreeActionableProvider: FC = ({ children }) => {
|
||||
)
|
||||
|
||||
const finishCreatingDoc = useCallback(
|
||||
entity => {
|
||||
(entity: any) => {
|
||||
entity.endpoint = 'doc'
|
||||
return finishCreatingDocOrFile(entity)
|
||||
},
|
||||
@@ -461,7 +463,7 @@ export const FileTreeActionableProvider: FC = ({ children }) => {
|
||||
)
|
||||
|
||||
const finishCreatingLinkedFile = useCallback(
|
||||
entity => {
|
||||
(entity: any) => {
|
||||
entity.endpoint = 'linked_file'
|
||||
return finishCreatingDocOrFile(entity)
|
||||
},
|
||||
|
||||
@@ -16,7 +16,9 @@ export const useFileTreeCreateForm = () => {
|
||||
return context
|
||||
}
|
||||
|
||||
const FileTreeCreateFormProvider: FC = ({ children }) => {
|
||||
const FileTreeCreateFormProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
// is the form valid
|
||||
const [valid, setValid] = useState(false)
|
||||
|
||||
|
||||
@@ -28,10 +28,9 @@ type State = {
|
||||
touchedName: boolean
|
||||
}
|
||||
|
||||
const FileTreeCreateNameProvider: FC<{ initialName?: string }> = ({
|
||||
children,
|
||||
initialName = '',
|
||||
}) => {
|
||||
const FileTreeCreateNameProvider: FC<
|
||||
React.PropsWithChildren<{ initialName?: string }>
|
||||
> = ({ children, initialName = '' }) => {
|
||||
const [state, setName] = useReducer(
|
||||
(state: State, name: string) => ({
|
||||
name, // the file name
|
||||
|
||||
@@ -18,9 +18,11 @@ import { isAcceptableFile } from '@/features/file-tree/util/is-acceptable-file'
|
||||
import { FileTreeFindResult } from '@/features/ide-react/types/file-tree'
|
||||
|
||||
const DRAGGABLE_TYPE = 'ENTITY'
|
||||
export const FileTreeDraggableProvider: FC<{
|
||||
fileTreeContainer?: HTMLDivElement
|
||||
}> = ({ fileTreeContainer, children }) => {
|
||||
export const FileTreeDraggableProvider: FC<
|
||||
React.PropsWithChildren<{
|
||||
fileTreeContainer?: HTMLDivElement
|
||||
}>
|
||||
> = ({ fileTreeContainer, children }) => {
|
||||
const options = useMemo(
|
||||
() => ({ rootElement: fileTreeContainer }),
|
||||
[fileTreeContainer]
|
||||
|
||||
@@ -25,11 +25,13 @@ export function useFileTreeMainContext() {
|
||||
return context
|
||||
}
|
||||
|
||||
export const FileTreeMainProvider: FC<{
|
||||
refProviders: object
|
||||
setRefProviderEnabled: (provider: string, value: boolean) => void
|
||||
setStartedFreeTrial: (value: boolean) => void
|
||||
}> = ({
|
||||
export const FileTreeMainProvider: FC<
|
||||
React.PropsWithChildren<{
|
||||
refProviders: object
|
||||
setRefProviderEnabled: (provider: string, value: boolean) => void
|
||||
setStartedFreeTrial: (value: boolean) => void
|
||||
}>
|
||||
> = ({
|
||||
refProviders,
|
||||
setRefProviderEnabled,
|
||||
setStartedFreeTrial,
|
||||
|
||||
@@ -22,7 +22,9 @@ export const FileTreePathContext = createContext<
|
||||
FileTreePathContextValue | undefined
|
||||
>(undefined)
|
||||
|
||||
export const FileTreePathProvider: FC = ({ children }) => {
|
||||
export const FileTreePathProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { fileTreeData }: { fileTreeData: Folder } = useFileTreeData()
|
||||
const projectId = getMeta('ol-project_id')
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// TODO: The types in this file have mismatches between string and string[] and
|
||||
// it's not immediately clear how to resolve it. I've therefore left in a bunch
|
||||
// of `any` types. We should fix this.
|
||||
import {
|
||||
createContext,
|
||||
useCallback,
|
||||
@@ -120,9 +123,11 @@ function fileTreeSelectableReadOnlyReducer(
|
||||
}
|
||||
}
|
||||
|
||||
export const FileTreeSelectableProvider: FC<{
|
||||
onSelect: (value: FindResult[]) => void
|
||||
}> = ({ onSelect, children }) => {
|
||||
export const FileTreeSelectableProvider: FC<
|
||||
React.PropsWithChildren<{
|
||||
onSelect: (value: FindResult[]) => void
|
||||
}>
|
||||
> = ({ onSelect, children }) => {
|
||||
const { _id: projectId, rootDocId } = useProjectContext()
|
||||
|
||||
const [initialSelectedEntityId] = usePersistedState(
|
||||
@@ -206,21 +211,24 @@ export const FileTreeSelectableProvider: FC<{
|
||||
)
|
||||
)
|
||||
|
||||
const select = useCallback(id => {
|
||||
const select = useCallback((id: any) => {
|
||||
dispatch({ type: ACTION_TYPES.SELECT, id })
|
||||
}, [])
|
||||
|
||||
const unselect = useCallback(id => {
|
||||
const unselect = useCallback((id: any) => {
|
||||
dispatch({ type: ACTION_TYPES.UNSELECT, id })
|
||||
}, [])
|
||||
|
||||
const selectOrMultiSelectEntity = useCallback((id, isMultiSelect) => {
|
||||
const actionType = isMultiSelect
|
||||
? ACTION_TYPES.MULTI_SELECT
|
||||
: ACTION_TYPES.SELECT
|
||||
const selectOrMultiSelectEntity = useCallback(
|
||||
(id: any, isMultiSelect: any) => {
|
||||
const actionType = isMultiSelect
|
||||
? ACTION_TYPES.MULTI_SELECT
|
||||
: ACTION_TYPES.SELECT
|
||||
|
||||
dispatch({ type: actionType, id })
|
||||
}, [])
|
||||
dispatch({ type: actionType, id })
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
// TODO: wrap in useMemo
|
||||
const value = {
|
||||
@@ -254,7 +262,7 @@ export function useSelectableEntity(id: string, type: string) {
|
||||
const isSelected = selectedEntityIds.has(id)
|
||||
|
||||
const buildSelectedRange = useCallback(
|
||||
id => {
|
||||
(id: string) => {
|
||||
const selected = []
|
||||
|
||||
let started = false
|
||||
@@ -306,7 +314,7 @@ export function useSelectableEntity(id: string, type: string) {
|
||||
}, [fileTreeData, selectedEntityIds, view])
|
||||
|
||||
const handleEvent = useCallback(
|
||||
ev => {
|
||||
(ev: any) => {
|
||||
ev.stopPropagation()
|
||||
// use Command (macOS) or Ctrl (other OS) to select multiple items,
|
||||
// as long as the root folder wasn't selected
|
||||
@@ -342,7 +350,7 @@ export function useSelectableEntity(id: string, type: string) {
|
||||
)
|
||||
|
||||
const handleClick = useCallback(
|
||||
ev => {
|
||||
(ev: any) => {
|
||||
handleEvent(ev)
|
||||
if (!ev.ctrlKey && !ev.metaKey) {
|
||||
setContextMenuCoords(null)
|
||||
@@ -352,7 +360,7 @@ export function useSelectableEntity(id: string, type: string) {
|
||||
)
|
||||
|
||||
const handleKeyPress = useCallback(
|
||||
ev => {
|
||||
(ev: any) => {
|
||||
if (ev.key === 'Enter' || ev.key === ' ') {
|
||||
handleEvent(ev)
|
||||
}
|
||||
@@ -361,7 +369,7 @@ export function useSelectableEntity(id: string, type: string) {
|
||||
)
|
||||
|
||||
const handleContextMenu = useCallback(
|
||||
ev => {
|
||||
(ev: any) => {
|
||||
// make sure the right-clicked entity gets selected
|
||||
if (!selectedEntityIds.has(id)) {
|
||||
handleEvent(ev)
|
||||
|
||||
@@ -25,7 +25,7 @@ export function useFileTreeSocketListener(onDelete: (entity: any) => void) {
|
||||
|
||||
const selectEntityIfCreatedByUser = useCallback(
|
||||
// hack to automatically re-open refreshed linked files
|
||||
(entityId, entityName, userId) => {
|
||||
(entityId: any, entityName: any, userId: string) => {
|
||||
// If the created entity's user exists and is the current user
|
||||
if (userId && user?.id === userId) {
|
||||
// And we're expecting a refreshed socket for this entity
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import React, { ChangeEvent, useCallback, useState } from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import useWaitForI18n from '../../../shared/hooks/use-wait-for-i18n'
|
||||
import getMeta from '../../../utils/meta'
|
||||
@@ -37,7 +37,7 @@ export default function GroupMembers() {
|
||||
const canUseAddSeatsFeature = getMeta('ol-canUseAddSeatsFeature')
|
||||
|
||||
const handleEmailsChange = useCallback(
|
||||
e => {
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
setEmailString(e.target.value)
|
||||
},
|
||||
[setEmailString]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useState } from 'react'
|
||||
import { ChangeEvent, FormEvent, useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { deleteJSON, FetchError, postJSON } from '@/infrastructure/fetch-json'
|
||||
import getMeta from '../../../utils/meta'
|
||||
@@ -58,7 +58,7 @@ export function ManagersTable({
|
||||
const [removeMemberError, setRemoveMemberError] = useState<APIError>()
|
||||
|
||||
const addManagers = useCallback(
|
||||
e => {
|
||||
(e: FormEvent | React.MouseEvent) => {
|
||||
e.preventDefault()
|
||||
setInviteError(undefined)
|
||||
const emails = parseEmails(emailString)
|
||||
@@ -92,7 +92,7 @@ export function ManagersTable({
|
||||
)
|
||||
|
||||
const removeManagers = useCallback(
|
||||
e => {
|
||||
(e: React.MouseEvent) => {
|
||||
e.preventDefault()
|
||||
setRemoveMemberError(undefined)
|
||||
;(async () => {
|
||||
@@ -131,7 +131,7 @@ export function ManagersTable({
|
||||
)
|
||||
|
||||
const handleEmailsChange = useCallback(
|
||||
e => {
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
setEmailString(e.target.value)
|
||||
},
|
||||
[setEmailString]
|
||||
|
||||
+3
-3
@@ -64,7 +64,7 @@ export default function DropdownButton({
|
||||
const isUserManaged = !userPending && user.enrollment?.managedBy === groupId
|
||||
|
||||
const handleResendManagedUserInvite = useCallback(
|
||||
async user => {
|
||||
async (user: User) => {
|
||||
try {
|
||||
const result = await runResendManagedUserInviteAsync(
|
||||
postJSON(
|
||||
@@ -96,7 +96,7 @@ export default function DropdownButton({
|
||||
)
|
||||
|
||||
const handleResendLinkSSOInviteAsync = useCallback(
|
||||
async user => {
|
||||
async (user: User) => {
|
||||
try {
|
||||
const result = await runResendLinkSSOInviteAsync(
|
||||
postJSON(`/manage/groups/${groupId}/resendSSOLinkInvite/${user._id}`)
|
||||
@@ -126,7 +126,7 @@ export default function DropdownButton({
|
||||
)
|
||||
|
||||
const handleResendGroupInvite = useCallback(
|
||||
async user => {
|
||||
async (user: User) => {
|
||||
try {
|
||||
await runResendGroupInviteAsync(
|
||||
postJSON(`/manage/groups/${groupId}/resendInvite/`, {
|
||||
|
||||
-1
@@ -101,7 +101,6 @@ export default function OffboardManagedUserModal({
|
||||
<OLFormSelect
|
||||
aria-label={t('select_user')}
|
||||
required
|
||||
placeholder={t('choose_from_group_members')}
|
||||
value={selectedRecipientId || ''}
|
||||
onChange={e => setSelectedRecipientId(e.target.value)}
|
||||
>
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ export default function SelectUserCheckbox({
|
||||
useGroupMembersContext()
|
||||
|
||||
const handleSelectUser = useCallback(
|
||||
(event, user) => {
|
||||
(event: React.ChangeEvent<HTMLInputElement>, user: User) => {
|
||||
if (event.target.checked) {
|
||||
selectUser(user)
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ export default function UnlinkUserModal({
|
||||
}, [groupId, updateMemberView, user])
|
||||
|
||||
const handleUnlink = useCallback(
|
||||
event => {
|
||||
(event: React.MouseEvent) => {
|
||||
event.preventDefault()
|
||||
setHasError(undefined)
|
||||
if (!user) {
|
||||
|
||||
@@ -21,7 +21,7 @@ export default function UserRow({
|
||||
const { t } = useTranslation()
|
||||
|
||||
const handleSelectUser = useCallback(
|
||||
(event, user) => {
|
||||
(event: React.ChangeEvent<HTMLInputElement>, user: User) => {
|
||||
if (event.target.checked) {
|
||||
selectUser(user)
|
||||
} else {
|
||||
|
||||
+4
-4
@@ -72,7 +72,7 @@ export function GroupMembersProvider({ children }: GroupMembersProviderProps) {
|
||||
)
|
||||
|
||||
const addMembers = useCallback(
|
||||
emailString => {
|
||||
(emailString: string) => {
|
||||
setInviteError(undefined)
|
||||
const emails = parseEmails(emailString)
|
||||
mapSeries(emails, async email => {
|
||||
@@ -102,7 +102,7 @@ export function GroupMembersProvider({ children }: GroupMembersProviderProps) {
|
||||
)
|
||||
|
||||
const removeMember = useCallback(
|
||||
async user => {
|
||||
async (user: User) => {
|
||||
let url
|
||||
if (paths.removeInvite && user.invite && user._id == null) {
|
||||
url = `${paths.removeInvite}/${encodeURIComponent(user.email)}`
|
||||
@@ -126,7 +126,7 @@ export function GroupMembersProvider({ children }: GroupMembersProviderProps) {
|
||||
)
|
||||
|
||||
const removeMembers = useCallback(
|
||||
e => {
|
||||
(e: any) => {
|
||||
e.preventDefault()
|
||||
setRemoveMemberError(undefined)
|
||||
;(async () => {
|
||||
@@ -142,7 +142,7 @@ export function GroupMembersProvider({ children }: GroupMembersProviderProps) {
|
||||
)
|
||||
|
||||
const updateMemberView = useCallback(
|
||||
(userId, updatedUser) => {
|
||||
(userId: string, updatedUser: User) => {
|
||||
setUsers(
|
||||
users.map(u => {
|
||||
if (u._id === userId) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ReactDOM from 'react-dom'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import getMeta from '@/utils/meta'
|
||||
import DefaultNavbar from '@/features/ui/components/bootstrap-5/navbar/default-navbar'
|
||||
import Footer from '@/features/ui/components/bootstrap-5/footer/footer'
|
||||
@@ -7,16 +7,17 @@ import { SplitTestProvider } from '@/shared/context/split-test-context'
|
||||
const navbarElement = document.getElementById('navbar-container')
|
||||
if (navbarElement) {
|
||||
const navbarProps = getMeta('ol-navbar')
|
||||
ReactDOM.render(
|
||||
const root = createRoot(navbarElement)
|
||||
root.render(
|
||||
<SplitTestProvider>
|
||||
<DefaultNavbar {...navbarProps} />
|
||||
</SplitTestProvider>,
|
||||
navbarElement
|
||||
</SplitTestProvider>
|
||||
)
|
||||
}
|
||||
|
||||
const footerElement = document.getElementById('footer-container')
|
||||
if (footerElement) {
|
||||
const footerProps = getMeta('ol-footer')
|
||||
ReactDOM.render(<Footer {...footerProps} />, footerElement)
|
||||
const root = createRoot(footerElement)
|
||||
root.render(<Footer {...footerProps} />)
|
||||
}
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ function DocumentDiffViewer({
|
||||
|
||||
// Append the editor view DOM to the container node when mounted
|
||||
const containerRef = useCallback(
|
||||
node => {
|
||||
(node: HTMLDivElement) => {
|
||||
if (node) {
|
||||
node.appendChild(view.dom)
|
||||
}
|
||||
|
||||
@@ -15,4 +15,6 @@ const IdeRoot: FC = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export default withErrorBoundary(memo(IdeRoot), GenericErrorBoundaryFallback)
|
||||
export default withErrorBoundary(memo(IdeRoot), () => (
|
||||
<GenericErrorBoundaryFallback />
|
||||
))
|
||||
|
||||
+3
-1
@@ -10,7 +10,9 @@ type HorizontalResizeHandleOwnProps = {
|
||||
}
|
||||
|
||||
export const HorizontalResizeHandle: FC<
|
||||
HorizontalResizeHandleOwnProps & PanelResizeHandleProps
|
||||
React.PropsWithChildren<
|
||||
HorizontalResizeHandleOwnProps & PanelResizeHandleProps
|
||||
>
|
||||
> = ({ children, resizable = true, onDoubleClick, ...props }) => {
|
||||
const { t } = useTranslation()
|
||||
const [isDragging, setIsDragging] = useState(false)
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ export const UnsavedDocs: FC = () => {
|
||||
useEventListener(
|
||||
'beforeunload',
|
||||
useCallback(
|
||||
event => {
|
||||
(event: BeforeUnloadEvent) => {
|
||||
if (openDocs.hasUnsavedChanges()) {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
|
||||
event.preventDefault()
|
||||
|
||||
@@ -23,7 +23,9 @@ type CommandRegistry = {
|
||||
unregister: (...id: string[]) => void
|
||||
}
|
||||
|
||||
export const CommandRegistryProvider: React.FC = ({ children }) => {
|
||||
export const CommandRegistryProvider: React.FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [registry, setRegistry] = useState(new Map<string, Command>())
|
||||
const register = useCallback((...elements: Command[]) => {
|
||||
setRegistry(
|
||||
|
||||
@@ -36,7 +36,9 @@ export const ConnectionContext = createContext<
|
||||
ConnectionContextValue | undefined
|
||||
>(undefined)
|
||||
|
||||
export const ConnectionProvider: FC = ({ children }) => {
|
||||
export const ConnectionProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const location = useLocation()
|
||||
|
||||
const [connectionManager] = useState(() => new ConnectionManager())
|
||||
|
||||
@@ -88,7 +88,9 @@ export const EditorManagerContext = createContext<EditorManager | undefined>(
|
||||
undefined
|
||||
)
|
||||
|
||||
export const EditorManagerProvider: FC = ({ children }) => {
|
||||
export const EditorManagerProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { scopeStore } = useIdeContext()
|
||||
const { reportError, eventEmitter, projectId } = useIdeReactContext()
|
||||
|
||||
@@ -36,7 +36,9 @@ const FileTreeOpenContext = createContext<
|
||||
| undefined
|
||||
>(undefined)
|
||||
|
||||
export const FileTreeOpenProvider: FC = ({ children }) => {
|
||||
export const FileTreeOpenProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { rootDocId, owner } = useProjectContext()
|
||||
const { eventEmitter, projectJoined } = useIdeReactContext()
|
||||
const { openDocWithId, currentDocumentId, openInitialDoc } =
|
||||
|
||||
@@ -4,7 +4,9 @@ const GlobalAlertsContext = createContext<HTMLDivElement | null | undefined>(
|
||||
undefined
|
||||
)
|
||||
|
||||
export const GlobalAlertsProvider: FC = ({ children }) => {
|
||||
export const GlobalAlertsProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [globalAlertsContainer, setGlobalAlertsContainer] =
|
||||
useState<HTMLDivElement | null>(null)
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ export function createReactScopeValueStore(projectId: string) {
|
||||
return scopeStore
|
||||
}
|
||||
|
||||
export const IdeReactProvider: FC = ({ children }) => {
|
||||
export const IdeReactProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const projectId = getMeta('ol-project_id')
|
||||
const [scopeStore] = useState(() => createReactScopeValueStore(projectId))
|
||||
const [eventEmitter] = useState(createIdeEventEmitter)
|
||||
|
||||
+3
-1
@@ -16,7 +16,9 @@ export const IdeRedesignSwitcherContext = createContext<
|
||||
IdeRedesignSwitcherContextValue | undefined
|
||||
>(undefined)
|
||||
|
||||
export const IdeRedesignSwitcherProvider: FC = ({ children }) => {
|
||||
export const IdeRedesignSwitcherProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [showSwitcherModal, setShowSwitcherModal] = useState(false)
|
||||
|
||||
return (
|
||||
|
||||
@@ -47,7 +47,7 @@ export const MetadataContext = createContext<
|
||||
| undefined
|
||||
>(undefined)
|
||||
|
||||
export const MetadataProvider: FC = ({ children }) => {
|
||||
export const MetadataProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const { t } = useTranslation()
|
||||
const { eventEmitter, projectId } = useIdeReactContext()
|
||||
const { socket } = useConnectionContext()
|
||||
|
||||
@@ -30,7 +30,9 @@ type ModalsContextValue = {
|
||||
|
||||
const ModalsContext = createContext<ModalsContextValue | undefined>(undefined)
|
||||
|
||||
export const ModalsContextProvider: FC = ({ children }) => {
|
||||
export const ModalsContextProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [showGenericModal, setShowGenericModal] = useState(false)
|
||||
const [showConfirmModal, setShowConfirmModal] = useState(false)
|
||||
const [genericMessageModalData, setGenericMessageModalData] =
|
||||
|
||||
@@ -65,7 +65,9 @@ export const OnlineUsersContext = createContext<
|
||||
OnlineUsersContextValue | undefined
|
||||
>(undefined)
|
||||
|
||||
export const OnlineUsersProvider: FC = ({ children }) => {
|
||||
export const OnlineUsersProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { eventEmitter } = useIdeReactContext()
|
||||
const { socket } = useConnectionContext()
|
||||
const { currentDocumentId } = useEditorManagerContext()
|
||||
|
||||
@@ -42,7 +42,7 @@ const OutlineContext = createContext<
|
||||
| undefined
|
||||
>(undefined)
|
||||
|
||||
export const OutlineProvider: FC = ({ children }) => {
|
||||
export const OutlineProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const [flatOutline, setFlatOutline] = useState<FlatOutlineState>(undefined)
|
||||
const [currentlyHighlightedLine, setCurrentlyHighlightedLine] =
|
||||
useState<number>(-1)
|
||||
@@ -55,7 +55,7 @@ export const OutlineProvider: FC = ({ children }) => {
|
||||
|
||||
useEventListener(
|
||||
'file-view:file-opened',
|
||||
useCallback(_ => {
|
||||
useCallback(() => {
|
||||
setBinaryFileOpened(true)
|
||||
}, [])
|
||||
)
|
||||
@@ -63,7 +63,7 @@ export const OutlineProvider: FC = ({ children }) => {
|
||||
useEventListener(
|
||||
'scroll:editor:update',
|
||||
useCallback(
|
||||
evt => {
|
||||
(evt: CustomEvent) => {
|
||||
if (ignoreNextScroll) {
|
||||
setIgnoreNextScroll(false)
|
||||
return
|
||||
@@ -77,7 +77,7 @@ export const OutlineProvider: FC = ({ children }) => {
|
||||
useEventListener(
|
||||
'cursor:editor:update',
|
||||
useCallback(
|
||||
evt => {
|
||||
(evt: CustomEvent) => {
|
||||
if (ignoreNextCursorUpdate) {
|
||||
setIgnoreNextCursorUpdate(false)
|
||||
return
|
||||
@@ -90,7 +90,7 @@ export const OutlineProvider: FC = ({ children }) => {
|
||||
|
||||
useEventListener(
|
||||
'doc:after-opened',
|
||||
useCallback(evt => {
|
||||
useCallback((evt: CustomEvent) => {
|
||||
if (evt.detail.isNewDoc) {
|
||||
setIgnoreNextCursorUpdate(true)
|
||||
}
|
||||
|
||||
@@ -79,7 +79,9 @@ const noTrackChangesPermissionsMap: typeof permissionsMap = {
|
||||
owner: permissionsMap.owner,
|
||||
}
|
||||
|
||||
export const PermissionsProvider: React.FC = ({ children }) => {
|
||||
export const PermissionsProvider: React.FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [permissions, setPermissions] =
|
||||
useScopeValue<Readonly<Permissions>>('permissions')
|
||||
const { connectionState } = useConnectionContext()
|
||||
|
||||
@@ -27,10 +27,11 @@ import { UserSettingsProvider } from '@/shared/context/user-settings-context'
|
||||
import { IdeRedesignSwitcherProvider } from './ide-redesign-switcher-context'
|
||||
import { CommandRegistryProvider } from './command-registry-context'
|
||||
|
||||
export const ReactContextRoot: FC<{ providers?: Record<string, FC> }> = ({
|
||||
children,
|
||||
providers = {},
|
||||
}) => {
|
||||
export const ReactContextRoot: FC<
|
||||
React.PropsWithChildren<{
|
||||
providers?: Record<string, FC>
|
||||
}>
|
||||
> = ({ children, providers = {} }) => {
|
||||
const Providers = {
|
||||
ChatProvider,
|
||||
ConnectionProvider,
|
||||
|
||||
@@ -26,7 +26,9 @@ export const ReferencesContext = createContext<
|
||||
| undefined
|
||||
>(undefined)
|
||||
|
||||
export const ReferencesProvider: FC = ({ children }) => {
|
||||
export const ReferencesProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { fileTreeData } = useFileTreeData()
|
||||
const { eventEmitter, projectId } = useIdeReactContext()
|
||||
const { socket } = useConnectionContext()
|
||||
|
||||
@@ -50,7 +50,7 @@ export const SnapshotContext = createContext<
|
||||
| undefined
|
||||
>(undefined)
|
||||
|
||||
export const SnapshotProvider: FC = ({ children }) => {
|
||||
export const SnapshotProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const { _id: projectId } = useProjectContext()
|
||||
const [snapshotLoadingState, setSnapshotLoadingState] =
|
||||
useState<SnapshotLoadingState>('')
|
||||
|
||||
@@ -27,7 +27,7 @@ export const ToolbarProjectTitle = () => {
|
||||
const hasRenamePermissions = permissionsLevel === 'owner'
|
||||
const [isRenaming, setIsRenaming] = useState(false)
|
||||
const onRename = useCallback(
|
||||
name => {
|
||||
(name: string) => {
|
||||
if (name) {
|
||||
renameProject(name)
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ const RailContext = createContext<
|
||||
| undefined
|
||||
>(undefined)
|
||||
|
||||
export const RailProvider: FC = ({ children }) => {
|
||||
export const RailProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const [isOpen, setIsOpen] = useState(true)
|
||||
const [resizing, setResizing] = useState(false)
|
||||
const [activeModal, setActiveModalInternal] = useState<RailModalKey | null>(
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ function CompileTimeWarningUpgradePrompt() {
|
||||
>(`has-dismissed-10s-compile-time-warning-until`)
|
||||
|
||||
const handleNewCompile = useCallback(
|
||||
compileTime => {
|
||||
(compileTime: number) => {
|
||||
setShowWarning(false)
|
||||
if (compileTime > 10000) {
|
||||
if (isProjectOwner) {
|
||||
|
||||
@@ -62,10 +62,10 @@ function PdfJsViewer({ url, pdfFile }: PdfJsViewerProps) {
|
||||
|
||||
// create the viewer when the container is mounted
|
||||
const handleContainer = useCallback(
|
||||
parent => {
|
||||
(parent: HTMLDivElement | null) => {
|
||||
if (parent) {
|
||||
try {
|
||||
setPdfJsWrapper(new PDFJSWrapper(parent.firstChild))
|
||||
setPdfJsWrapper(new PDFJSWrapper(parent.firstChild as HTMLDivElement))
|
||||
} catch (error: any) {
|
||||
setLoadingError(true)
|
||||
captureException(error)
|
||||
@@ -385,7 +385,7 @@ function PdfJsViewer({ url, pdfFile }: PdfJsViewerProps) {
|
||||
|
||||
// set the scale in response to zoom option changes
|
||||
const setZoom = useCallback(
|
||||
zoom => {
|
||||
(zoom: any) => {
|
||||
switch (zoom) {
|
||||
case 'zoom-in':
|
||||
if (pdfJsWrapper) {
|
||||
@@ -430,7 +430,7 @@ function PdfJsViewer({ url, pdfFile }: PdfJsViewerProps) {
|
||||
}, [pdfJsWrapper])
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
event => {
|
||||
(event: React.KeyboardEvent) => {
|
||||
if (!initialised || !pdfJsWrapper) {
|
||||
return
|
||||
}
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ export default function PdfLogEntryRawContent({
|
||||
|
||||
const { elementRef } = useResizeObserver(
|
||||
useCallback(
|
||||
element => {
|
||||
(element: Element) => {
|
||||
if (element.scrollHeight === 0) return // skip update when logs-pane is closed
|
||||
setNeedsExpander(element.scrollHeight > collapsedSize)
|
||||
},
|
||||
|
||||
+3
-2
@@ -1,4 +1,4 @@
|
||||
import ReactDOM from 'react-dom'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import PdfPreview from './pdf-preview'
|
||||
import useWaitForI18n from '../../../shared/hooks/use-wait-for-i18n'
|
||||
import { ReactContextRoot } from '@/features/ide-react/context/react-context-root'
|
||||
@@ -21,5 +21,6 @@ export default PdfPreviewDetachedRoot // for testing
|
||||
|
||||
const element = document.getElementById('pdf-preview-detached-root')
|
||||
if (element) {
|
||||
ReactDOM.render(<PdfPreviewDetachedRoot />, element)
|
||||
const root = createRoot(element)
|
||||
root.render(<PdfPreviewDetachedRoot />)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { FC } from 'react'
|
||||
|
||||
export const PdfPreviewMessages: FC = ({ children }) => {
|
||||
export const PdfPreviewMessages: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
return <div className="pdf-preview-messages">{children}</div>
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ export const usePdfPreviewContext = () => {
|
||||
return context
|
||||
}
|
||||
|
||||
export const PdfPreviewProvider: FC = ({ children }) => {
|
||||
export const PdfPreviewProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [loadingError, setLoadingError] = useState(false)
|
||||
|
||||
const value = useMemo(
|
||||
|
||||
+2
-2
@@ -36,8 +36,8 @@ function PdfViewerControlsToolbar({
|
||||
const [availableWidth, setAvailableWidth] = useState<number>(1000)
|
||||
|
||||
const handleResize = useCallback(
|
||||
element => {
|
||||
setAvailableWidth(element.offsetWidth)
|
||||
(element: Element) => {
|
||||
setAvailableWidth((element as HTMLElement).offsetWidth)
|
||||
},
|
||||
[setAvailableWidth]
|
||||
)
|
||||
|
||||
@@ -33,8 +33,8 @@ export default function usePresentationMode(
|
||||
}, [handlePageChange, page])
|
||||
|
||||
const clickListener = useCallback(
|
||||
event => {
|
||||
if (event.target.tagName === 'A') {
|
||||
(event: MouseEvent) => {
|
||||
if ((event.target as HTMLElement).tagName === 'A') {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ export default function usePresentationMode(
|
||||
)
|
||||
|
||||
const arrowKeyListener = useCallback(
|
||||
event => {
|
||||
(event: KeyboardEvent) => {
|
||||
switch (event.key) {
|
||||
case 'ArrowLeft':
|
||||
case 'ArrowUp':
|
||||
|
||||
@@ -51,7 +51,7 @@ export default function useSynctex(): {
|
||||
|
||||
useEventListener(
|
||||
'cursor:editor:update',
|
||||
useCallback(event => setCursorPosition(event.detail), [])
|
||||
useCallback((event: CustomEvent) => setCursorPosition(event.detail), [])
|
||||
)
|
||||
|
||||
const [syncToPdfInFlight, setSyncToPdfInFlight] = useState(false)
|
||||
@@ -86,7 +86,7 @@ export default function useSynctex(): {
|
||||
}, [dirname, getCurrentDocumentId, pathInFolder, rootDocId])
|
||||
|
||||
const goToCodeLine = useCallback(
|
||||
(file, line) => {
|
||||
(file?: string, line?: number) => {
|
||||
if (file) {
|
||||
const doc = findEntityByPath(file)?.entity
|
||||
if (doc) {
|
||||
@@ -102,7 +102,7 @@ export default function useSynctex(): {
|
||||
)
|
||||
|
||||
const goToPdfLocation = useCallback(
|
||||
params => {
|
||||
(params: string) => {
|
||||
setSyncToPdfInFlight(true)
|
||||
|
||||
if (clsiServerId) {
|
||||
@@ -251,7 +251,10 @@ export default function useSynctex(): {
|
||||
|
||||
useEventListener(
|
||||
'synctex:sync-to-position',
|
||||
useCallback(event => syncToCode({ position: event.detail }), [syncToCode])
|
||||
useCallback(
|
||||
(event: CustomEvent) => syncToCode({ position: event.detail }),
|
||||
[syncToCode]
|
||||
)
|
||||
)
|
||||
|
||||
const [hasSingleSelectedDoc, setHasSingleSelectedDoc] = useDetachState(
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ export default function CreateTagModal({
|
||||
}, [runAsync, tagName, selectedColor, onCreate])
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
e => {
|
||||
(e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
runCreateTag()
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { FormEvent, useCallback, useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Tag } from '../../../../../../app/src/Features/Tags/types'
|
||||
import useAsync from '../../../../shared/hooks/use-async'
|
||||
@@ -56,7 +56,7 @@ export function EditTagModal({ id, tag, onEdit, onClose }: EditTagModalProps) {
|
||||
)
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
e => {
|
||||
(e: FormEvent) => {
|
||||
e.preventDefault()
|
||||
if (tag) {
|
||||
runEditTag(tag._id)
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useState } from 'react'
|
||||
import { FormEvent, useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import useAsync from '../../../../shared/hooks/use-async'
|
||||
import { useRefWithAutoFocus } from '../../../../shared/hooks/use-ref-with-auto-focus'
|
||||
@@ -73,7 +73,7 @@ export function ManageTagModal({
|
||||
)
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
e => {
|
||||
(e: FormEvent) => {
|
||||
e.preventDefault()
|
||||
if (tag) {
|
||||
runUpdateTag(tag._id)
|
||||
|
||||
+9
-2
@@ -1,4 +1,11 @@
|
||||
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import {
|
||||
FormEvent,
|
||||
memo,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import * as eventTracking from '../../../../infrastructure/event-tracking'
|
||||
import { Project } from '../../../../../../types/project/dashboard/api'
|
||||
@@ -58,7 +65,7 @@ function RenameProjectModal({
|
||||
}, [project.name])
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
event => {
|
||||
(event: FormEvent) => {
|
||||
event.preventDefault()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
@@ -100,4 +100,6 @@ function ProjectListPageContent() {
|
||||
)
|
||||
}
|
||||
|
||||
export default withErrorBoundary(ProjectListRoot, GenericErrorBoundaryFallback)
|
||||
export default withErrorBoundary(ProjectListRoot, () => (
|
||||
<GenericErrorBoundaryFallback />
|
||||
))
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import { memo, useCallback } from 'react'
|
||||
import { ChangeEvent, memo, useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useProjectListContext } from '@/features/project-list/context/project-list-context'
|
||||
import OLFormCheckbox from '@/features/ui/components/ol/ol-form-checkbox'
|
||||
@@ -10,7 +10,7 @@ export const ProjectCheckbox = memo<{ projectId: string; projectName: string }>(
|
||||
useProjectListContext()
|
||||
|
||||
const handleCheckboxChange = useCallback(
|
||||
event => {
|
||||
(event: ChangeEvent<HTMLInputElement>) => {
|
||||
toggleSelectedProject(projectId, event.target.checked)
|
||||
},
|
||||
[projectId, toggleSelectedProject]
|
||||
|
||||
+5
-4
@@ -14,6 +14,7 @@ import {
|
||||
DropdownMenu,
|
||||
DropdownToggle,
|
||||
} from '@/features/ui/components/bootstrap-5/dropdown-menu'
|
||||
import { Tag } from '../../../../../../../../app/src/Features/Tags/types'
|
||||
|
||||
function TagsDropdown() {
|
||||
const {
|
||||
@@ -26,7 +27,7 @@ function TagsDropdown() {
|
||||
const { openCreateTagModal, CreateTagModal } = useTag()
|
||||
|
||||
const handleOpenCreateTagModal = useCallback(
|
||||
e => {
|
||||
(e: React.MouseEvent) => {
|
||||
e.preventDefault()
|
||||
openCreateTagModal()
|
||||
},
|
||||
@@ -34,7 +35,7 @@ function TagsDropdown() {
|
||||
)
|
||||
|
||||
const handleAddTagToSelectedProjects = useCallback(
|
||||
(e, tagId) => {
|
||||
(e: React.MouseEvent, tagId: string) => {
|
||||
e.preventDefault()
|
||||
const tag = tags.find(tag => tag._id === tagId)
|
||||
const projectIds = []
|
||||
@@ -50,7 +51,7 @@ function TagsDropdown() {
|
||||
)
|
||||
|
||||
const handleRemoveTagFromSelectedProjects = useCallback(
|
||||
(e, tagId) => {
|
||||
(e: React.MouseEvent, tagId: string) => {
|
||||
e.preventDefault()
|
||||
for (const selectedProject of selectedProjects) {
|
||||
removeProjectFromTagInView(tagId, selectedProject.id)
|
||||
@@ -64,7 +65,7 @@ function TagsDropdown() {
|
||||
)
|
||||
|
||||
const containsAllSelectedProjects = useCallback(
|
||||
tag => {
|
||||
(tag: Tag) => {
|
||||
for (const project of selectedProjects) {
|
||||
if (!(tag.project_ids || []).includes(project.id)) {
|
||||
return false
|
||||
|
||||
@@ -6,9 +6,11 @@ import { createContext, type FC, type ReactNode, useContext } from 'react'
|
||||
*/
|
||||
const DsNavStyleContext = createContext<boolean | undefined>(undefined)
|
||||
|
||||
export const DsNavStyleProvider: FC<{
|
||||
children: ReactNode
|
||||
}> = ({ children }) => (
|
||||
export const DsNavStyleProvider: FC<
|
||||
React.PropsWithChildren<{
|
||||
children: ReactNode
|
||||
}>
|
||||
> = ({ children }) => (
|
||||
<DsNavStyleContext.Provider value>{children}</DsNavStyleContext.Provider>
|
||||
)
|
||||
|
||||
|
||||
@@ -293,7 +293,7 @@ export function ProjectListProvider({ children }: ProjectListProviderProps) {
|
||||
}, [selectedProjectIds, visibleProjects])
|
||||
|
||||
const selectOrUnselectAllProjects = useCallback(
|
||||
checked => {
|
||||
(checked: any) => {
|
||||
setSelectedProjectIds(prevSelectedProjectIds => {
|
||||
const selectedProjectIds = new Set(prevSelectedProjectIds)
|
||||
for (const project of visibleProjects) {
|
||||
|
||||
@@ -50,7 +50,7 @@ function useTag() {
|
||||
)
|
||||
|
||||
const handleEditTag = useCallback(
|
||||
(e, tagId) => {
|
||||
(e: React.MouseEvent, tagId: string) => {
|
||||
e.preventDefault()
|
||||
const tag = find(tags, ['_id', tagId])
|
||||
if (tag) {
|
||||
@@ -69,7 +69,7 @@ function useTag() {
|
||||
)
|
||||
|
||||
const handleDeleteTag = useCallback(
|
||||
(e, tagId) => {
|
||||
(e: React.MouseEvent, tagId: string) => {
|
||||
e.preventDefault()
|
||||
const tag = find(tags, ['_id', tagId])
|
||||
if (tag) {
|
||||
@@ -80,7 +80,7 @@ function useTag() {
|
||||
)
|
||||
|
||||
const onDelete = useCallback(
|
||||
tagId => {
|
||||
(tagId: string) => {
|
||||
deleteTag(tagId)
|
||||
setDeletingTag(undefined)
|
||||
},
|
||||
@@ -88,7 +88,7 @@ function useTag() {
|
||||
)
|
||||
|
||||
const handleManageTag = useCallback(
|
||||
(e, tagId) => {
|
||||
(e: React.MouseEvent, tagId: string) => {
|
||||
e.preventDefault()
|
||||
const tag = find(tags, ['_id', tagId])
|
||||
if (tag) {
|
||||
|
||||
+5
-4
@@ -36,7 +36,7 @@ export const ReviewPanelAddComment = memo<{
|
||||
}, [view, threadId])
|
||||
|
||||
const submitForm = useCallback(
|
||||
async message => {
|
||||
async (message: string) => {
|
||||
setSubmitting(true)
|
||||
|
||||
const content = view.state.sliceDoc(from, to)
|
||||
@@ -85,14 +85,15 @@ export const ReviewPanelAddComment = memo<{
|
||||
// We cannot use the autofocus attribute as we need to wait until the parent element
|
||||
// has been positioned (with the "top" attribute) to avoid scrolling to the initial
|
||||
// position of the element
|
||||
const observerCallback = useCallback(mutationList => {
|
||||
const observerCallback = useCallback((mutationList: MutationRecord[]) => {
|
||||
if (hasBeenFocused.current) {
|
||||
return
|
||||
}
|
||||
|
||||
for (const mutation of mutationList) {
|
||||
if (mutation.target.style.top) {
|
||||
const textArea = mutation.target.getElementsByTagName('textarea')[0]
|
||||
const target = mutation.target as HTMLElement
|
||||
if (target.style.top) {
|
||||
const textArea = target.getElementsByTagName('textarea')[0]
|
||||
if (textArea) {
|
||||
textArea.focus()
|
||||
hasBeenFocused.current = true
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import { memo, useCallback, useState } from 'react'
|
||||
import { Dispatch, memo, SetStateAction, useCallback, useState } from 'react'
|
||||
import { Change, CommentOperation } from '../../../../../types/change'
|
||||
import { ReviewPanelMessage } from './review-panel-message'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@@ -41,7 +41,7 @@ export const ReviewPanelCommentContent = memo<{
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
(content, setContent) => {
|
||||
(content: string, setContent: Dispatch<SetStateAction<string>>) => {
|
||||
if (!onReply || submitting) {
|
||||
return
|
||||
}
|
||||
|
||||
+16
-14
@@ -16,19 +16,21 @@ import { EditorSelection } from '@codemirror/state'
|
||||
import MaterialIcon from '@/shared/components/material-icon'
|
||||
import { OFFSET_FOR_ENTRIES_ABOVE } from '../utils/position-items'
|
||||
|
||||
export const ReviewPanelEntry: FC<{
|
||||
position: number
|
||||
op: AnyOperation
|
||||
docId: string
|
||||
top?: number
|
||||
className?: string
|
||||
selectLineOnFocus?: boolean
|
||||
hoverRanges?: boolean
|
||||
disabled?: boolean
|
||||
onEnterEntryIndicator?: () => void
|
||||
onLeaveEntryIndicator?: () => void
|
||||
entryIndicator?: 'comment' | 'edit'
|
||||
}> = ({
|
||||
export const ReviewPanelEntry: FC<
|
||||
React.PropsWithChildren<{
|
||||
position: number
|
||||
op: AnyOperation
|
||||
docId: string
|
||||
top?: number
|
||||
className?: string
|
||||
selectLineOnFocus?: boolean
|
||||
hoverRanges?: boolean
|
||||
disabled?: boolean
|
||||
onEnterEntryIndicator?: () => void
|
||||
onLeaveEntryIndicator?: () => void
|
||||
entryIndicator?: 'comment' | 'edit'
|
||||
}>
|
||||
> = ({
|
||||
children,
|
||||
position,
|
||||
top,
|
||||
@@ -58,7 +60,7 @@ export const ReviewPanelEntry: FC<{
|
||||
}, [setReviewPanelOpen])
|
||||
|
||||
const selectEntry = useCallback(
|
||||
event => {
|
||||
(event: React.FocusEvent | React.MouseEvent) => {
|
||||
setFocused(true)
|
||||
|
||||
if (event.target instanceof HTMLTextAreaElement) {
|
||||
|
||||
+3
-1
@@ -26,7 +26,9 @@ export const ChangesUsersContext = createContext<ChangesUsers | undefined>(
|
||||
undefined
|
||||
)
|
||||
|
||||
export const ChangesUsersProvider: FC = ({ children }) => {
|
||||
export const ChangesUsersProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { _id: projectId, members, owner } = useProjectContext()
|
||||
const { isRestrictedTokenMember } = useEditorContext()
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ const buildRanges = (currentDocument: DocumentContainer | null) => {
|
||||
|
||||
const RangesActionsContext = createContext<RangesActions | undefined>(undefined)
|
||||
|
||||
export const RangesProvider: FC = ({ children }) => {
|
||||
export const RangesProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const view = useCodeMirrorViewContext()
|
||||
const { projectId } = useIdeReactContext()
|
||||
const { currentDocument } = useEditorManagerContext()
|
||||
|
||||
+3
-1
@@ -5,7 +5,9 @@ import { TrackChangesStateProvider } from './track-changes-state-context'
|
||||
import { ThreadsProvider } from './threads-context'
|
||||
import { ReviewPanelViewProvider } from './review-panel-view-context'
|
||||
|
||||
export const ReviewPanelProviders: FC = ({ children }) => {
|
||||
export const ReviewPanelProviders: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<ReviewPanelViewProvider>
|
||||
<ChangesUsersProvider>
|
||||
|
||||
+3
-1
@@ -20,7 +20,9 @@ const ReviewPanelViewActionsContext = createContext<ViewActions | undefined>(
|
||||
undefined
|
||||
)
|
||||
|
||||
export const ReviewPanelViewProvider: FC = ({ children }) => {
|
||||
export const ReviewPanelViewProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [view, setView] = useState<View>('cur_file')
|
||||
|
||||
const actions = useMemo(
|
||||
|
||||
@@ -48,7 +48,7 @@ const ThreadsActionsContext = createContext<ThreadsActions | undefined>(
|
||||
undefined
|
||||
)
|
||||
|
||||
export const ThreadsProvider: FC = ({ children }) => {
|
||||
export const ThreadsProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const { _id: projectId } = useProjectContext()
|
||||
const { currentDocument } = useEditorManagerContext()
|
||||
const { isRestrictedTokenMember } = useEditorContext()
|
||||
@@ -225,7 +225,7 @@ export const ThreadsProvider: FC = ({ children }) => {
|
||||
useSocketListener(
|
||||
socket,
|
||||
'new-comment-threads',
|
||||
useCallback(threads => {
|
||||
useCallback((threads: any) => {
|
||||
setData(prevState => {
|
||||
const newThreads = { ...prevState }
|
||||
for (const threadId of Object.keys(threads)) {
|
||||
|
||||
+3
-1
@@ -44,7 +44,9 @@ const TrackChangesStateActionsContext = createContext<
|
||||
TrackChangesStateActions | undefined
|
||||
>(undefined)
|
||||
|
||||
export const TrackChangesStateProvider: FC = ({ children }) => {
|
||||
export const TrackChangesStateProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const permissions = usePermissionsContext()
|
||||
const { socket } = useConnectionContext()
|
||||
const project = useProjectContext()
|
||||
|
||||
+2
-2
@@ -126,7 +126,7 @@ const ShareProjectModal = React.memo(function ShareProjectModal({
|
||||
}, [handleHide, inFlight])
|
||||
|
||||
// update `error` and `inFlight` while sending a request
|
||||
const monitorRequest = useCallback(request => {
|
||||
const monitorRequest = useCallback((request: () => any) => {
|
||||
setError(undefined)
|
||||
setInFlight(true)
|
||||
|
||||
@@ -149,7 +149,7 @@ const ShareProjectModal = React.memo(function ShareProjectModal({
|
||||
|
||||
// merge the new data with the old project data
|
||||
const updateProject = useCallback(
|
||||
data => Object.assign(project, data),
|
||||
(data: ProjectContextUpdateValue) => Object.assign(project, data),
|
||||
[project]
|
||||
)
|
||||
|
||||
|
||||
+28
-13
@@ -2,7 +2,15 @@ import {
|
||||
useCodeMirrorStateContext,
|
||||
useCodeMirrorViewContext,
|
||||
} from './codemirror-context'
|
||||
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import {
|
||||
FC,
|
||||
FormEvent,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { runScopeHandlers } from '@codemirror/view'
|
||||
import {
|
||||
closeSearchPanel,
|
||||
@@ -49,7 +57,7 @@ type MatchPositions = {
|
||||
interrupted: boolean
|
||||
}
|
||||
|
||||
const CodeMirrorSearchForm: FC = () => {
|
||||
const CodeMirrorSearchForm: FC<React.PropsWithChildren> = () => {
|
||||
const view = useCodeMirrorViewContext()
|
||||
const state = useCodeMirrorStateContext()
|
||||
const { setProjectSearchIsOpen } = useLayoutContext()
|
||||
@@ -78,7 +86,7 @@ const CodeMirrorSearchForm: FC = () => {
|
||||
|
||||
const newEditor = useIsNewEditorEnabled()
|
||||
|
||||
const handleInputRef = useCallback(node => {
|
||||
const handleInputRef = useCallback((node: HTMLInputElement) => {
|
||||
inputRef.current = node
|
||||
|
||||
// focus the search input when the panel opens
|
||||
@@ -88,11 +96,11 @@ const CodeMirrorSearchForm: FC = () => {
|
||||
}
|
||||
}, [])
|
||||
|
||||
const handleReplaceRef = useCallback(node => {
|
||||
const handleReplaceRef = useCallback((node: HTMLInputElement) => {
|
||||
replaceRef.current = node
|
||||
}, [])
|
||||
|
||||
const handleSubmit = useCallback(event => {
|
||||
const handleSubmit = useCallback((event: FormEvent) => {
|
||||
event.preventDefault()
|
||||
}, [])
|
||||
|
||||
@@ -125,8 +133,8 @@ const CodeMirrorSearchForm: FC = () => {
|
||||
}, [handleChange, state, view])
|
||||
|
||||
const handleFormKeyDown = useCallback(
|
||||
event => {
|
||||
if (runScopeHandlers(view, event, 'search-panel')) {
|
||||
(event: React.KeyboardEvent<HTMLFormElement>) => {
|
||||
if (runScopeHandlers(view, event.nativeEvent, 'search-panel')) {
|
||||
event.preventDefault()
|
||||
}
|
||||
},
|
||||
@@ -135,7 +143,7 @@ const CodeMirrorSearchForm: FC = () => {
|
||||
|
||||
// Returns true if the event was handled, false otherwise
|
||||
const handleEmacsNavigation = useCallback(
|
||||
event => {
|
||||
(event: KeyboardEvent) => {
|
||||
const emacsCtrlSeq =
|
||||
emacsKeybindingsActive &&
|
||||
event.ctrlKey &&
|
||||
@@ -163,7 +171,14 @@ const CodeMirrorSearchForm: FC = () => {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
closeSearchPanel(view)
|
||||
document.dispatchEvent(new CustomEvent('cm:emacs-close-search-panel'))
|
||||
// Wait for the search panel to close before moving the cursor
|
||||
window.setTimeout(
|
||||
() =>
|
||||
document.dispatchEvent(
|
||||
new CustomEvent('cm:emacs-close-search-panel')
|
||||
),
|
||||
0
|
||||
)
|
||||
return true
|
||||
}
|
||||
default: {
|
||||
@@ -175,7 +190,7 @@ const CodeMirrorSearchForm: FC = () => {
|
||||
)
|
||||
|
||||
const handleSearchKeyDown = useCallback(
|
||||
event => {
|
||||
(event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
switch (event.key) {
|
||||
case 'Enter':
|
||||
event.preventDefault()
|
||||
@@ -191,13 +206,13 @@ const CodeMirrorSearchForm: FC = () => {
|
||||
}
|
||||
break
|
||||
}
|
||||
handleEmacsNavigation(event)
|
||||
handleEmacsNavigation(event.nativeEvent)
|
||||
},
|
||||
[view, handleEmacsNavigation, emacsKeybindingsActive]
|
||||
)
|
||||
|
||||
const handleReplaceKeyDown = useCallback(
|
||||
event => {
|
||||
(event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
switch (event.key) {
|
||||
case 'Enter':
|
||||
event.preventDefault()
|
||||
@@ -216,7 +231,7 @@ const CodeMirrorSearchForm: FC = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
handleEmacsNavigation(event)
|
||||
handleEmacsNavigation(event.nativeEvent)
|
||||
},
|
||||
[view, handleEmacsNavigation]
|
||||
)
|
||||
|
||||
@@ -106,7 +106,7 @@ const Toolbar = memo(function Toolbar() {
|
||||
// calculate overflow when buttons change
|
||||
const observerRef = useRef<MutationObserver | null>(null)
|
||||
const handleButtons = useCallback(
|
||||
node => {
|
||||
(node: HTMLDivElement) => {
|
||||
if (!('MutationObserver' in window)) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ function CodeMirrorView() {
|
||||
|
||||
// append the editor view dom to the container node when mounted
|
||||
const containerRef = useCallback(
|
||||
node => {
|
||||
(node: HTMLDivElement) => {
|
||||
if (node) {
|
||||
node.appendChild(view.dom)
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import { FC, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { FC, FormEvent, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
useCodeMirrorStateContext,
|
||||
@@ -71,7 +71,7 @@ export const HrefTooltipContent: FC = () => {
|
||||
}, [view])
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
event => {
|
||||
(event: FormEvent) => {
|
||||
event.preventDefault()
|
||||
view.dispatch(closeCommandTooltip())
|
||||
view.focus()
|
||||
|
||||
@@ -14,7 +14,7 @@ function EditorSwitch() {
|
||||
const richTextAvailable = openDocName ? isValidTeXFile(openDocName) : false
|
||||
|
||||
const handleChange = useCallback(
|
||||
event => {
|
||||
(event: ChangeEvent<HTMLInputElement>) => {
|
||||
const editorType = event.target.value
|
||||
|
||||
switch (editorType) {
|
||||
|
||||
+3
-1
@@ -80,7 +80,9 @@ const FigureModalExistingFigureContext = createContext<
|
||||
| undefined
|
||||
>(undefined)
|
||||
|
||||
export const FigureModalProvider: FC = ({ children }) => {
|
||||
export const FigureModalProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [state, dispatch] = useReducer(reducer, {
|
||||
source: FigureModalSource.NONE,
|
||||
helpShown: false,
|
||||
|
||||
+4
-1
@@ -1,7 +1,10 @@
|
||||
import { FC } from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
|
||||
const LearnWikiLink: FC<{ article: string }> = ({ article, children }) => {
|
||||
const LearnWikiLink: FC<React.PropsWithChildren<{ article: string }>> = ({
|
||||
article,
|
||||
children,
|
||||
}) => {
|
||||
return <a href={`/learn/latex/${article}`}>{children}</a>
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -104,7 +104,8 @@ const FigureModalContent = () => {
|
||||
const hide = useCallback(() => {
|
||||
dispatch({ source: FigureModalSource.NONE })
|
||||
view.requestMeasure()
|
||||
view.focus()
|
||||
// Wait for the modal to close before focusing the editor
|
||||
window.setTimeout(() => view.focus(), 0)
|
||||
}, [dispatch, view])
|
||||
|
||||
useEventListener(
|
||||
|
||||
@@ -176,8 +176,8 @@ export const Cell: FC<{
|
||||
}, [cellData.content, editing, view])
|
||||
|
||||
const onInput = useCallback(
|
||||
e => {
|
||||
update(filterInput(e.target.value))
|
||||
(e: React.FormEvent<HTMLTextAreaElement>) => {
|
||||
update(filterInput((e.target as HTMLTextAreaElement).value))
|
||||
},
|
||||
[update, filterInput]
|
||||
)
|
||||
|
||||
+4
-2
@@ -38,7 +38,9 @@ export const useEditingContext = () => {
|
||||
return context
|
||||
}
|
||||
|
||||
export const EditingContextProvider: FC = ({ children }) => {
|
||||
export const EditingContextProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { table } = useTableContext()
|
||||
const [cellData, setCellData] = useState<EditingContextData | null>(null)
|
||||
const [initialContent, setInitialContent] = useState<string | undefined>(
|
||||
@@ -85,7 +87,7 @@ export const EditingContextProvider: FC = ({ children }) => {
|
||||
}, [setCellData])
|
||||
|
||||
const startEditing = useCallback(
|
||||
(rowIndex: number, cellIndex: number, initialContent = undefined) => {
|
||||
(rowIndex: number, cellIndex: number, initialContent?: string) => {
|
||||
if (cellData?.dirty) {
|
||||
// We're already editing something else
|
||||
commitCellData()
|
||||
|
||||
+3
-1
@@ -411,7 +411,9 @@ export const useSelectionContext = () => {
|
||||
return context
|
||||
}
|
||||
|
||||
export const SelectionContextProvider: FC = ({ children }) => {
|
||||
export const SelectionContextProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [selection, setSelection] = useState<TableSelection | null>(null)
|
||||
const [dragging, setDragging] = useState(false)
|
||||
return (
|
||||
|
||||
+9
-7
@@ -34,13 +34,15 @@ const TableContext = createContext<
|
||||
| undefined
|
||||
>(undefined)
|
||||
|
||||
export const TableProvider: FC<{
|
||||
tableData: ParsedTableData
|
||||
tableNode: SyntaxNode | null
|
||||
tabularNode: SyntaxNode
|
||||
view: EditorView
|
||||
directTableChild?: boolean
|
||||
}> = ({
|
||||
export const TableProvider: FC<
|
||||
React.PropsWithChildren<{
|
||||
tableData: ParsedTableData
|
||||
tableNode: SyntaxNode | null
|
||||
tabularNode: SyntaxNode
|
||||
view: EditorView
|
||||
directTableChild?: boolean
|
||||
}>
|
||||
> = ({
|
||||
tableData,
|
||||
children,
|
||||
tableNode,
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ const TabularContext = createContext<
|
||||
| undefined
|
||||
>(undefined)
|
||||
|
||||
export const TabularProvider: FC = ({ children }) => {
|
||||
export const TabularProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
const [helpShown, setHelpShown] = useState(false)
|
||||
const [columnWidthModalShown, setColumnWidthModalShown] = useState(false)
|
||||
|
||||
+1
-1
@@ -273,7 +273,7 @@ export const Tabular: FC<{
|
||||
)
|
||||
}
|
||||
|
||||
const TabularWrapper: FC = () => {
|
||||
const TabularWrapper: FC<React.PropsWithChildren> = () => {
|
||||
const { setSelection, selection } = useSelectionContext()
|
||||
const { commitCellData, cellData } = useEditingContext()
|
||||
const { ref } = useTabularContext()
|
||||
|
||||
+9
-7
@@ -7,13 +7,15 @@ import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
|
||||
import MaterialIcon from '../../../../../shared/components/material-icon'
|
||||
import { useTabularContext } from '../contexts/tabular-context'
|
||||
|
||||
export const ToolbarButtonMenu: FC<{
|
||||
id: string
|
||||
label: string
|
||||
icon: string
|
||||
disabled?: boolean
|
||||
disabledLabel?: string
|
||||
}> = memo(function ButtonMenu({
|
||||
export const ToolbarButtonMenu: FC<
|
||||
React.PropsWithChildren<{
|
||||
id: string
|
||||
label: string
|
||||
icon: string
|
||||
disabled?: boolean
|
||||
disabledLabel?: string
|
||||
}>
|
||||
> = memo(function ButtonMenu({
|
||||
icon,
|
||||
id,
|
||||
label,
|
||||
|
||||
+2
-2
@@ -28,12 +28,12 @@ export const ToolbarButton = memo<{
|
||||
disabledLabel,
|
||||
}) {
|
||||
const view = useCodeMirrorViewContext()
|
||||
const handleMouseDown = useCallback(event => {
|
||||
const handleMouseDown = useCallback((event: React.MouseEvent) => {
|
||||
event.preventDefault()
|
||||
}, [])
|
||||
|
||||
const handleClick = useCallback(
|
||||
event => {
|
||||
(event: React.MouseEvent) => {
|
||||
if (command) {
|
||||
emitTableGeneratorEvent(view, id)
|
||||
event.preventDefault()
|
||||
|
||||
+20
-16
@@ -9,16 +9,18 @@ import { emitTableGeneratorEvent } from '../analytics'
|
||||
import { useCodeMirrorViewContext } from '../../codemirror-context'
|
||||
import classNames from 'classnames'
|
||||
|
||||
export const ToolbarDropdown: FC<{
|
||||
id: string
|
||||
label?: string
|
||||
btnClassName?: string
|
||||
icon?: string
|
||||
tooltip?: string
|
||||
disabled?: boolean
|
||||
disabledTooltip?: string
|
||||
showCaret?: boolean
|
||||
}> = ({
|
||||
export const ToolbarDropdown: FC<
|
||||
React.PropsWithChildren<{
|
||||
id: string
|
||||
label?: string
|
||||
btnClassName?: string
|
||||
icon?: string
|
||||
tooltip?: string
|
||||
disabled?: boolean
|
||||
disabledTooltip?: string
|
||||
showCaret?: boolean
|
||||
}>
|
||||
> = ({
|
||||
id,
|
||||
label,
|
||||
children,
|
||||
@@ -112,12 +114,14 @@ export const ToolbarDropdown: FC<{
|
||||
}
|
||||
|
||||
export const ToolbarDropdownItem: FC<
|
||||
Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'> & {
|
||||
command: () => void
|
||||
id: string
|
||||
icon?: string
|
||||
active?: boolean
|
||||
}
|
||||
React.PropsWithChildren<
|
||||
Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'> & {
|
||||
command: () => void
|
||||
id: string
|
||||
icon?: string
|
||||
active?: boolean
|
||||
}
|
||||
>
|
||||
> = ({ children, command, id, icon, active, ...props }) => {
|
||||
const view = useCodeMirrorViewContext()
|
||||
const onClick = useCallback(() => {
|
||||
|
||||
@@ -8,12 +8,14 @@ import { EditorView } from '@codemirror/view'
|
||||
import { emitToolbarEvent } from '../../extensions/toolbar/utils/analytics'
|
||||
import { useCodeMirrorViewContext } from '../codemirror-context'
|
||||
|
||||
export const ToolbarButtonMenu: FC<{
|
||||
id: string
|
||||
label: string
|
||||
icon: React.ReactNode
|
||||
altCommand?: (view: EditorView) => void
|
||||
}> = memo(function ButtonMenu({ icon, id, label, altCommand, children }) {
|
||||
export const ToolbarButtonMenu: FC<
|
||||
React.PropsWithChildren<{
|
||||
id: string
|
||||
label: string
|
||||
icon: React.ReactNode
|
||||
altCommand?: (view: EditorView) => void
|
||||
}>
|
||||
> = memo(function ButtonMenu({ icon, id, label, altCommand, children }) {
|
||||
const target = useRef<any>(null)
|
||||
const { open, onToggle, ref } = useDropdown()
|
||||
const view = useCodeMirrorViewContext()
|
||||
|
||||
@@ -6,14 +6,15 @@ import { useCodeMirrorViewContext } from '../codemirror-context'
|
||||
import OLOverlay from '@/features/ui/components/ol/ol-overlay'
|
||||
import OLPopover from '@/features/ui/components/ol/ol-popover'
|
||||
|
||||
export const ToolbarOverflow: FC<{
|
||||
overflowed: boolean
|
||||
overflowOpen: boolean
|
||||
setOverflowOpen: (open: boolean) => void
|
||||
overflowRef?: React.Ref<HTMLDivElement>
|
||||
}> = ({ overflowed, overflowOpen, setOverflowOpen, overflowRef, children }) => {
|
||||
export const ToolbarOverflow: FC<
|
||||
React.PropsWithChildren<{
|
||||
overflowed: boolean
|
||||
overflowOpen: boolean
|
||||
setOverflowOpen: (open: boolean) => void
|
||||
overflowRef?: React.Ref<HTMLDivElement>
|
||||
}>
|
||||
> = ({ overflowed, overflowOpen, setOverflowOpen, overflowRef, children }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const buttonRef = useRef<HTMLButtonElement>(null)
|
||||
const keyboardInputRef = useRef(false)
|
||||
const view = useCodeMirrorViewContext()
|
||||
|
||||
+2
-2
@@ -31,12 +31,12 @@ export const ToolbarButton = memo<{
|
||||
}) {
|
||||
const view = useCodeMirrorViewContext()
|
||||
|
||||
const handleMouseDown = useCallback(event => {
|
||||
const handleMouseDown = useCallback((event: React.MouseEvent) => {
|
||||
event.preventDefault()
|
||||
}, [])
|
||||
|
||||
const handleClick = useCallback(
|
||||
event => {
|
||||
(event: React.MouseEvent) => {
|
||||
emitToolbarEvent(view, id)
|
||||
if (command) {
|
||||
event.preventDefault()
|
||||
|
||||
+5
-5
@@ -1,3 +1,4 @@
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import {
|
||||
StateField,
|
||||
StateEffect,
|
||||
@@ -12,7 +13,6 @@ import {
|
||||
getSpellCheckLanguage,
|
||||
} from '@/features/source-editor/extensions/spelling/index'
|
||||
import { sendMB } from '@/infrastructure/event-tracking'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { SpellingSuggestions } from '@/features/source-editor/extensions/spelling/spelling-suggestions'
|
||||
import { SplitTestProvider } from '@/shared/context/split-test-context'
|
||||
import { addLearnedWord } from '@/features/source-editor/extensions/spelling/learned-words'
|
||||
@@ -159,7 +159,8 @@ const createSpellingSuggestionList = (word: Word) => (view: EditorView) => {
|
||||
const dom = document.createElement('div')
|
||||
dom.classList.add('ol-cm-spelling-context-menu-tooltip')
|
||||
|
||||
ReactDOM.render(
|
||||
const root = createRoot(dom)
|
||||
root.render(
|
||||
<SplitTestProvider>
|
||||
<SpellingSuggestions
|
||||
word={word}
|
||||
@@ -235,12 +236,11 @@ const createSpellingSuggestionList = (word: Word) => (view: EditorView) => {
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</SplitTestProvider>,
|
||||
dom
|
||||
</SplitTestProvider>
|
||||
)
|
||||
|
||||
const destroy = () => {
|
||||
ReactDOM.unmountComponentAtNode(dom)
|
||||
root.unmount()
|
||||
}
|
||||
|
||||
return { dom, destroy }
|
||||
|
||||
+4
-4
@@ -7,7 +7,7 @@ import {
|
||||
import { Decoration, EditorView, WidgetType } from '@codemirror/view'
|
||||
import { undo } from '@codemirror/commands'
|
||||
import { ancestorNodeOfType } from '../../utils/tree-operations/ancestors'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import { PastedContentMenu } from '../../components/paste-html/pasted-content-menu'
|
||||
import { SplitTestProvider } from '../../../../shared/context/split-test-context'
|
||||
|
||||
@@ -171,7 +171,8 @@ class PastedContentMenuWidget extends WidgetType {
|
||||
|
||||
toDOM(view: EditorView) {
|
||||
const element = document.createElement('span')
|
||||
ReactDOM.render(
|
||||
const root = createRoot(element)
|
||||
root.render(
|
||||
<SplitTestProvider>
|
||||
<PastedContentMenu
|
||||
insertPastedContent={this.insertPastedContent}
|
||||
@@ -179,8 +180,7 @@ class PastedContentMenuWidget extends WidgetType {
|
||||
formatted={this.formatted}
|
||||
pastedContent={this.pastedContent}
|
||||
/>
|
||||
</SplitTestProvider>,
|
||||
element
|
||||
</SplitTestProvider>
|
||||
)
|
||||
return element
|
||||
}
|
||||
|
||||
+18
-4
@@ -1,10 +1,12 @@
|
||||
import { createRoot, Root } from 'react-dom/client'
|
||||
import { EditorView, WidgetType } from '@codemirror/view'
|
||||
import { SyntaxNode } from '@lezer/common'
|
||||
import * as ReactDOM from 'react-dom'
|
||||
import { Tabular } from '../../../components/table-generator/tabular'
|
||||
import { ParsedTableData } from '../../../components/table-generator/utils'
|
||||
|
||||
export class TabularWidget extends WidgetType {
|
||||
static roots: WeakMap<HTMLElement, Root> = new WeakMap()
|
||||
|
||||
constructor(
|
||||
private parsedTableData: ParsedTableData,
|
||||
private tabularNode: SyntaxNode,
|
||||
@@ -15,13 +17,21 @@ export class TabularWidget extends WidgetType {
|
||||
super()
|
||||
}
|
||||
|
||||
renderInDOMContainer(children: React.ReactNode, element: HTMLElement) {
|
||||
const root = TabularWidget.roots.get(element) || createRoot(element)
|
||||
if (!TabularWidget.roots.has(element)) {
|
||||
TabularWidget.roots.set(element, root)
|
||||
}
|
||||
root.render(children)
|
||||
}
|
||||
|
||||
toDOM(view: EditorView) {
|
||||
const element = document.createElement('div')
|
||||
element.classList.add('ol-cm-tabular')
|
||||
if (this.tableNode) {
|
||||
element.classList.add('ol-cm-environment-table')
|
||||
}
|
||||
ReactDOM.render(
|
||||
this.renderInDOMContainer(
|
||||
<Tabular
|
||||
view={view}
|
||||
tabularNode={this.tabularNode}
|
||||
@@ -46,7 +56,7 @@ export class TabularWidget extends WidgetType {
|
||||
}
|
||||
|
||||
updateDOM(element: HTMLElement, view: EditorView): boolean {
|
||||
ReactDOM.render(
|
||||
this.renderInDOMContainer(
|
||||
<Tabular
|
||||
view={view}
|
||||
tabularNode={this.tabularNode}
|
||||
@@ -68,6 +78,10 @@ export class TabularWidget extends WidgetType {
|
||||
}
|
||||
|
||||
destroy(element: HTMLElement) {
|
||||
ReactDOM.unmountComponentAtNode(element)
|
||||
const root = TabularWidget.roots.get(element)
|
||||
if (root) {
|
||||
TabularWidget.roots.delete(element)
|
||||
root.unmount()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user