@@ -57,15 +57,20 @@ export function template_to_functions(items, namespace) {
5757 */
5858 let last_current_element ;
5959
60+ // if the first item is a comment we need to add another comment for effect.start
6061 if ( items [ 0 ] . kind === 'create_anchor' ) {
6162 items . unshift ( { kind : 'create_anchor' } ) ;
6263 }
6364
6465 for ( let instruction of items ) {
66+ // on push element we add the element to the stack, from this moment on every insert will
67+ // happen on the last element in the stack
6568 if ( instruction . kind === 'push_element' && last_current_element ) {
6669 elements_stack . push ( last_current_element ) ;
6770 continue ;
6871 }
72+ // we closed one element, we remove it from the stack and eventually revert back
73+ // the namespace to the previous one
6974 if ( instruction . kind === 'pop_element' ) {
7075 const removed = elements_stack . pop ( ) ;
7176 if ( removed ?. namespaced ) {
@@ -77,14 +82,21 @@ export function template_to_functions(items, namespace) {
7782 continue ;
7883 }
7984
85+ // if the inserted node is in the svg/mathml we push the namespace to the stack because we need to
86+ // create with createElementNS
8087 if ( instruction . metadata ?. svg || instruction . metadata ?. mathml ) {
8188 namespace_stack . push ( instruction . metadata . svg ? NAMESPACE_SVG : NAMESPACE_MATHML ) ;
8289 }
8390
8491 // @ts -expect-error we can't be here if `swap_current_element` but TS doesn't know that
8592 const value = map [ instruction . kind ] (
8693 ...[
94+ // for set prop we need to send the last element (not the one in the stack since
95+ // it get's added to the stack only after the push_element instruction)...for all the rest
96+ // the first prop is a the scope to generate the name of the variable
8797 ...( instruction . kind === 'set_prop' ? [ last_current_element ] : [ scope ] ) ,
98+ // for create element we also need to add the namespace...namespaces in the stack get's precedence over
99+ // the "global" namespace (and if we are in a foreignObject we default to html)
88100 ...( instruction . kind === 'create_element'
89101 ? [
90102 foreign_object_count > 0
@@ -102,16 +114,20 @@ export function template_to_functions(items, namespace) {
102114 ) ;
103115
104116 if ( value ) {
117+ // this will compose the body of the function
105118 body . push ( value . call ) ;
106119 }
107120
121+ // with set_prop we don't need to do anything else, in all other cases we also need to
122+ // append the element/node/anchor to the current active element or push it in the elements array
108123 if ( instruction . kind !== 'set_prop' ) {
109124 if ( elements_stack . length >= 1 && value ) {
110125 const { call } = map . insert ( /** @type {Element } */ ( elements_stack . at ( - 1 ) ) , value ) ;
111126 body . push ( call ) ;
112127 } else if ( value ) {
113128 elements . push ( b . id ( value . name ) ) ;
114129 }
130+ // keep track of the last created element (it will be pushed to the stack after the props are set)
115131 if ( instruction . kind === 'create_element' ) {
116132 last_current_element = /** @type {Element } */ ( value ) ;
117133 if ( last_current_element . element === 'foreignObject' ) {
@@ -120,6 +136,7 @@ export function template_to_functions(items, namespace) {
120136 }
121137 }
122138 }
139+ // every function needs to return a fragment so we create one and push all the elements there
123140 const fragment = scope . generate ( 'fragment' ) ;
124141 body . push ( b . var ( fragment , b . call ( 'document.createDocumentFragment' ) ) ) ;
125142 body . push ( b . call ( fragment + '.append' , ...elements ) ) ;
@@ -159,6 +176,11 @@ function create_element(scope, namespace, element) {
159176 }
160177 const call = b . var ( name , b . call ( fn , ...args ) ) ;
161178 /**
179+ * if there's an "is" attribute we can't just add it as a property, it needs to be
180+ * specified on creation like this `document.createElement('button', { is: 'my-button' })`
181+ *
182+ * Since the props are appended after the creation we change the generated call arguments and we push
183+ * the is attribute later on on `set_prop`
162184 * @param {string } value
163185 */
164186 function add_is ( value ) {
@@ -208,6 +230,7 @@ function create_text(scope, value) {
208230 * @param {string } value
209231 */
210232function set_prop ( el , prop , value ) {
233+ // see comment above about the "is" attribute
211234 if ( prop === 'is' ) {
212235 el . add_is ( value ) ;
213236 return ;
@@ -217,6 +240,7 @@ function set_prop(el, prop, value) {
217240 let fn = namespace !== prop ? '.setAttributeNS' : '.setAttribute' ;
218241 let args = [ b . literal ( fix_attribute_casing ( prop ) ) , b . literal ( value ?? '' ) ] ;
219242
243+ // attributes like `xlink:href` need to be set with the `xlink` namespace
220244 if ( namespace === 'xlink' ) {
221245 args . unshift ( b . literal ( 'http://www.w3.org/1999/xlink' ) ) ;
222246 }
@@ -235,6 +259,7 @@ function set_prop(el, prop, value) {
235259function insert ( el , child , anchor ) {
236260 return {
237261 call : b . call (
262+ // if we have a template element we need to push into it's content rather than the element itself
238263 el . name + ( el . element === 'template' ? '.content' : '' ) + '.insertBefore' ,
239264 b . id ( child . name ) ,
240265 b . id ( anchor ?. name ?? 'undefined' )
0 commit comments