diff --git a/src/components/atoms/TypographyMaxLines.tsx b/src/components/atoms/TypographyMaxLines.tsx index 24631775..dbbf010d 100644 --- a/src/components/atoms/TypographyMaxLines.tsx +++ b/src/components/atoms/TypographyMaxLines.tsx @@ -8,12 +8,15 @@ import styled from '@emotion/styled'; import Typography, { TypographyProps } from '@mui/material/Typography'; +import { shouldForwardProp } from '@/lib/ui/ShouldForwardProp.ts'; + +type TypographyMaxLinesProps = { + lines?: number; +}; export const TypographyMaxLines = styled(Typography, { - shouldForwardProp: (prop) => prop !== 'lines', -})<{ - lines?: number; -}>(({ lines = 2 }) => ({ + shouldForwardProp: shouldForwardProp(['lines']), +})(({ lines = 2 }) => ({ lineHeight: '1.5rem', maxHeight: '3rem', display: '-webkit-box', diff --git a/src/components/chapter/ChapterList.tsx b/src/components/chapter/ChapterList.tsx index 60160dcf..c616bef2 100644 --- a/src/components/chapter/ChapterList.tsx +++ b/src/components/chapter/ChapterList.tsx @@ -45,10 +45,14 @@ import { Mangas } from '@/lib/data/Mangas'; import { useNavBarContext } from '@/components/context/NavbarContext.tsx'; import { useResizeObserver } from '@/util/useResizeObserver.tsx'; import { MediaQuery } from '@/lib/ui/MediaQuery.tsx'; +import { shouldForwardProp } from '@/lib/ui/ShouldForwardProp.ts'; -const ChapterListHeader = styled(Stack, { shouldForwardProp: (prop) => prop !== 'scrollbarWidth' })<{ +type ChapterListHeaderProps = { scrollbarWidth: number; -}>(({ theme, scrollbarWidth }) => ({ +}; +const ChapterListHeader = styled(Stack, { + shouldForwardProp: shouldForwardProp(['scrollbarWidth']), +})(({ theme, scrollbarWidth }) => ({ padding: theme.spacing(1), paddingRight: `calc(${scrollbarWidth}px + ${theme.spacing(1)})`, paddingBottom: 0, @@ -57,16 +61,17 @@ const ChapterListHeader = styled(Stack, { shouldForwardProp: (prop) => prop !== }, })); -const StyledVirtuoso = styled(Virtuoso, { shouldForwardProp: (prop) => prop !== 'topOffset' })<{ topOffset: number }>( - ({ theme, topOffset }) => ({ - listStyle: 'none', - padding: 0, - [theme.breakpoints.up('md')]: { - height: `calc(100vh - ${topOffset}px)`, - margin: 0, - }, - }), -); +type StyledVirtuosoProps = { topOffset: number }; +const StyledVirtuoso = styled(Virtuoso, { + shouldForwardProp: shouldForwardProp(['topOffset']), +})(({ theme, topOffset }) => ({ + listStyle: 'none', + padding: 0, + [theme.breakpoints.up('md')]: { + height: `calc(100vh - ${topOffset}px)`, + margin: 0, + }, +})); export interface IChapterWithMeta extends ChapterWithMetaType['chapter']> { selected: boolean | null; diff --git a/src/components/manga/MangaDetails.tsx b/src/components/manga/MangaDetails.tsx index 7927b926..92a55ebc 100644 --- a/src/components/manga/MangaDetails.tsx +++ b/src/components/manga/MangaDetails.tsx @@ -38,6 +38,7 @@ import { MangaType, SourceType } from '@/lib/graphql/generated/graphql.ts'; import { useLocalStorage } from '@/util/useStorage.tsx'; import { useResizeObserver } from '@/util/useResizeObserver.tsx'; import { useMetadataServerSettings } from '@/lib/metadata/metadataServerSettings.ts'; +import { shouldForwardProp } from '@/lib/ui/ShouldForwardProp.ts'; const DetailsWrapper = styled('div')(({ theme }) => ({ display: 'flex', @@ -51,12 +52,13 @@ const DetailsWrapper = styled('div')(({ theme }) => ({ }, })); -const TopContentWrapper = styled('div', { - shouldForwardProp: (prop) => !['url', 'mangaThumbnailBackdrop'].includes(prop as string), -})<{ +type TopContentWrapperProps = { url: string; mangaThumbnailBackdrop: boolean; -}>(({ theme, url, mangaThumbnailBackdrop }) => ({ +}; +const TopContentWrapper = styled('div', { + shouldForwardProp: shouldForwardProp(['url', 'mangaThumbnailBackdrop']), +})(({ theme, url, mangaThumbnailBackdrop }) => ({ position: 'relative', backgroundImage: mangaThumbnailBackdrop ? `url(${url})` : undefined, backgroundRepeat: mangaThumbnailBackdrop ? 'no-repeat' : undefined, diff --git a/src/components/virtuoso/StyledGroupHeader.tsx b/src/components/virtuoso/StyledGroupHeader.tsx index 45b03c1a..6aec5c86 100644 --- a/src/components/virtuoso/StyledGroupHeader.tsx +++ b/src/components/virtuoso/StyledGroupHeader.tsx @@ -8,12 +8,14 @@ import { styled } from '@mui/material/styles'; import Typography, { TypographyProps } from '@mui/material/Typography'; +import { shouldForwardProp } from '@/lib/ui/ShouldForwardProp.ts'; -export const StyledGroupHeader = styled(Typography, { shouldForwardProp: (prop) => prop !== 'isFirstItem' })< - { - isFirstItem: boolean; - } & TypographyProps ->(({ theme, isFirstItem }) => ({ +type StyledGroupHeaderProps = { + isFirstItem: boolean; +}; +export const StyledGroupHeader = styled(Typography, { + shouldForwardProp: shouldForwardProp(['isFirstItem']), +})(({ theme, isFirstItem }) => ({ paddingLeft: theme.spacing(3), // 16px - 10px (bottom padding of the group items) paddingTop: theme.spacing(0.75), diff --git a/src/lib/ui/ShouldForwardProp.ts b/src/lib/ui/ShouldForwardProp.ts new file mode 100644 index 00000000..47e791e0 --- /dev/null +++ b/src/lib/ui/ShouldForwardProp.ts @@ -0,0 +1,18 @@ +/* + * 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/. + */ + +type TupleUnion = { + [S in U]: Exclude extends never ? [...R, S] : TupleUnion, [...R, S]>; +}[U]; + +export const shouldForwardProp = + >(customProps: TupleUnion) => + (prop: string): boolean => + // @ts-ignore - TS2589: Type instantiation is excessively deep and possibly infinite. + // this function should never be used without a strict type, thus, this error can be ignored + !customProps.includes(prop);