Skip to content

Commit

Permalink
feat: support ListHeaderComponent and ListFooterComponent
Browse files Browse the repository at this point in the history
  • Loading branch information
janicduplessis committed Jul 21, 2023
1 parent a395c6c commit 8054fd2
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 8 deletions.
79 changes: 72 additions & 7 deletions src/Wishlist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,36 @@ type Props = ViewProps & {
onEndReached?: () => void;
initialIndex?: number;
contentContainerStyle?: StyleProp<ViewStyle> | undefined;
/**
* Rendered at the bottom of all the items. Can be a React Component Class, a render function, or
* a rendered element.
*/
ListFooterComponent?:
| React.ComponentType<any>
| React.ReactElement
| null
| undefined;
/**
* Rendered at the top of all the items. Can be a React Component Class, a render function, or
* a rendered element.
*/
ListHeaderComponent?:
| React.ComponentType<any>
| React.ReactElement
| null
| undefined;
};

function ComponentBase<T extends BaseItem>(
{ children, style, data, contentContainerStyle, ...rest }: Props,
{
children,
style,
data,
contentContainerStyle,
ListFooterComponent,
ListHeaderComponent,
...rest
}: Props,
ref: React.Ref<WishListInstance>,
) {
const nativeWishlist = useRef<InstanceType<typeof NativeWishList> | null>(
Expand Down Expand Up @@ -123,6 +149,28 @@ function ComponentBase<T extends BaseItem>(
[children, width],
);

if (ListHeaderComponent) {
childrenTemplates.__wishlistHeader = React.isValidElement(
ListHeaderComponent,
) ? (
ListHeaderComponent
) : (
// @ts-expect-error
<ListHeaderComponent />
);
}

if (ListFooterComponent) {
childrenTemplates.__wishlistFooter = React.isValidElement(
ListFooterComponent,
) ? (
ListFooterComponent
) : (
// @ts-expect-error
<ListFooterComponent />
);
}

const templatesRegistry = useMemo<NestedTemplatesContextValue>(
() => ({
templates: {},
Expand All @@ -137,6 +185,9 @@ function ComponentBase<T extends BaseItem>(
[],
);

const hasHeader = !!ListHeaderComponent;
const hasFooter = !!ListFooterComponent;

// Resolve inflator - either use the provided callback or use the mapping
const resolvedInflater: InflateMethod = useMemo(() => {
return (
Expand All @@ -145,7 +196,17 @@ function ComponentBase<T extends BaseItem>(
previousItem: TemplateItem | null,
) => {
'worklet';
const value = (data as WishlistDataInternal<T>).__at(index);
const internalData = data as WishlistDataInternal<T>;

let value: T | undefined;
if (hasHeader && index === internalData.__firstIndex() - 1) {
value = { key: '__wishlistHeader', type: '__wishlistHeader' } as T;
} else if (hasFooter && index === internalData.__lastIndex()) {
value = { key: '__wishlistFooter', type: '__wishlistFooter' } as T;
} else {
value = internalData.__at(index);
}

if (!value) {
return undefined;
}
Expand All @@ -170,7 +231,7 @@ function ComponentBase<T extends BaseItem>(

return [item, value];
};
}, [data]);
}, [data, hasFooter, hasHeader]);

const inflatorIdRef = useRef<string | null>(null);
const prevInflatorRef = useRef<typeof resolvedInflater>();
Expand Down Expand Up @@ -222,7 +283,6 @@ function ComponentBase<T extends BaseItem>(
</View>
))}
</View>

<InnerComponent
inflatorId={inflatorId}
style={style}
Expand All @@ -231,6 +291,7 @@ function ComponentBase<T extends BaseItem>(
templates={childrenTemplates}
nestedTemplates={templatesRegistry.templates}
contentContainerStyle={contentContainerStyle}
initialIndex={rest.initialIndex ?? (hasHeader ? -1 : 0)}
/>
</>
</TemplatesRegistryContext.Provider>
Expand All @@ -251,6 +312,7 @@ type InnerComponentProps = ViewProps & {
templates: { [key: string]: any };
nestedTemplates: { [key: string]: any };
contentContainerStyle?: StyleProp<ViewStyle> | undefined;
initialIndex: number;
};

function InnerComponent({
Expand All @@ -261,8 +323,12 @@ function InnerComponent({
templates,
nestedTemplates,
contentContainerStyle,
initialIndex,
}: InnerComponentProps) {
const combinedTemplates = { ...templates, ...nestedTemplates };
const combinedTemplates: { [key: string]: React.ReactElement<any> } = {
...templates,
...nestedTemplates,
};

const { id } = useWishlistContext();

Expand All @@ -281,14 +347,13 @@ function InnerComponent({
inflatorId={inflatorId}
onEndReached={rest?.onEndReached}
onStartReached={rest?.onStartReached}
initialIndex={rest.initialIndex ?? 0}
initialIndex={initialIndex}
>
<NativeContentContainer
collapsable={false}
style={contentContainerStyle}
/>
</NativeWishList>

<NativeTemplateContainer
names={keys}
inflatorId={inflatorId}
Expand Down
25 changes: 24 additions & 1 deletion src/WishlistData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export interface WishlistDataInternal<T extends Item> extends WishlistData<T> {
__attach: (wishlistId: string) => void;
__detach: (wishlistId: string) => void;
__at: (index: number) => T | undefined;
__firstIndex: () => number;
__lastIndex: () => number;
}

/**
Expand Down Expand Up @@ -64,6 +66,17 @@ export function useWishlistData<T extends Item>(
return currentlyRenderedCopy.at(index);
}

function __firstIndex() {
return 0 - currentlyRenderedCopy.__numberOfNegative;
}

function __lastIndex() {
return (
currentlyRenderedCopy.length -
currentlyRenderedCopy.__numberOfNegative
);
}

function __attach(wishlistId: string) {
attachedListIds.add(wishlistId);

Expand Down Expand Up @@ -92,6 +105,8 @@ export function useWishlistData<T extends Item>(
__at,
__attach,
__detach,
__firstIndex,
__lastIndex,
};

global.dataCtx[dataId] = internalData;
Expand All @@ -102,7 +117,7 @@ export function useWishlistData<T extends Item>(
}, []);

return useMemo(
() => ({
(): WishlistDataInternal<T> => ({
update: <ResT>(updateJob: UpdateJob<T, ResT>) => {
'worklet';

Expand Down Expand Up @@ -138,6 +153,14 @@ export function useWishlistData<T extends Item>(
getWishlistData().__detach(wishlistId);
})();
},
__firstIndex: () => {
'worklet';
return getWishlistData().__firstIndex();
},
__lastIndex: () => {
'worklet';
return getWishlistData().__lastIndex();
},
}),
[getWishlistData],
);
Expand Down

0 comments on commit 8054fd2

Please sign in to comment.