mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Rewrite infinite lists to support horizontal
This commit is contained in:
parent
26f9cf646b
commit
894cbb3c9d
@ -31,12 +31,10 @@
|
||||
"next": "13.0.5",
|
||||
"next-fonts": "^1.5.1",
|
||||
"next-translate": "^1.6.0",
|
||||
"next-transpile-modules": "^10.0.0",
|
||||
"raf": "^3.4.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-i18next": "^12.0.0",
|
||||
"react-infinite-scroll-component": "^6.1.0",
|
||||
"react-native-reanimated": "^2.13.0",
|
||||
"react-native-web": "^0.18.10",
|
||||
"solito": "^2.0.5",
|
||||
|
@ -78,7 +78,7 @@ export const Link = ({
|
||||
},
|
||||
default: {},
|
||||
});
|
||||
const Wrapper = radiusStyle ? View : Fragment;
|
||||
const Wrapper = radiusStyle.style ? View : Fragment;
|
||||
|
||||
return (
|
||||
<Wrapper {...radiusStyle}>
|
||||
|
@ -9,6 +9,7 @@
|
||||
"react-native-svg": "^13.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@shopify/flash-list": "^1.4.0",
|
||||
"@types/react": "^18.0.25",
|
||||
"typescript": "^4.9.3"
|
||||
},
|
||||
|
@ -27,6 +27,7 @@ import { ErrorView, Layout, WithLoading } from "./fetch";
|
||||
export const InfiniteFetch = <Data,>({
|
||||
query,
|
||||
placeholderCount = 15,
|
||||
horizontal = false,
|
||||
children,
|
||||
layout,
|
||||
...props
|
||||
@ -34,6 +35,7 @@ export const InfiniteFetch = <Data,>({
|
||||
query: QueryIdentifier<Data>;
|
||||
placeholderCount?: number;
|
||||
layout: Layout;
|
||||
horizontal?: boolean;
|
||||
children: (
|
||||
item: Data extends Page<infer Item> ? WithLoading<Item> : WithLoading<Data>,
|
||||
key: string | undefined,
|
||||
@ -65,6 +67,7 @@ export const InfiniteFetch = <Data,>({
|
||||
]
|
||||
: items
|
||||
}
|
||||
horizontal={horizontal}
|
||||
keyExtractor={(item: any) => item.id?.toString()}
|
||||
numColumns={numColumns}
|
||||
estimatedItemSize={size}
|
||||
|
@ -19,22 +19,84 @@
|
||||
*/
|
||||
|
||||
import { Page, QueryIdentifier, useInfiniteFetch } from "@kyoo/models";
|
||||
import { useBreakpointValue } from "@kyoo/primitives";
|
||||
import { ReactElement } from "react";
|
||||
import InfiniteScroll from "react-infinite-scroll-component";
|
||||
import { useYoshiki } from "yoshiki";
|
||||
import { ReactElement, useRef } from "react";
|
||||
import { Stylable, useYoshiki } from "yoshiki";
|
||||
import { ErrorView, Layout, WithLoading } from "./fetch";
|
||||
|
||||
const InfiniteScroll = ({
|
||||
children,
|
||||
loader,
|
||||
layout = "vertical",
|
||||
loadMore,
|
||||
hasMore,
|
||||
isFetching,
|
||||
...props
|
||||
}: {
|
||||
children?: ReactElement | (ReactElement | null)[] | null;
|
||||
loader?: (ReactElement | null)[];
|
||||
layout?: "vertical" | "horizontal" | "grid";
|
||||
loadMore: () => void;
|
||||
hasMore: boolean;
|
||||
isFetching: boolean;
|
||||
} & Stylable) => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const { css } = useYoshiki();
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
onScroll={() => {
|
||||
if (!ref.current || !hasMore || isFetching) return;
|
||||
const scroll =
|
||||
layout === "horizontal"
|
||||
? ref.current.scrollWidth - ref.current.scrollLeft
|
||||
: ref.current.scrollHeight - ref.current.scrollTop;
|
||||
const offset = layout === "horizontal" ? ref.current.offsetWidth : ref.current.offsetHeight;
|
||||
|
||||
if (scroll <= offset * 1.2) loadMore();
|
||||
}}
|
||||
{...css(
|
||||
[
|
||||
{
|
||||
display: "flex",
|
||||
alignItems: "flex-start",
|
||||
overflow: "overlay",
|
||||
},
|
||||
layout == "vertical" && {
|
||||
flexDirection: "column",
|
||||
alignItems: "stretch",
|
||||
},
|
||||
layout == "horizontal" && {
|
||||
flexDirection: "row",
|
||||
alignItems: "stretch",
|
||||
},
|
||||
layout === "grid" && {
|
||||
flexWrap: "wrap",
|
||||
justifyContent: "center",
|
||||
},
|
||||
],
|
||||
|
||||
props,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
{hasMore && isFetching && loader}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const InfiniteFetch = <Data,>({
|
||||
query,
|
||||
placeholderCount = 15,
|
||||
children,
|
||||
layout,
|
||||
horizontal = false,
|
||||
...props
|
||||
}: {
|
||||
query: QueryIdentifier<Data>;
|
||||
placeholderCount?: number;
|
||||
layout: Layout;
|
||||
horizontal?: boolean;
|
||||
children: (
|
||||
item: Data extends Page<infer Item> ? WithLoading<Item> : WithLoading<Data>,
|
||||
key: string | undefined,
|
||||
@ -43,38 +105,19 @@ export const InfiniteFetch = <Data,>({
|
||||
}): JSX.Element | null => {
|
||||
if (!query.infinite) console.warn("A non infinite query was passed to an InfiniteFetch.");
|
||||
|
||||
const { items, error, fetchNextPage, hasNextPage } = useInfiniteFetch(query);
|
||||
const { numColumns } = useBreakpointValue(layout);
|
||||
const { css } = useYoshiki();
|
||||
const { items, error, fetchNextPage, hasNextPage, isFetching } = useInfiniteFetch(query);
|
||||
const grid = layout.numColumns !== 1;
|
||||
|
||||
if (error) return <ErrorView error={error} />;
|
||||
|
||||
return (
|
||||
<InfiniteScroll
|
||||
scrollableTarget="main" // Default to the main element for the scroll.
|
||||
dataLength={items?.length ?? 0}
|
||||
next={fetchNextPage}
|
||||
layout={grid ? "grid" : horizontal ? "horizontal" : "vertical"}
|
||||
loadMore={fetchNextPage}
|
||||
hasMore={hasNextPage!}
|
||||
isFetching={isFetching}
|
||||
loader={[...Array(12)].map((_, i) => children({ isLoading: true } as any, i.toString(), i))}
|
||||
{...css(
|
||||
[
|
||||
{
|
||||
display: "flex",
|
||||
alignItems: "flex-start",
|
||||
justifyContent: "center",
|
||||
overflow: "unset !important",
|
||||
},
|
||||
numColumns === 1 && {
|
||||
flexDirection: "column",
|
||||
alignItems: "stretch",
|
||||
},
|
||||
numColumns !== 1 && {
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
],
|
||||
|
||||
props,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{items?.map((item, i) =>
|
||||
children({ ...item, isLoading: false } as any, (item as any).id?.toString(), i),
|
||||
|
@ -48,12 +48,12 @@ export const Fetch = <Data,>({
|
||||
const { data, error } = useFetch(query);
|
||||
|
||||
if (error) return <ErrorView error={error} />;
|
||||
if (placeholderCount === 1 || !isPage<object>(data))
|
||||
return children(data ? { ...data, isLoading: false } : ({ isLoading: true } as any), 0);
|
||||
if (!data)
|
||||
return (
|
||||
<>{[...Array(placeholderCount)].map((_, i) => children({ isLoading: true } as any, i))}</>
|
||||
);
|
||||
if (!isPage<object>(data))
|
||||
return children(data ? { ...data, isLoading: false } : ({ isLoading: true } as any), 0);
|
||||
return <>{data.items.map((item, i) => children({ ...item, isLoading: false } as any, i))}</>;
|
||||
};
|
||||
|
||||
|
@ -2322,6 +2322,7 @@ __metadata:
|
||||
dependencies:
|
||||
"@kyoo/models": "workspace:^"
|
||||
"@kyoo/primitives": "workspace:^"
|
||||
"@shopify/flash-list": ^1.4.0
|
||||
"@types/react": ^18.0.25
|
||||
react-native-svg: ^13.6.0
|
||||
typescript: ^4.9.3
|
||||
@ -3156,6 +3157,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@shopify/flash-list@npm:^1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@shopify/flash-list@npm:1.4.0"
|
||||
dependencies:
|
||||
recyclerlistview: 4.2.0
|
||||
tslib: 2.4.0
|
||||
peerDependencies:
|
||||
"@babel/runtime": "*"
|
||||
react: "*"
|
||||
react-native: "*"
|
||||
checksum: c6510b0d6ae6404fe92ede0c918ba184bc2b27ed39c627eebad16a6542792cb34e750e2004e1a9ce165f9d729f1af0555cba1e4c224fd52bfd2a600fdc9e2a65
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sideway/address@npm:^4.1.3":
|
||||
version: 4.1.4
|
||||
resolution: "@sideway/address@npm:4.1.4"
|
||||
@ -9834,15 +9849,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"next-transpile-modules@npm:^10.0.0":
|
||||
version: 10.0.0
|
||||
resolution: "next-transpile-modules@npm:10.0.0"
|
||||
dependencies:
|
||||
enhanced-resolve: ^5.10.0
|
||||
checksum: 3300fc7081f63b2c9487588db7cbe718f209dfd2111adec22d9c8af0e3c8ade2d95fd45f91e045546d78d98cafc78a49431de9a623360d33831b5e694bf007c9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"next@npm:13.0.5":
|
||||
version: 13.0.5
|
||||
resolution: "next@npm:13.0.5"
|
||||
@ -10923,17 +10929,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-infinite-scroll-component@npm:^6.1.0":
|
||||
version: 6.1.0
|
||||
resolution: "react-infinite-scroll-component@npm:6.1.0"
|
||||
dependencies:
|
||||
throttle-debounce: ^2.1.0
|
||||
peerDependencies:
|
||||
react: ">=16.0.0"
|
||||
checksum: 3708398934366df907dbad215247ebc1033221957ce7e32289ea31750cce70aa16513e2d03743e06c8b868ac7c542d12d5dbb6c830fd408433a4762f3cb5ecfb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-is@npm:^16.12.0 || ^17.0.0 || ^18.0.0, react-is@npm:^18.2.0":
|
||||
version: 18.2.0
|
||||
resolution: "react-is@npm:18.2.0"
|
||||
@ -11234,6 +11229,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"recyclerlistview@npm:4.2.0":
|
||||
version: 4.2.0
|
||||
resolution: "recyclerlistview@npm:4.2.0"
|
||||
dependencies:
|
||||
lodash.debounce: 4.0.8
|
||||
prop-types: 15.8.1
|
||||
ts-object-utils: 0.0.5
|
||||
peerDependencies:
|
||||
react: ">= 15.2.1"
|
||||
react-native: ">= 0.30.0"
|
||||
checksum: 6cba6a99fb487067c509112b94e3d4d3905d782bbcb7af2cffbd57c601a4650d670e4eee5fec18d195d58ff6ec01a47288c5510379a2f37da3c5fc0a58860441
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"regenerate-unicode-properties@npm:^10.1.0":
|
||||
version: 10.1.0
|
||||
resolution: "regenerate-unicode-properties@npm:10.1.0"
|
||||
@ -12624,13 +12633,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"throttle-debounce@npm:^2.1.0":
|
||||
version: 2.3.0
|
||||
resolution: "throttle-debounce@npm:2.3.0"
|
||||
checksum: 6d90aa2ddb294f8dad13d854a1cfcd88fdb757469669a096a7da10f515ee466857ac1e750649cb9da931165c6f36feb448318e7cb92570f0a3679d20e860a925
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"through2@npm:^2.0.1":
|
||||
version: 2.0.5
|
||||
resolution: "through2@npm:2.0.5"
|
||||
@ -13307,12 +13309,10 @@ __metadata:
|
||||
next: 13.0.5
|
||||
next-fonts: ^1.5.1
|
||||
next-translate: ^1.6.0
|
||||
next-transpile-modules: ^10.0.0
|
||||
raf: ^3.4.1
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0
|
||||
react-i18next: ^12.0.0
|
||||
react-infinite-scroll-component: ^6.1.0
|
||||
react-native-reanimated: ^2.13.0
|
||||
react-native-web: ^0.18.10
|
||||
solito: ^2.0.5
|
||||
|
Loading…
x
Reference in New Issue
Block a user