import { LIST, SECTION, ELLIPSE, GROUP, IMAGE, FORM, WRAPPER, LAYOUT_SECTION, } from '@adalo/constants' import { PushNode } from './buildPushTree' import { getChildrenHeights, getChildrenHeightsForList, getChildrenHeightsForSection, } from './getHeights' export const getOriginalLowerEdge = (pushNode: PushNode): number => pushNode.originalY + pushNode.originalHeight export const getLowerEdge = (pushNode: PushNode): number => { if (!pushNode.dataNode) { throw new Error('getLowerEdge -> pushNode without dataNode') } return pushNode.originalY + pushNode.dataNode.height + pushNode.yOffset } export const getOriginalUpperBound = (pushedBy: PushNode[]): number => { const originalFirstLowerEdge = getOriginalLowerEdge(pushedBy[0]) const upperBound = pushedBy.reduce( (maxUpperBound: number, pushingNode: PushNode): number => Math.max(maxUpperBound, getOriginalLowerEdge(pushingNode)), originalFirstLowerEdge ) return upperBound } export const getYOffset = (pushNode: PushNode): number => { if (pushNode.dataNode) { const { pushedBy } = pushNode const upperBound = getOriginalUpperBound(pushedBy) const firstPushingYOffset = getLowerEdge(pushedBy[0]) - upperBound return pushedBy.reduce( (yOffset: number, pushingNode: PushNode): number => Math.max(yOffset, getLowerEdge(pushingNode) - upperBound), firstPushingYOffset ) } else { console.error({ pushNode }) throw new Error('getYOffset -> pushNode without dataNode') } } export const yOffsetChanged = (pushNode: PushNode): void => { // eslint-disable-next-line no-param-reassign pushNode.yOffset = 0 if (pushNode.pushedBy.length > 0) { // eslint-disable-next-line no-param-reassign pushNode.yOffset = getYOffset(pushNode) } // eslint-disable-next-line @typescript-eslint/no-use-before-define makePush(pushNode) } export const makePush = (pushNode: PushNode): void => { pushNode.pushes.forEach(pushedNode => yOffsetChanged(pushedNode)) } export const SECTION_TYPES: Set = new Set([ IMAGE, SECTION, ELLIPSE, LAYOUT_SECTION, // renders as SECTION in components/LayoutSection.tsx ]) export const isSection = ({ type }: PushNode): boolean => SECTION_TYPES.has(type) // prettier-ignore export const calculateHeightFromChildren = (pushNode: PushNode): void => { let newHeight // Components hidden by conditional visibility shouldn't have an updated height if (!pushNode.dataNode?.visible && pushNode.dataNode?.visibleOnDevice) { return } if (pushNode.type === LIST) { newHeight = getChildrenHeightsForList(pushNode) if (pushNode?.options?.manualPagination) { const fixedPaginationHeight = 35 newHeight += fixedPaginationHeight } } else if (isSection(pushNode)) { newHeight = getChildrenHeightsForSection(pushNode) } else if ( pushNode.type === GROUP || pushNode.type === FORM || pushNode.type === WRAPPER || pushNode.type === 'LIST_ITEM' ) { newHeight = getChildrenHeights(pushNode) } else { throw new Error( `An unsupported type ${pushNode.type} has children, supported types include: SECTION, ELLIPSE, IMAGE, LIST, FORM` ) } heightChanged(pushNode, newHeight) } export const heightChanged = (pushNode: PushNode, newHeight: number) => { if (!pushNode.dataNode) { console.error({ pushNode }) throw new Error('heightChanged -> pushNode without dataNode') } const heightDidntChange = pushNode.dataNode.height === newHeight if (heightDidntChange) { return } pushNode.dataNode.height = newHeight makePush(pushNode) if (pushNode?.parent) { calculateHeightFromChildren(pushNode.parent) } }