react-tiniest-form
Version:
the tiniest form
50 lines (49 loc) • 1.99 kB
JavaScript
import { jsx as _jsx } from "react/jsx-runtime";
import { cloneElement, createContext, isValidElement, useCallback, useContext, useEffect, useRef, } from 'react';
import { composeRefs } from '../../utils/@common/composeRefs';
const ITEM_ATTR = 'item_attr';
const createCollection = () => {
const defaultValue = {
collectionRef: { current: null },
itemMap: new Map(),
getItems: () => [],
};
const CollectionContext = createContext(null);
const CollectionProvider = ({ children }) => {
const collectionRef = useRef(null);
const itemMap = useRef(new Map()).current;
if (!isValidElement(children))
return null;
return (_jsx(CollectionContext.Provider, { value: { collectionRef, itemMap }, children: cloneElement(children, { ref: composeRefs(collectionRef, children.props.ref) }) }));
};
const CollectionItem = ({ children }) => {
const ref = useRef(null);
const { itemMap } = useCollection();
useEffect(() => {
itemMap.set(ref, { ref });
return () => {
itemMap.delete(ref);
};
});
if (!isValidElement(children))
return null;
return cloneElement(children, {
ref: composeRefs(ref, children.ref),
[ITEM_ATTR]: '',
});
};
const useCollection = () => {
const context = useContext(CollectionContext);
if (!context)
return defaultValue;
const getItems = useCallback(() => {
const collectionNode = context.collectionRef.current;
if (!collectionNode)
return [];
return Array.from(collectionNode.querySelectorAll(`[${ITEM_ATTR}]`));
}, [context.collectionRef, context.itemMap]);
return Object.assign(Object.assign({}, context), { getItems });
};
return { CollectionProvider, CollectionItem, useCollection };
};
export default createCollection;