import getParents from "../get-parents" ; import type { DirectiveParameters , ExtendedHTMLElement } from "../types" ; function eachDirective ( { element , expression , evaluate , getState , evaluateDirectives , directives , } ) { const elementState = getState ( element ) ; const state = evaluate ( expression , elementState ) || [ ] ; const containerParent = element . parentElement as ExtendedHTMLElement ; if ( ! containerParent || state === containerParent . state ) { return ; } const hasParentEach = ! ! element . parentElement ?. closest ( "[x-has-each]" ) ; containerParent . state = hasParentEach ? elementState . state : state ; const initializedAlready = containerParent . children . length > 1 ; containerParent . setAttribute ( "_x" , "" ) ; const level = getParents ( element , "x-recurse" ) . length ; if ( initializedAlready ) { const amountOfItems = state . length ; const amountOfChildren = containerParent . children . length - 1 ; if ( amountOfItems > amountOfChildren ) { for ( let i = 0 ; i < amountOfItems - amountOfChildren ; i ++ ) { const templateClone = document . importNode ( element . content , true ) ; containerParent . appendChild ( templateClone . firstElementChild ) ; } } if ( amountOfItems < amountOfChildren ) { for ( let i = 0 ; i < amountOfChildren - amountOfItems ; i ++ ) { containerParent . lastElementChild ?. remove ( ) ; } } let child = containerParent . firstElementChild ?. nextElementSibling as ExtendedHTMLElement ; state . forEach ( ( value ) => { if ( child ) { child . setAttribute ( "x-state" , "" ) ; child . state = { value , level } ; const children = findFirstChildrenWith ( child , "TEMPLATE" ) ; children . forEach ( ( child ) => { if ( child . parentElement ) { ( child . parentElement as ExtendedHTMLElement ) . state = state ; } } ) ; evaluateDirectives ( directives , child ) ; child = child . nextElementSibling as ExtendedHTMLElement ; } } ) ; if ( child && state . length === 0 ) { child . remove ( ) ; } } else { state . forEach ( ( value ) => { const templateClone = document . importNode ( element . content , true ) ; const firstChild = templateClone . firstElementChild ; containerParent . appendChild ( templateClone ) ; containerParent . setAttribute ( "x-has-each" , "" ) ; let child = firstChild ; do { if ( child ) { child . setAttribute ( "x-state" , "" ) ; child . state = { value , level } ; evaluateDirectives ( directives , child ) ; } } while ( ( child = child ?. nextElementSibling ) ) ; } ) ; } } eachDirective . evaluateFrom = "top" ; function findFirstChildrenWith ( element , tagName ) { let ret = [ ] ; function recurse ( element ) { let child = element . firstElementChild ; do { if ( child ?. tagName === tagName ) { ret . push ( child as ExtendedHTMLElement ) ; } else if ( child ?. children . length ) { recurse ( child ) ; } } while ( ( child = child ?. nextElementSibling || null ) ) ; } recurse ( element ) ; return ret ; } export default eachDirective ;