import { memo, forwardRef, cloneElement, Children, useMemo } from 'react'; import { View, ViewStyle, type ViewProps } from 'react-native'; import { isNil } from '../../utils'; import { elementGroupStyles } from './utils'; export enum Orientation { Horizontal = 'horizontal', Vertical = 'vertical', } export type Props = Omit & { orientation?: `${Orientation}`; borderRadius?: number | string; style?: ViewStyle; }; export const ElementGroup = ( { orientation: orientationProp = Orientation.Horizontal, children, style, borderRadius: borderRadiusProp, ...props }: Props, ref: any, ) => { const orientation = orientationProp === Orientation.Vertical ? 'vertial' : 'horizontal'; elementGroupStyles.useVariants({ orientation: orientation as any, }); // const componentStyles = useComponentStyles( // 'ElementGroup', // [style, !isNil(borderRadiusProp) ? { borderRadius: borderRadiusProp } : {}], // { // orientation: orientation === Orientation.Vertical ? 'vertial' : 'horizontal', // }, // ); const { containerStyle, borderRadius, borderRadiuses } = useMemo(() => { const { borderRadius: _borderRadius, borderTopLeftRadius, borderTopRightRadius, borderBottomLeftRadius, borderBottomRightRadius, ...restStyle } = elementGroupStyles.root as any; const { borderTopLeftRadius: _borderTopLeftRadius, borderTopRightRadius: _borderTopRightRadius, borderBottomLeftRadius: _borderBottomLeftRadius, borderBottomRightRadius: _borderBottomRightRadius, ..._restStyle } = style ?? {}; return { containerStyle: [restStyle, _restStyle], borderRadius: borderRadiusProp || _borderRadius, borderRadiuses: { borderTopLeftRadius: borderTopLeftRadius || _borderTopLeftRadius, borderTopRightRadius: borderTopRightRadius || _borderTopRightRadius, borderBottomLeftRadius: borderBottomLeftRadius || _borderBottomLeftRadius, borderBottomRightRadius: borderBottomRightRadius || _borderBottomRightRadius, }, }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [style, borderRadiusProp, orientation]); const modifiedChildren = useMemo(() => { if (!children) return null; if (!Array.isArray(children) || children.length <= 1) return children; // if we have enough elements for left, right return Children.map(children, (child: JSX.Element, index) => { const [firstBorderProp, lastBorderProp] = { [Orientation.Horizontal]: ['borderTopRightRadius', 'borderBottomLeftRadius'], [Orientation.Vertical]: ['borderBottomLeftRadius', 'borderTopRightRadius'], }[orientation as Orientation]; const isFirstChild = index === 0; const isLastChild = index === children.length - 1; const prop = isFirstChild ? 'first' : isLastChild ? 'last' : 'middle'; type KeyOfBorderRadiuses = keyof typeof borderRadiuses; const mapBorderRadiusFromProp = { [firstBorderProp]: !isNil(borderRadiuses[firstBorderProp as KeyOfBorderRadiuses]) ? borderRadiuses[firstBorderProp as KeyOfBorderRadiuses] : borderRadius, [lastBorderProp]: !isNil(borderRadiuses[lastBorderProp as KeyOfBorderRadiuses]) ? borderRadiuses[lastBorderProp as KeyOfBorderRadiuses] : borderRadius, }; const borderRadiusStyles = { first: { [firstBorderProp]: 0, borderBottomRightRadius: 0, borderTopLeftRadius: !isNil(borderRadiuses.borderTopLeftRadius) ? borderRadiuses.borderTopLeftRadius : borderRadius, [lastBorderProp]: mapBorderRadiusFromProp[lastBorderProp], }, middle: { borderTopLeftRadius: 0, borderBottomRightRadius: 0, borderTopRightRadius: 0, borderBottomLeftRadius: 0, }, last: { borderTopLeftRadius: 0, [lastBorderProp]: 0, borderBottomRightRadius: !isNil(borderRadiuses.borderBottomRightRadius) ? borderRadiuses.borderBottomRightRadius : borderRadius, [firstBorderProp]: mapBorderRadiusFromProp[firstBorderProp], }, }; return cloneElement(child, { ...child.props, style: [child.props.style, borderRadiusStyles[prop]].flat(), }); }); }, [borderRadius, borderRadiuses, children, orientation]); return ( {modifiedChildren} ); }; export default memo(forwardRef(ElementGroup));