UNPKG

react-tiniest-form

Version:
50 lines (49 loc) 1.99 kB
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;