@crossed/primitive
Version:
A universal & performant styling library for React Native, Next.js & React
72 lines (71 loc) • 2.65 kB
JavaScript
"use client";
import { jsx } from "react/jsx-runtime";
import React from "react";
import { Slot } from "./Slot";
import { createScope, useComposedRefs } from "@crossed/core";
function createCollection(name) {
const [CollectionProviderImpl, useCollectionContext] = createScope({
collectionRef: { current: null },
itemMap: /* @__PURE__ */ new Map()
});
const CollectionProvider = (props) => {
const { children } = props;
const ref = React.useRef(null);
const itemMap = React.useRef(/* @__PURE__ */ new Map()).current;
return /* @__PURE__ */ jsx(CollectionProviderImpl, { itemMap, collectionRef: ref, children });
};
CollectionProvider.displayName = "Collection";
const COLLECTION_SLOT_NAME = name + "CollectionSlot";
const CollectionSlot = React.forwardRef(
(props, forwardedRef) => {
const { children } = props;
const context = useCollectionContext();
const composedRefs = useComposedRefs(forwardedRef, context.collectionRef);
return /* @__PURE__ */ jsx(Slot, { ref: composedRefs, children });
}
);
CollectionSlot.displayName = COLLECTION_SLOT_NAME;
const ITEM_SLOT_NAME = name + "CollectionItemSlot";
const ITEM_DATA_ATTR = "data-crossed-collection-item";
const CollectionItemSlot = React.forwardRef((props, forwardedRef) => {
const { children, ...itemData } = props;
const ref = React.useRef(null);
const composedRefs = useComposedRefs(forwardedRef, ref);
const context = useCollectionContext();
React.useEffect(() => {
context.itemMap.set(ref, { ref, ...itemData });
return () => void context.itemMap.delete(ref);
});
return /* @__PURE__ */ jsx(Slot, { ...{ [ITEM_DATA_ATTR]: "" }, ref: composedRefs, children });
});
CollectionItemSlot.displayName = ITEM_SLOT_NAME;
function useCollection() {
const context = useCollectionContext();
const getItems = React.useCallback(() => {
const collectionNode = context.collectionRef.current;
if (!collectionNode)
return [];
const orderedNodes = Array.from(
collectionNode.querySelectorAll(`[${ITEM_DATA_ATTR}]`)
);
const items = Array.from(context.itemMap.values());
const orderedItems = items.sort(
(a, b) => orderedNodes.indexOf(a.ref.current) - orderedNodes.indexOf(b.ref.current)
);
return orderedItems;
}, [context.collectionRef, context.itemMap]);
return getItems;
}
return [
{
Provider: CollectionProvider,
Slot: CollectionSlot,
ItemSlot: CollectionItemSlot
},
useCollection
];
}
export {
createCollection
};
//# sourceMappingURL=Collections.js.map