Feature/update dependency react to v18.x (#346)

* Update dependency "react" to v18.x

Update to v18.2.0

* Update dependency "react" to v18.x - Fix some dependency version issue

Something caused weird tsc issues, most likely a version mismatch since it got fixed by doing a clean install (deleting node_modules folder, yarn.lock and clearing the cache) of the dependencies

* Update dependency "react" to v18.x - Fix "i18n" tsc issues

* Update dependency "react" to v18.x - Fix tsc issue

Typography can only have a single child

* Update dependency "react" to v18.x - Prevent build warning

TODO: migrate to Vite

Gets used without being declared as a dependency.
Since CRA is unmaintained this will not get fixed.

* Update dependency "react" to v18.x - Use "createRoot"

* Update dependency "react" to v18.x - Fix dnd in strict mode
This commit is contained in:
schroda
2023-06-04 21:40:04 +02:00
committed by GitHub
parent 62bf6d66dc
commit 61975b5c49
14 changed files with 1637 additions and 2879 deletions

View File

@@ -33,9 +33,9 @@
"file-selector": "^0.6.0", "file-selector": "^0.6.0",
"i18next": "^22.5.0", "i18next": "^22.5.0",
"i18next-browser-languagedetector": "^7.0.2", "i18next-browser-languagedetector": "^7.0.2",
"react": "^17.0.2", "react": "^18.2.0",
"react-beautiful-dnd": "^13.1.1", "react-beautiful-dnd": "^13.1.1",
"react-dom": "^17.0.2", "react-dom": "^18.2.0",
"react-i18next": "^12.3.1", "react-i18next": "^12.3.1",
"react-router-dom": "^6.11.2", "react-router-dom": "^6.11.2",
"react-scripts": "^5.0.1", "react-scripts": "^5.0.1",
@@ -45,9 +45,10 @@
"web-vitals": "^3.3.2" "web-vitals": "^3.3.2"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^17.0.2", "@babel/plugin-proposal-private-property-in-object": "^7.21.10",
"@types/react": "^18.2.8",
"@types/react-beautiful-dnd": "^13.1.4", "@types/react-beautiful-dnd": "^13.1.4",
"@types/react-dom": "^17.0.2", "@types/react-dom": "^18.2.4",
"@typescript-eslint/eslint-plugin": "^5.59.8", "@typescript-eslint/eslint-plugin": "^5.59.8",
"@typescript-eslint/parser": "^5.59.8", "@typescript-eslint/parser": "^5.59.8",
"eslint": "^8.35.0", "eslint": "^8.35.0",

View File

@@ -159,7 +159,7 @@ export default function ExtensionCard(props: IProps) {
sx={{ color: installedState === InstalledState.OBSOLETE ? 'red' : 'inherit' }} sx={{ color: installedState === InstalledState.OBSOLETE ? 'red' : 'inherit' }}
onClick={() => handleButtonClick()} onClick={() => handleButtonClick()}
> >
{t(INSTALLED_STATE_TO_TRANSLATION_KEY_MAP[installedState])} {t(INSTALLED_STATE_TO_TRANSLATION_KEY_MAP[installedState]) as string}
</Button> </Button>
</CardContent> </CardContent>
</Card> </Card>

View File

@@ -48,7 +48,7 @@ const LibraryOptionsPanel: React.FC<IProps> = ({ open, onClose }) => {
open={open} open={open}
onClose={onClose} onClose={onClose}
tabs={['filter', 'sort', 'display']} tabs={['filter', 'sort', 'display']}
tabTitle={(key) => t(TITLES[key])} tabTitle={(key) => t(TITLES[key]) as string}
tabContent={(key) => { tabContent={(key) => {
if (key === 'filter') { if (key === 'filter') {
return ( return (

View File

@@ -38,7 +38,7 @@ const ChapterOptions: React.FC<IProps> = ({ open, onClose, options, optionsDispa
onClose={onClose} onClose={onClose}
minHeight={150} minHeight={150}
tabs={['filter', 'sort', 'display']} tabs={['filter', 'sort', 'display']}
tabTitle={(key) => t(TITLES[key])} tabTitle={(key) => t(TITLES[key]) as string}
tabContent={(key) => { tabContent={(key) => {
if (key === 'filter') { if (key === 'filter') {
return ( return (

View File

@@ -49,8 +49,10 @@ const DownloadStateIndicator: React.FC<DownloadStateIndicatorProps> = ({ downloa
}} }}
> >
<Typography variant="caption" component="div" color="text.secondary"> <Typography variant="caption" component="div" color="text.secondary">
{download.progress !== 0 && `${Math.round(download.progress * 100)}%`} <>
{download.progress === 0 && t(DOWNLOAD_STATE_TO_TRANSLATION_KEY_MAP[download.state])} {download.progress !== 0 && `${Math.round(download.progress * 100)}%`}
{download.progress === 0 && t(DOWNLOAD_STATE_TO_TRANSLATION_KEY_MAP[download.state])}
</>
</Typography> </Typography>
</Box> </Box>
</Box> </Box>

View File

@@ -48,7 +48,7 @@ export default function DesktopSideBar({ navBarItems }: IProps) {
<Link to={path} style={{ color: 'inherit', textDecoration: 'none' }} key={path}> <Link to={path} style={{ color: 'inherit', textDecoration: 'none' }} key={path}>
<ListItemButton disableRipple key={title}> <ListItemButton disableRipple key={title}>
<ListItemIcon sx={{ minWidth: '0' }}> <ListItemIcon sx={{ minWidth: '0' }}>
<Tooltip placement="right" title={t(title)}> <Tooltip placement="right" title={t(title) as string}>
{iconFor(path, IconComponent, SelectedIconComponent)} {iconFor(path, IconComponent, SelectedIconComponent)}
</Tooltip> </Tooltip>
</ListItemIcon> </ListItemIcon>

View File

@@ -70,7 +70,7 @@ export default function MobileBottomBar({ navBarItems }: IProps) {
: 'grey.600', : 'grey.600',
}} }}
> >
{t(title)} {t(title) as string}
</Box> </Box>
</Box> </Box>
</ListItemButton> </ListItemButton>

View File

@@ -7,11 +7,11 @@
*/ */
import React, { useEffect, useRef } from 'react'; import React, { useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';
import { Box } from '@mui/material'; import { Box } from '@mui/material';
import Page from 'components/reader/Page'; import Page from 'components/reader/Page';
import DoublePage from 'components/reader/DoublePage'; import DoublePage from 'components/reader/DoublePage';
import { IReaderProps } from 'typings'; import { IReaderProps } from 'typings';
import { createRoot } from 'react-dom/client';
const isSpreadPage = (image: HTMLImageElement): boolean => { const isSpreadPage = (image: HTMLImageElement): boolean => {
const aspectRatio = image.height / image.width; const aspectRatio = image.height / image.width;
@@ -58,8 +58,11 @@ export default function DoublePagedPager(props: IReaderProps) {
} }
function displayPages() { function displayPages() {
const container = document.getElementById('display');
const root = createRoot(container!);
if (pagesDisplayed.current === 2) { if (pagesDisplayed.current === 2) {
ReactDOM.render( root.render(
<DoublePage <DoublePage
key={curPage} key={curPage}
index={curPage} index={curPage}
@@ -67,10 +70,9 @@ export default function DoublePagedPager(props: IReaderProps) {
image2src={pages[curPage + 1].src} image2src={pages[curPage + 1].src}
settings={settings} settings={settings}
/>, />,
document.getElementById('display'),
); );
} else { } else {
ReactDOM.render( root.render(
<Page <Page
key={curPage} key={curPage}
index={curPage} index={curPage}
@@ -78,7 +80,6 @@ export default function DoublePagedPager(props: IReaderProps) {
onImageLoad={() => {}} onImageLoad={() => {}}
settings={settings} settings={settings}
/>, />,
document.getElementById('display'),
); );
} }
} }

View File

@@ -6,16 +6,14 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
import ReactDOM from 'react-dom';
import React from 'react'; import React from 'react';
import Slide, { SlideProps } from '@mui/material/Slide'; import Slide, { SlideProps } from '@mui/material/Slide';
import Snackbar from '@mui/material/Snackbar'; import Snackbar from '@mui/material/Snackbar';
import MuiAlert, { AlertColor as Severity } from '@mui/material/Alert'; import MuiAlert, { AlertColor as Severity } from '@mui/material/Alert';
import { createRoot, Root } from 'react-dom/client';
function removeToast(id: string) { function removeToast(root: Root) {
const container = document.querySelector(`#${id}`)!!; root.unmount();
ReactDOM.unmountComponentAtNode(container);
document.body.removeChild(container);
} }
function Transition(props: SlideProps) { function Transition(props: SlideProps) {
@@ -57,9 +55,10 @@ export default function makeToast(message: string, severity: Severity) {
document.body.appendChild(container); document.body.appendChild(container);
ReactDOM.render(<Toast message={message} severity={severity} />, container); const root = createRoot(container!);
root.render(<Toast message={message} severity={severity} />);
setTimeout(() => removeToast(container.id), 3500); setTimeout(() => removeToast(root), 3500);
} }
export function makeToaster([toasts, setToasts]: [React.ReactElement[], (arg0: React.ReactElement[]) => void]): [ export function makeToaster([toasts, setToasts]: [React.ReactElement[], (arg0: React.ReactElement[]) => void]): [

View File

@@ -7,15 +7,16 @@
*/ */
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import { createRoot } from 'react-dom/client';
import App from 'App'; import App from 'App';
import 'index.css'; import 'index.css';
// roboto font // roboto font
import '@fontsource/roboto'; import '@fontsource/roboto';
ReactDOM.render( const container = document.getElementById('root');
const root = createRoot(container!);
root.render(
<React.StrictMode> <React.StrictMode>
<App /> <App />
</React.StrictMode>, </React.StrictMode>,
document.getElementById('root'),
); );

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import React, { useEffect, useState } from 'react';
import { Droppable, DroppableProps } from 'react-beautiful-dnd';
// issue: https://github.com/atlassian/react-beautiful-dnd/issues/2399
// credit for fix: https://github.com/atlassian/react-beautiful-dnd/issues/2399#issuecomment-1175638194
export default function StrictModeDroppable({ children, ...props }: DroppableProps) {
const [enabled, setEnabled] = useState(false);
useEffect(() => {
const animation = requestAnimationFrame(() => setEnabled(true));
return () => {
cancelAnimationFrame(animation);
setEnabled(false);
};
}, []);
if (!enabled) {
return null;
}
return <Droppable {...props}>{children}</Droppable>;
}

View File

@@ -15,7 +15,7 @@ import IconButton from '@mui/material/IconButton';
import NavbarContext from 'components/context/NavbarContext'; import NavbarContext from 'components/context/NavbarContext';
import EmptyView from 'components/util/EmptyView'; import EmptyView from 'components/util/EmptyView';
import React, { useContext, useEffect } from 'react'; import React, { useContext, useEffect } from 'react';
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd'; import { DragDropContext, Draggable } from 'react-beautiful-dnd';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import useSubscription from 'components/library/useSubscription'; import useSubscription from 'components/library/useSubscription';
@@ -27,6 +27,7 @@ import { useTranslation } from 'react-i18next';
import { IChapter, IQueue } from 'typings'; import { IChapter, IQueue } from 'typings';
import makeToast from 'components/util/Toast'; import makeToast from 'components/util/Toast';
import requestManager from 'lib/RequestManager'; import requestManager from 'lib/RequestManager';
import StrictModeDroppable from 'lib/StrictModeDroppable';
const initialQueue = { const initialQueue = {
status: 'Stopped', status: 'Stopped',
@@ -95,7 +96,7 @@ const DownloadQueue: React.FC = () => {
</IconButton> </IconButton>
</NavbarToolbar> </NavbarToolbar>
<DragDropContext onDragEnd={onDragEnd}> <DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable"> <StrictModeDroppable droppableId="droppable">
{(droppableProvided) => ( {(droppableProvided) => (
<Box ref={droppableProvided.innerRef} sx={{ pt: 1 }}> <Box ref={droppableProvided.innerRef} sx={{ pt: 1 }}>
{queue.map((item, index) => ( {queue.map((item, index) => (
@@ -155,7 +156,7 @@ const DownloadQueue: React.FC = () => {
{droppableProvided.placeholder} {droppableProvided.placeholder}
</Box> </Box>
)} )}
</Droppable> </StrictModeDroppable>
</DragDropContext> </DragDropContext>
</> </>
); );

View File

@@ -8,14 +8,7 @@
import React, { useMemo, useState, useContext, useEffect } from 'react'; import React, { useMemo, useState, useContext, useEffect } from 'react';
import { List, ListItem, ListItemText, ListItemIcon, IconButton } from '@mui/material'; import { List, ListItem, ListItemText, ListItemIcon, IconButton } from '@mui/material';
import { import { DragDropContext, Draggable, DropResult, DraggingStyle, NotDraggingStyle } from 'react-beautiful-dnd';
DragDropContext,
Droppable,
Draggable,
DropResult,
DraggingStyle,
NotDraggingStyle,
} from 'react-beautiful-dnd';
import DragHandleIcon from '@mui/icons-material/DragHandle'; import DragHandleIcon from '@mui/icons-material/DragHandle';
import EditIcon from '@mui/icons-material/Edit'; import EditIcon from '@mui/icons-material/Edit';
import { useTheme, Palette } from '@mui/material/styles'; import { useTheme, Palette } from '@mui/material/styles';
@@ -35,6 +28,7 @@ import { ICategory } from 'typings';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { DEFAULT_FULL_FAB_HEIGHT } from 'components/util/StyledFab'; import { DEFAULT_FULL_FAB_HEIGHT } from 'components/util/StyledFab';
import requestManager from 'lib/RequestManager'; import requestManager from 'lib/RequestManager';
import StrictModeDroppable from 'lib/StrictModeDroppable';
const getItemStyle = ( const getItemStyle = (
isDragging: boolean, isDragging: boolean,
@@ -134,7 +128,7 @@ export default function Categories() {
return ( return (
<> <>
<DragDropContext onDragEnd={onDragEnd}> <DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable"> <StrictModeDroppable droppableId="droppable">
{(droppableProvided) => ( {(droppableProvided) => (
<List ref={droppableProvided.innerRef} sx={{ paddingBottom: DEFAULT_FULL_FAB_HEIGHT }}> <List ref={droppableProvided.innerRef} sx={{ paddingBottom: DEFAULT_FULL_FAB_HEIGHT }}>
{categories.map((item, index) => ( {categories.map((item, index) => (
@@ -178,7 +172,7 @@ export default function Categories() {
{droppableProvided.placeholder} {droppableProvided.placeholder}
</List> </List>
)} )}
</Droppable> </StrictModeDroppable>
</DragDropContext> </DragDropContext>
<Fab <Fab
color="primary" color="primary"

4408
yarn.lock

File diff suppressed because it is too large Load Diff