UNPKG

@ehsaneha/react-slot

Version:

A React <Slot> component that merges props and forwards refs to a single child element, similar to Radix UI’s Slot.

59 lines (58 loc) 2.59 kB
var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import { cloneElement, isValidElement, forwardRef, Fragment, } from "react"; function mergeProps(slotProps, childProps) { const merged = Object.assign(Object.assign({}, slotProps), childProps); for (const key in slotProps) { const isEvent = key.startsWith("on") && typeof slotProps[key] === "function"; if (isEvent && typeof childProps[key] === "function") { merged[key] = (...args) => { var _a, _b, _c, _d; (_b = (_a = slotProps)[key]) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); (_d = (_c = childProps)[key]) === null || _d === void 0 ? void 0 : _d.call(_c, ...args); }; } } merged.className = [slotProps.className, childProps.className] .filter(Boolean) .join(" "); merged.style = Object.assign(Object.assign({}, slotProps.style), childProps.style); return merged; } const Slot = forwardRef((_a, ref) => { var { children } = _a, slotProps = __rest(_a, ["children"]); if (!isValidElement(children) || children.type === Fragment || Array.isArray(children)) { if (process.env.NODE_ENV !== "production") { console.warn("<Slot> expects exactly one valid React element as its child, and does not accept React.Fragment or multiple children."); } return null; } // Grab the child's existing ref to merge if any const child = children; const mergedProps = mergeProps(slotProps, child.props); // Combine refs (child's ref + forwarded ref) function setRefs(node) { if (typeof ref === "function") ref(node); else if (ref) ref.current = node; const childRef = child.ref; if (typeof childRef === "function") childRef(node); else if (childRef && typeof childRef === "object") childRef.current = node; } return cloneElement(child, Object.assign(Object.assign({}, mergedProps), { ref: setRefs })); }); export default Slot;