import Yoga , { Node , YogaNode } from 'yoga-layout-prebuilt' ; import { RawNode } from '../Register/getDataFromReactNode' ; import getSizeOfShape from './getShapeSize' ; import { DisplayMap , FlexDirectionMap , FlexWrapMap , JustifyContentMap , LayoutAlignMap , } from './LayoutEnums' ; const getFourFromNumOrArr = ( target ) => { if ( target instanceof Array ) { switch ( target . length ) { case 1 : const m = target [ 0 ] ; return [ m , m , m , m ] ; case 2 : const [ tb , lr ] = target ; return [ tb , lr , tb , lr ] ; case 3 : const [ t , lar , b ] = target ; return [ t , lar , b , lar ] ; case 4 : return target ; default : return [ 0 , 0 , 0 , 0 ] ; } } else { return [ target , target , target , target ] ; } } ; const constructYogaNode = ( node ) => { const yogaNode = Node . create ( ) ; const style = node . attrs ; if ( style . position === 'absolute' ) { yogaNode . setWidth ( 0 ) ; yogaNode . setHeight ( 0 ) ; return yogaNode ; } if ( style . alignContent ) { yogaNode . setAlignContent ( LayoutAlignMap [ style . alignContent ] ) ; } if ( style . alignItems ) { yogaNode . setAlignItems ( LayoutAlignMap [ style . alignItems ] ) ; } if ( style . alignSelf ) { yogaNode . setAlignSelf ( LayoutAlignMap [ style . alignSelf ] ) ; } if ( style . display ) { yogaNode . setDisplay ( DisplayMap [ style . display ] ) ; } else { yogaNode . setDisplay ( DisplayMap [ 'flex' ] ) ; } if ( style . flex ) { yogaNode . setFlex ( style . flex ) ; } if ( style . flexBasis ) { yogaNode . setFlexBasis ( style . flexBasis ) ; } if ( style . flexGrow ) { yogaNode . setFlexGrow ( style . flexGrow ) ; } if ( style . flexShrink ) { yogaNode . setFlexShrink ( style . flexShrink ) ; } if ( style . flexDirection ) { yogaNode . setFlexDirection ( FlexDirectionMap [ style . flexDirection ] ) ; } if ( style . flexWrap ) { yogaNode . setFlexWrap ( FlexWrapMap [ style . flexWrap ] ) ; } if ( style . justifyContent ) { yogaNode . setJustifyContent ( JustifyContentMap [ style . justifyContent ] ) ; } if ( style . maxHeight ) { yogaNode . setMaxHeight ( style . maxHeight ) ; } if ( style . minHeight ) { yogaNode . setMinHeight ( style . minHeight ) ; } if ( style . maxWidth ) { yogaNode . setMaxWidth ( style . maxWidth ) ; } if ( style . minWidth ) { yogaNode . setMinWidth ( style . minWidth ) ; } if ( style . height ) { if ( style . height === 'auto' ) { yogaNode . setHeightAuto ( ) ; } else { yogaNode . setHeight ( style . height ) ; } } if ( style . width ) { if ( style . width === 'auto' ) { yogaNode . setWidthAuto ( ) ; } else { yogaNode . setWidth ( style . width ) ; } } if ( style . margin ) { const marginArray = getFourFromNumOrArr ( style . margin ) ; if ( marginArray [ 0 ] === 'auto' ) { yogaNode . setMarginAuto ( Yoga . EDGE_TOP ) ; } else { yogaNode . setMargin ( Yoga . EDGE_TOP , Number ( marginArray [ 0 ] ) ) ; } if ( marginArray [ 1 ] === 'auto' ) { yogaNode . setMarginAuto ( Yoga . EDGE_RIGHT ) ; } else { yogaNode . setMargin ( Yoga . EDGE_RIGHT , Number ( marginArray [ 1 ] ) ) ; } if ( marginArray [ 2 ] === 'auto' ) { yogaNode . setMarginAuto ( Yoga . EDGE_BOTTOM ) ; } else { yogaNode . setMargin ( Yoga . EDGE_BOTTOM , Number ( marginArray [ 2 ] ) ) ; } if ( marginArray [ 3 ] === 'auto' ) { yogaNode . setMarginAuto ( Yoga . EDGE_LEFT ) ; } else { yogaNode . setMargin ( Yoga . EDGE_LEFT , Number ( marginArray [ 3 ] ) ) ; } } if ( style . padding ) { const paddingArray = getFourFromNumOrArr ( style . padding ) ; yogaNode . setPadding ( Yoga . EDGE_TOP , paddingArray [ 0 ] ) ; yogaNode . setPadding ( Yoga . EDGE_RIGHT , paddingArray [ 1 ] ) ; yogaNode . setPadding ( Yoga . EDGE_BOTTOM , paddingArray [ 2 ] ) ; yogaNode . setPadding ( Yoga . EDGE_LEFT , paddingArray [ 3 ] ) ; } return yogaNode ; } ; export interface LayoutedNode extends RawNode { boundaryBox : { width : number ; height : number ; x : number ; y : number ; } ; children : LayoutedNode [ ] ; } type ContainerNode = RawNode & { container : YogaNode ; children : ContainerNode [ ] ; } ; const constructNodes = ( root , basicContainer ) : ContainerNode | null => { const childrenArr = [ [ root ] ] ; const parentArr = [ ] ; let resultNode = null ; while ( childrenArr [ 0 ] ) { const children = childrenArr . pop ( ) || [ ] ; const parent = parentArr . pop ( ) ; const newChilren = [ ] ; for ( let i = 0 ; i < children ?. length ; i += 1 ) { const node = children [ i ] ; const size = getSizeOfShape ( node . type , node . attrs ) ; if ( ! node . attrs . width ) { node . attrs . width = size . width || 0 ; } if ( ! node . attrs . height ) { node . attrs . height = size . height || 0 ; } const containerNode = { ... node , container : constructYogaNode ( node ) , children : [ ] , } ; if ( node . children . length ) { parentArr . push ( containerNode ) ; childrenArr . push ( node . children ) ; } newChilren . push ( containerNode ) ; } if ( ! parent ) { resultNode = newChilren [ 0 ] ; basicContainer . insertChild ( newChilren [ 0 ] . container , 0 ) ; } else { parent . children = newChilren ; for ( let j = 0 ; j < parent . children . length ; j += 1 ) { parent . container . insertChild ( parent . children [ j ] . container , j ) ; } } } return resultNode ; } ; const caculateNodes = ( node , parentBoundaryBox ) : LayoutedNode => { const boundaryBox = { width : Number ( node . attrs . width ) || 0 , height : Number ( node . attrs . height ) || 0 , x : 0 , y : 0 , } ; let actualBondary = { ... boundaryBox } ; const { container , ... restNode } = node ; if ( restNode . attrs . position === 'absolute' ) { boundaryBox . x = restNode . attrs . x ; boundaryBox . y = restNode . attrs . y ; actualBondary = boundaryBox ; } else if ( container ) { const layout = container . getComputedLayout ( ) ; boundaryBox . width = layout . width ; boundaryBox . height = layout . height ; boundaryBox . x = layout . left + parentBoundaryBox . x ; boundaryBox . y = layout . top + parentBoundaryBox . y ; actualBondary = { ... boundaryBox } ; if ( [ 'circle' , 'ellipse' ] . includes ( restNode . type ) ) { boundaryBox . x += boundaryBox . width / 2 ; boundaryBox . y += boundaryBox . height / 2 ; } if ( restNode . type === 'text' ) { boundaryBox . y += boundaryBox . height ; } } const children = [ ] ; for ( let i = 0 ; i < restNode . children . length ; i += 1 ) { children . push ( caculateNodes ( restNode . children [ i ] , actualBondary ) ) ; } return { ... restNode , attrs : { ... restNode . attrs , ... boundaryBox , } , children , boundaryBox , } ; } ; const getPositionUsingYoga = ( root ) : LayoutedNode => { const basicContainer = Node . create ( ) ; basicContainer . setWidthAuto ( ) ; basicContainer . setHeightAuto ( ) ; const newNodes = constructNodes ( root , basicContainer ) || ( { ... root , container : basicContainer } as ContainerNode ) ; basicContainer . calculateLayout ( ) ; const result = caculateNodes ( newNodes , { width : 0 , height : 0 , x : 0 , y : 0 , } ) ; basicContainer . freeRecursive ( ) ; return result ; } ; export default getPositionUsingYoga ;