import { CreatePositionChangeParams , EdgeChange , FlowElement , FlowElements , GraphNode , NodeChange , NodeDimensionChange , SelectionChange , } from '~/types' ; import { clampPosition , isGraphNode } from '~/utils/graph' ; export const applyChanges = < T extends FlowElement = GraphNode , C extends NodeChange = T extends GraphNode ? NodeChange : EdgeChange > ( changes , elements ) : T [ ] => { let elementIds = elements . map ( ( el ) => el . id ) ; changes . forEach ( ( change ) => { const i = elementIds . indexOf ( change . id ) ; const el = elements [ i ] ; if ( el ) { switch ( change . type ) { case 'select' : el . selected = change . selected ; break ; case 'dimensions' : if ( isGraphNode ( el ) ) { if ( typeof change . dimensions !== 'undefined' ) el . dimensions = change . dimensions ; if ( typeof change . position !== 'undefined' ) el . position = change . position ; if ( typeof change . dragging !== 'undefined' ) el . dragging = change . dragging ; } break ; case 'remove' : elements . splice ( i , 1 ) ; elementIds = elements . map ( ( el ) => el . id ) ; break ; } } } ) ; return elements ; } ; export const createSelectionChange = ( id , selected ) : SelectionChange => ( { id , type : 'select' , selected , } ) ; export const createPositionChange = ( { node , diff , dragging , nodeExtent } ) : NodeDimensionChange => { const change = { id : node . id , type : 'dimensions' , dragging : ! ! dragging , handleBounds : node . handleBounds , } ; if ( diff ) { const nextPosition = { x : node . position . x + diff . x , y : node . position . y + diff . y } ; let currentExtent = nodeExtent || node . extent ; if ( node . extent === 'parent' && node . parentNode && node . dimensions . width && node . dimensions . height ) { currentExtent = node . parentNode ?. dimensions . width && node . parentNode ?. dimensions . height ? [ [ 0 , 0 ] , [ node . parentNode . dimensions . width - node . dimensions . width , node . parentNode . dimensions . height - node . dimensions . height , ] , ] : currentExtent ; } change . position = currentExtent ? clampPosition ( nextPosition , currentExtent ) : nextPosition ; } return change ; } ; const isParentSelected = ( node , selectedIds ) : boolean => { if ( ! node . parentNode ) return false ; if ( selectedIds . includes ( node . parentNode . id ) ) return true ; return isParentSelected ( node . parentNode , selectedIds ) ; } ; export const getSelectionChanges = ( items , selectedIds ) => { return items . reduce ( ( res , item ) => { const willBeSelected = selectedIds . includes ( item . id ) || ! ! ( isGraphNode ( item ) && item . parentNode && isParentSelected ( item , selectedIds ) ) ; if ( ! item . selected && willBeSelected ) { res . push ( createSelectionChange ( item . id , true ) ) ; } else if ( item . selected && ! willBeSelected ) { res . push ( createSelectionChange ( item . id , false ) ) ; } return res ; } , [ ] as SelectionChange [ ] ) ; } ;