UNPKG

@hanamura/react-containers

Version:
69 lines 3.17 kB
'use client'; import { jsxs as _jsxs } from "react/jsx-runtime"; import { Children, Fragment, isValidElement, cloneElement } from 'react'; import { useAdaptiveContainer, normalizeSpacingValue, } from '../core'; /** * Stack component - arranges children in a vertical stack * * Features: * - Responsive spacing based on breakpoints * - Optional dividers at start, between items, and end * - Customizable divider rendering with position information * - Customizable HTML element via 'as' prop */ export function Stack({ children, options, queries, adaptiveOptions, className, style, as = 'div', ...rest }) { // Get the current options based on active breakpoint const { options: mergedOptions } = useAdaptiveContainer(options, queries, adaptiveOptions); // Create the base style for the stack container const containerStyle = { display: 'flex', flexDirection: 'column', gap: normalizeSpacingValue(mergedOptions.gap) ?? 0, paddingInline: normalizeSpacingValue(mergedOptions.paddingInline), paddingBlock: normalizeSpacingValue(mergedOptions.paddingBlock), ...style, }; // Default divider positions with between=true as default const dividerPositions = { start: false, between: true, end: false, ...mergedOptions.dividerPositions, }; // Process children for rendering const childrenArray = Children.toArray(children); const childCount = childrenArray.length; const Component = as; // Helper function to render divider based on type const renderDivider = (index, position) => { if (!mergedOptions.divider) return null; if (typeof mergedOptions.divider === 'function') { // If divider is a function, call it with props return mergedOptions.divider({ index, position }); } else { // If divider is a ReactNode, clone it to avoid React warnings about using // the same element instance in multiple locations if (isValidElement(mergedOptions.divider)) { // Add key to ensure React can properly differentiate between cloned elements return cloneElement(mergedOptions.divider, { key: `divider-${position}-${index}` }); } // For non-element ReactNodes (like strings), return as is return mergedOptions.divider; } }; return (_jsxs(Component, { className: className, style: containerStyle, ...rest, children: [childCount > 0 && mergedOptions.divider && dividerPositions.start && renderDivider(0, 'start'), childrenArray.map((child, index) => (_jsxs(Fragment, { children: [child, mergedOptions.divider && index < childCount - 1 && dividerPositions.between && renderDivider(index + 1, 'between')] }, index))), childCount > 0 && mergedOptions.divider && dividerPositions.end && renderDivider(childCount, 'end')] })); } //# sourceMappingURL=Stack.js.map