/* eslint-disable react/self-closing-comp */ /* eslint-disable @typescript-eslint/ban-ts-comment */ /* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable @typescript-eslint/ban-types */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/unbound-method */ import React, { Children, Component, JSXElementConstructor, ReactElement, } from 'react'; import classnames from 'classnames'; import './index.scss'; export enum Direction { '横向' = 'hoz', '纵向' = 'ver', '未知' = 'unknown', } const verDirect = ['top', 'bottom']; const hozDirect = ['left', 'right']; const arrangeStyle = { 'flex-wrap': 'wrap', 'justify-content': 'flex-start', 'align-content': 'flex-start', 'flex-direction': 'row', }; // 默认纵向, 垂直方向 function getDirection(children: any) { let direction: Direction = Direction.未知; Children.forEach(children, (item) => { if ( item?.type?.role !== 'content' && direction === Direction.未知 && typeof item === 'object' ) { const role: string = item?.type?.role || ''; const isVer = verDirect.includes(role); const isHoz = hozDirect.includes(role); if (isVer) { direction = Direction.纵向; } else if (isHoz) { direction = Direction.横向; } } }); return direction === Direction.未知 ? Direction.纵向 : direction; } // 默认所有项都是自动撑开,左右top、bottom、right、left、或者定义了size的分别是根据孩子宽度或者具体大小固定的。 function renderChildren( child: any, inDirection: Direction, interval: number, ): null | ReactElement { if (!child) { return null; } if (Symbol.for('react.fragment') === child.type) { return React.cloneElement(child, { ...child.props, children: Children.map(child.props.children, (item) => { renderChildren(item, inDirection, interval); }), }); } if (React.isValidElement(child)) { const $type: any = child.type; const props: any = child.props; const newPorps = { ...props }; // 这种写法 对于百分比难以控制, 故而放弃掉了 // if (interval && $type.role) { // newPorps.style = Object.assign({}, newPorps.style, { // [inDirection === Direction.横向 ? 'marginRight' : 'marginBottom']: // interval, // }); // } if (props.size) { newPorps.style = Object.assign({ overflow: 'auto' }, newPorps.style, { 'flex-basis': props.size, }); } else { if (props.auto || $type.role === 'layout' || $type.role === 'content') { newPorps.className = classnames( newPorps.className, newPorps.className ?? '', 'auto', ); } } return React.cloneElement(child, newPorps); } return child; } type childType = | ReactElement | (() => ReactElement>); type childArrayType = childType[]; export interface baselayoutI { children: childType; style: object | undefined; className: string; padding?: boolean | number; hoz?: boolean; // 下面6个设置子节点排列 middle?: boolean; center?: boolean; left?: boolean; right?: boolean; top?: boolean; bottom?: boolean; // 排列,默认的排列方式 arrange?: number | false | number[]; arrangeInterval: number; interval?: number; maxHeight?: number; minHeight?: number; // 样式 white?: boolean; radius?: boolean; radiusTop?: boolean; radiusBottom?: boolean; } export default function BaseLayout(props: baselayoutI) { const { children, className, style = {}, padding = false, hoz, middle, center, left, right, top, bottom, arrange = false, interval = 0, arrangeInterval = 0, maxHeight, minHeight, white = false, radius = false, radiusTop = false, radiusBottom = false, ...restProp } = props; let direction = hoz ? Direction.横向 : getDirection(children); // 排列 > direction // interval 能力 垂直下面 let finalChildren = Children.toArray(children).map((item, index) => renderChildren( item, direction, index === Children.count(children) - 1 ? 0 : interval ?? 0, ), ); // 排列能力构建 if ( parseInt(arrange as unknown as string, 10) > 0 || Array.isArray(arrange) ) { const spitNum: number = ( Array.isArray(arrange) ? arrange.length : arrange ) as number; direction = Direction.横向; const splitChildArray = Array(spitNum) .fill(false) .map(() => []); for (let i = 0; i < finalChildren.length; i++) { const splitBelong = i % spitNum; // @ts-ignore splitChildArray[splitBelong].push(finalChildren[i]); if ( arrangeInterval > 0 && Math.floor(i / spitNum) !== Math.floor(finalChildren.length / spitNum) ) { splitChildArray[splitBelong].push( /* @ts-ignore */
, ); } } finalChildren = Array(spitNum) .fill(false) .map((item, index: number) => (
{splitChildArray[index]}
)); } if (interval) { const len = finalChildren.length; for (let i = 0; i < len - 1; i++) { finalChildren.splice( i * 2 + 1, 0,
, ); } } const finalClassName = classnames( 'operate-components-layout-item', className, { ver: direction === 'ver', hoz: direction === 'hoz', middle, center, left, right, top, bottom, white, radius, 'radius-top': radiusTop, 'radius-bottom': radiusBottom, }, ); const finalStyle = { padding: padding === true ? '0 16px' : padding || '', minHeight, maxHeight, ...(style || {}), }; return (
{finalChildren}
); }