Skip to content

Commit

Permalink
refactor(ItemWithIndex): remove ItemWithIndex type (#129)
Browse files Browse the repository at this point in the history
* feat(virtualizedList): pass index in props of itemContainerWithAnimatedStyle

* feat(virtualizedListWithNodes): pass index in props of itemWrapperWithVirtualParentContext

* feat(virtualizedListWithScroll): pass index as props of itemWrapperWithScrollContext

* feat(virtualizedGrid): pass index in renderHeader, GridRow then ItemWrapper

* refactor(virtualizedGrid): stop using ItemWithIndex type

* refactor(virtualizedList): stop using ItemWithIndex type in layers of list

* refactor(virtualizedList): delete ItemWithIndex type

* refactor(SNvirtualizedList): stop indexing data in first layer

* refactor(Lists): delete addIndex helper

* fix(virtualizedGrid): fix index of row by taking header into account
  • Loading branch information
AlecColas authored and pierpo committed Jun 10, 2024
1 parent 2c4b579 commit 46c12e3
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React, { ReactNode, useCallback, useEffect, useMemo } from 'react';
import { View, ViewStyle, StyleSheet } from 'react-native';
import range from 'lodash/range';

import { ItemWithIndex } from '../virtualizedList/VirtualizedList';
import { SpatialNavigationVirtualizedList } from '../virtualizedList/SpatialNavigationVirtualizedList';
import {
PointerScrollProps,
Expand All @@ -13,7 +12,7 @@ import { ParentIdContext, useParentId } from '../../context/ParentIdContext';
import { typedMemo } from '../../helpers/TypedMemo';
import { convertToGrid } from './helpers/convertToGrid';

type SpatialNavigationVirtualizedGridProps<T extends ItemWithIndex> = Pick<
type SpatialNavigationVirtualizedGridProps<T> = Pick<
SpatialNavigationVirtualizedListWithScrollProps<T>,
| 'data'
| 'renderItem'
Expand All @@ -40,9 +39,8 @@ type SpatialNavigationVirtualizedGridProps<T extends ItemWithIndex> = Pick<
rowContainerStyle?: ViewStyle;
};

export type GridRowType<T extends ItemWithIndex> = {
export type GridRowType<T> = {
items: T[];
index: number;
};

const useRegisterGridRowVirtualNodes = ({ numberOfColumns }: { numberOfColumns: number }) => {
Expand Down Expand Up @@ -84,45 +82,51 @@ const useRegisterGridRowVirtualNodes = ({ numberOfColumns }: { numberOfColumns:
};

const ItemWrapperWithVirtualParentContext = typedMemo(
<T extends ItemWithIndex>({
<T,>({
virtualParentID,
item,
index,
renderItem,
}: {
virtualParentID: string;
item: T;
index: number;
renderItem: (args: { item: T; index: number }) => JSX.Element;
}) => (
<ParentIdContext.Provider value={virtualParentID}>
{renderItem({ item, index: item.index })}
{renderItem({ item, index })}
</ParentIdContext.Provider>
),
);
ItemWrapperWithVirtualParentContext.displayName = 'ItemWrapperWithVirtualParentContext';

const GridRow = <T extends ItemWithIndex>({
const GridRow = <T,>({
renderItem,
numberOfColumns,
row,
rowIndex,
rowContainerStyle,
}: {
renderItem: (args: { item: T; index: number }) => JSX.Element;
numberOfColumns: number;
row: GridRowType<T>;
rowIndex: number;
rowContainerStyle?: ViewStyle;
}) => {
const { getNthVirtualNodeID } = useRegisterGridRowVirtualNodes({ numberOfColumns });

return (
<HorizontalContainer style={rowContainerStyle}>
{row.items.map((item, index) => {
{row.items.map((item, columnIndex) => {
const itemIndex = rowIndex * numberOfColumns + columnIndex;
return (
/* This view is important to reset flex direction to vertical */
<View key={index}>
<View key={columnIndex}>
<ItemWrapperWithVirtualParentContext
virtualParentID={getNthVirtualNodeID(index)}
virtualParentID={getNthVirtualNodeID(columnIndex)}
renderItem={renderItem}
item={item}
index={itemIndex}
/>
</View>
);
Expand Down Expand Up @@ -181,7 +185,7 @@ const GridRow = <T extends ItemWithIndex>({
*/

export const SpatialNavigationVirtualizedGrid = typedMemo(
<T extends ItemWithIndex>({
<T,>({
renderItem,
data,
numberOfColumns,
Expand Down Expand Up @@ -221,24 +225,27 @@ export const SpatialNavigationVirtualizedGrid = typedMemo(
const itemSize = hasHeader ? itemSizeAsAFunction : itemHeight;

const renderRow = useCallback(
({ item: row }: { item: GridRowType<T> }) => (
({ item: row, index }: { item: GridRowType<T>; index: number }) => (
<GridRow
renderItem={renderItem}
numberOfColumns={numberOfColumns}
row={row}
rowIndex={index}
rowContainerStyle={rowContainerStyle}
/>
),
[renderItem, numberOfColumns, rowContainerStyle],
);
const renderHeaderThenRows = useCallback(
({ item }: { item: GridRowType<T> | JSX.Element }) => {
({ item, index }: { item: GridRowType<T> | JSX.Element; index: number }) => {
if (React.isValidElement(item)) {
return item;
}
return renderRow({ item: item as GridRowType<T> });
//We do this to have index taking into account the header
const computedIndex = hasHeader ? index - 1 : index;
return renderRow({ item: item as GridRowType<T>, index: computedIndex });
},
[renderRow],
[hasHeader, renderRow],
);

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import chunk from 'lodash/chunk';
import { GridRowType } from '../SpatialNavigationVirtualizedGrid';
import { ItemWithIndex } from '../../virtualizedList/VirtualizedList';

import { NodeOrientation } from '../../../types/orientation';

export const convertToGrid = <T extends ItemWithIndex>(
export const convertToGrid = <T>(
data: T[],
numberOfColumns: number,
header?: JSX.Element,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { ForwardedRef, useMemo } from 'react';
import { ForwardedRef } from 'react';
import { SpatialNavigationNode } from '../Node';
import {
PointerScrollProps,
SpatialNavigationVirtualizedListWithScroll,
SpatialNavigationVirtualizedListWithScrollProps,
} from './SpatialNavigationVirtualizedListWithScroll';
import { typedMemo } from '../../helpers/TypedMemo';
import { addIndex } from './helpers/addIndex';
import { ItemWithIndex } from './VirtualizedList';

import { typedForwardRef } from '../../helpers/TypedForwardRef';
import { SpatialNavigationVirtualizedListRef } from '../../types/SpatialNavigationVirtualizedListRef';

Expand All @@ -21,18 +20,12 @@ export const SpatialNavigationVirtualizedList = typedMemo(
props: SpatialNavigationVirtualizedListWithScrollProps<T> & PointerScrollProps,
ref: ForwardedRef<SpatialNavigationVirtualizedListRef>,
) => {
const indexedData = useMemo(() => addIndex(props.data), [props.data]);

return (
<SpatialNavigationNode
alignInGrid={props.isGrid ?? false}
orientation={props.orientation ?? 'horizontal'}
>
<SpatialNavigationVirtualizedListWithScroll<T & ItemWithIndex>
{...props}
data={indexedData}
ref={ref}
/>
<SpatialNavigationVirtualizedListWithScroll<T> {...props} ref={ref} />
</SpatialNavigationNode>
);
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ForwardedRef, useCallback, useImperativeHandle, useMemo, useRef, useState } from 'react';
import { VirtualizedListProps, ItemWithIndex } from './VirtualizedList';
import { VirtualizedListProps } from './VirtualizedList';

import {
SpatialNavigationVirtualizedListWithVirtualNodes,
Expand All @@ -20,30 +20,32 @@ import { typedForwardRef } from '../../helpers/TypedForwardRef';
import { SpatialNavigationVirtualizedListRef } from '../../types/SpatialNavigationVirtualizedListRef';

const ItemWrapperWithScrollContext = typedMemo(
<T extends ItemWithIndex>({
<T,>({
setCurrentlyFocusedItemIndex,
item,
index,
renderItem,
}: {
setCurrentlyFocusedItemIndex: (i: number) => void;
item: T;
index: number;
renderItem: VirtualizedListProps<T>['renderItem'];
}) => {
const { scrollToNodeIfNeeded: makeParentsScrollToNodeIfNeeded } =
useSpatialNavigatorParentScroll();

const scrollToItem: ScrollToNodeCallback = useCallback(
(newlyFocusedElementRef, additionalOffset) => {
setCurrentlyFocusedItemIndex(item.index);
setCurrentlyFocusedItemIndex(index);
// We need to propagate the scroll event for parents if we have nested ScrollViews/VirtualizedLists.
makeParentsScrollToNodeIfNeeded(newlyFocusedElementRef, additionalOffset);
},
[makeParentsScrollToNodeIfNeeded, setCurrentlyFocusedItemIndex, item.index],
[makeParentsScrollToNodeIfNeeded, setCurrentlyFocusedItemIndex, index],
);

return (
<SpatialNavigatorParentScrollContext.Provider value={scrollToItem}>
{renderItem({ item, index: item.index })}
{renderItem({ item, index })}
</SpatialNavigatorParentScrollContext.Provider>
);
},
Expand All @@ -63,14 +65,14 @@ export type PointerScrollProps = {
scrollInterval?: number;
};

const useRemotePointerVirtualizedListScrollProps = ({
const useRemotePointerVirtualizedListScrollProps = <T,>({
setCurrentlyFocusedItemIndex,
scrollInterval,
data,
}: {
setCurrentlyFocusedItemIndex: React.Dispatch<React.SetStateAction<number>>;
scrollInterval: number;
data: ItemWithIndex[];
data: T[];
}) => {
const {
deviceType,
Expand Down Expand Up @@ -166,7 +168,7 @@ const useRemotePointerVirtualizedListScrollProps = ({
*/
export const SpatialNavigationVirtualizedListWithScroll = typedMemo(
typedForwardRef(
<T extends ItemWithIndex>(
<T,>(
props: SpatialNavigationVirtualizedListWithScrollProps<T> & PointerScrollProps,
ref: ForwardedRef<SpatialNavigationVirtualizedListRef>,
) => {
Expand Down Expand Up @@ -210,11 +212,12 @@ export const SpatialNavigationVirtualizedListWithScroll = typedMemo(
);

const renderWrappedItem: typeof props.renderItem = useCallback(
({ item }) => (
({ item, index }) => (
<ItemWrapperWithScrollContext
setCurrentlyFocusedItemIndex={setCurrentlyFocusedItemIndexCallback}
renderItem={renderItem}
item={item}
index={index}
/>
),
[setCurrentlyFocusedItemIndexCallback, renderItem],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import uniqueId from 'lodash.uniqueid';
import { useCallback, useEffect, useImperativeHandle, useRef } from 'react';
import { VirtualizedListProps, ItemWithIndex } from './VirtualizedList';
import { VirtualizedListProps } from './VirtualizedList';
import { useSpatialNavigator } from '../../context/SpatialNavigatorContext';
import { ParentIdContext, useParentId } from '../../context/ParentIdContext';
import { updateVirtualNodeRegistration } from './helpers/updateVirtualNodeRegistration';
Expand Down Expand Up @@ -73,7 +73,7 @@ const useUpdateRegistration = <T,>({
}, [allItems]);
};

const useRegisterVirtualNodes = <T extends ItemWithIndex>({
const useRegisterVirtualNodes = <T,>({
allItems,
orientation,
isGrid,
Expand Down Expand Up @@ -118,17 +118,19 @@ const useRegisterVirtualNodes = <T extends ItemWithIndex>({
};

const ItemWrapperWithVirtualParentContext = typedMemo(
<T extends ItemWithIndex>({
<T,>({
virtualParentID,
index,
item,
renderItem,
}: {
virtualParentID: string;
item: T;
index: number;
renderItem: VirtualizedListProps<T>['renderItem'];
}) => (
<ParentIdContext.Provider value={virtualParentID}>
{renderItem({ item, index: item.index })}
{renderItem({ item, index: index })}
</ParentIdContext.Provider>
),
);
Expand Down Expand Up @@ -170,7 +172,7 @@ export type SpatialNavigationVirtualizedListWithVirtualNodesRef = {
* Framed letters correspond to rendered components.
*/
export const SpatialNavigationVirtualizedListWithVirtualNodes = typedMemo(
<T extends ItemWithIndex>(
<T,>(
props: SpatialNavigationVirtualizedListWithVirtualNodesProps<T> & {
getNodeIdRef: React.Ref<SpatialNavigationVirtualizedListWithVirtualNodesRef>;
},
Expand All @@ -191,11 +193,12 @@ export const SpatialNavigationVirtualizedListWithVirtualNodes = typedMemo(

const { renderItem } = props;
const renderWrappedItem: typeof props.renderItem = useCallback(
({ item }) => (
({ item, index }) => (
<ItemWrapperWithVirtualParentContext
virtualParentID={getNthVirtualNodeID(item.index)}
virtualParentID={getNthVirtualNodeID(index)}
renderItem={renderItem}
item={item}
index={index}
/>
),
[getNthVirtualNodeID, renderItem],
Expand Down
Loading

0 comments on commit 46c12e3

Please sign in to comment.