Skip to content

Commit

Permalink
Enhance item.loop to support extra props
Browse files Browse the repository at this point in the history
  • Loading branch information
davidbonnet committed Oct 2, 2023
1 parent 860aef4 commit 1cee76a
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 22 deletions.
32 changes: 22 additions & 10 deletions lib/hooks/useArray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
useRef,
useMemo,
createElement,
Fragment,
} from "../dependencies";

import { setProperty } from "../tools/setProperty";
Expand All @@ -29,6 +28,7 @@ function toNumber(value: string): number {

/**
* Takes an array and returns a function that generates the required props for handling an array item value.
* That function also contains three callables: `loop`, `add`, and `remove`.
*/
export function useArray<
A extends any[] | undefined,
Expand Down Expand Up @@ -113,14 +113,26 @@ export function useArray<
{
loop: {
configurable: false,
value: (
component: FunctionComponent<Omit<ItemProps<T, N, E>, "key">>,
) =>
state.current.map((_, index) => {
const { key, ...props } = item(index);
// FIXME: Creating an element out of `component` triggers an infinite loop
return createElement(Fragment, { key }, component(props));
}),
value: ((
Component: FunctionComponent<ItemProps<T, N, E>>,
extraProps?: {} | ((props: ItemProps<T, N, E>) => {}),
) => {
const getExtraProps =
extraProps === undefined
? undefined
: typeof extraProps === "function"
? extraProps
: () => extraProps;
return state.current.map((_, index) => {
const props: ItemProps<T, N, E> = item(index);
return createElement(
Component,
getExtraProps !== undefined
? { ...props, ...getExtraProps(props) }
: props,
);
});
}) as ItemCallable<T, N, E>["loop"],
},
add: {
configurable: false,
Expand Down Expand Up @@ -229,5 +241,5 @@ export function useArray<
) as ItemCallable<T, N, E>,
[onChangeItem, onChangeItemError, itemId],
);
return item;
return item as ItemCallable<T, N, E>;
}
31 changes: 30 additions & 1 deletion lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ export type ErrorReportObject<T extends object> = Partial<{
""?: ErrorMessage[];
};

/**
* Returns the NEVO props for the property with the specified `propertyName`. If `propertyName` is not provided, returns the NEVO props for the entire object.
*
* @param propertyName The name of the property for which to generate the props.
*/
export interface PropertyCallbable<
T extends object,
N extends string,
Expand Down Expand Up @@ -86,16 +91,40 @@ export type ItemProps<
E extends ErrorReportArray<T[]>,
> = NevoProps<T, N, E[number]> & { key: string; id: string };

/**
* Returns the NEVO props for the item at the specified `itemIndex`. If `itemIndex` is not provided, returns the NEVO props for the entire array.
*
* @param itemIndex The index of the item for which to generate the props.
*/
export interface ItemCallable<
T,
N extends string,
E extends ErrorReportArray<T[]>,
> {
(itemIndex: number): ItemProps<T, N, E>;
(): NevoProps<T[], N, E[""]>;
/**
* Loops over the items of the array and creates an instance
*
* @param Component
* @param extraProps An object containing extra properties to add to each element, or a function that takes the items props and returns the extra properties to add.
* @returns An array containing the produced elements out of `Component`.
*/
readonly loop: (
component: FunctionComponent<ItemProps<T, N, E>>,
Component: FunctionComponent<ItemProps<T, N, E>>,
extraProps?: {} | ((props: ItemProps<T, N, E>) => {}),
) => ReturnType<FunctionComponent>[];
/**
* Inserts an item at the specified index, shifting by one the previous item found at this index and its subsequent ones.
*
* @param item The item to add.
* @param index The index where to add this item.
*/
readonly add: (item: T, index?: number | `${number}`) => void;
/**
* Removes the item found at the specified `index`.
*
* @param index The index of the item to remove.
*/
readonly remove: (index: number | `${number}`) => void;
}
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"@types/lodash-es": "^4.17.9",
"is-promise": "^4.0.0",
"lodash-es": "^4.17.21",
"preact": "^10.18.0"
"preact": "^10.18.1"
},
"devDependencies": {
"@preact/preset-vite": "^2.5.0",
Expand Down
4 changes: 1 addition & 3 deletions src/views/State.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,7 @@ export function State() {
}, [onAppendItem]);
return (
<div class="m-3 flex flex-col space-y-2">
{item.loop((props) => (
<Person {...props} onRemove={onRemoveItem} />
))}
{item.loop(Person, { onRemoveItem })}
<button
class="bg-green-300 p-2 hover:bg-green-400 active:bg-green-800 active:text-white dark:bg-green-700 dark:hover:bg-green-800 dark:active:bg-green-900"
onClick={onPrependItem}
Expand Down

0 comments on commit 1cee76a

Please sign in to comment.