@winglet/react-utils
Version:
React utility library providing custom hooks, higher-order components (HOCs), and utility functions to enhance React application development with improved reusability and functionality
99 lines (98 loc) • 3.71 kB
TypeScript
import { type PropsWithChildren } from 'react';
/**
* Renders React components at a different location in the DOM tree while maintaining component hierarchy.
*
* This Portal component provides a powerful mechanism for rendering content outside of its normal
* DOM hierarchy, allowing you to break out of CSS containment (like overflow:hidden) or z-index
* stacking contexts. The content is rendered at the location of a designated Portal.Anchor component
* while preserving the React component tree structure for event bubbling and context propagation.
*
* ### Use Cases
* - **Modals and Overlays**: Render modal content at document root to avoid z-index issues
* - **Tooltips and Popovers**: Position floating elements outside scrollable containers
* - **Dropdown Menus**: Render dropdowns that extend beyond parent container boundaries
* - **Notification Systems**: Display notifications at a consistent location regardless of trigger source
*
* ### Key Features
* - Maintains React component hierarchy and context while changing DOM location
* - Automatically registers and unregisters content on mount/unmount
* - Preserves event bubbling through the React component tree
* - Supports multiple Portal instances with unique identification
* - Memory-optimized with automatic cleanup on component unmount
*
* ### Portal Lifecycle
* - On mount: Registers children with the Portal context using a unique ID
* - During updates: Re-registers with new content when children change
* - On unmount: Automatically unregisters to prevent memory leaks
* - Rendering: Content appears at Portal.Anchor location, not at Portal component location
*
* @example
* ```typescript
* // Basic modal usage
* const ModalExample = Portal.with(() => {
* const [showModal, setShowModal] = useState(false);
*
* return (
* <div className="app">
* <button onClick={() => setShowModal(true)}>Open Modal</button>
*
* {showModal && (
* <Portal>
* <div className="modal-backdrop">
* <div className="modal">
* <h2>Modal Title</h2>
* <p>This content is rendered at the Portal.Anchor location!</p>
* <button onClick={() => setShowModal(false)}>Close</button>
* </div>
* </div>
* </Portal>
* )}
*
* <Portal.Anchor /> // Modal content appears here
* </div>
* );
* });
*
* // Tooltip system
* const TooltipExample = Portal.with(() => {
* const [tooltip, setTooltip] = useState(null);
*
* return (
* <div className="container">
* <button
* onMouseEnter={() => setTooltip('Helpful tooltip text')}
* onMouseLeave={() => setTooltip(null)}
* >
* Hover me
* </button>
*
* {tooltip && (
* <Portal>
* <div className="tooltip">{tooltip}</div>
* </Portal>
* )}
*
* <Portal.Anchor className="tooltip-container" />
* </div>
* );
* });
*
* // Multiple portals
* const MultiPortalExample = Portal.with(() => {
* return (
* <div>
* <Portal><span>First portal content</span></Portal>
* <Portal><span>Second portal content</span></Portal>
*
* <div>Regular content here</div>
*
* <Portal.Anchor /> // Both portal contents render here
* </div>
* );
* });
* ```
*
* @param children - The React elements to render at the Portal.Anchor location. Can be any valid ReactNode
* @returns null - This component doesn't render anything in its own location, content appears at the anchor
*/
export declare const Portal: import("react").MemoExoticComponent<({ children }: PropsWithChildren) => null>;