import deindent from '../../../../utils/deindent'; import visit from '../../visit'; import visitComponent from '../Component/Component'; import visitWindow from './meta/Window'; import visitAttribute from './Attribute'; import visitEventHandler from './EventHandler'; import visitBinding from './Binding'; import visitRef from './Ref'; import addTransitions from './addTransitions'; import { DomGenerator } from '../../index'; import Block from '../../Block'; import { Node } from '../../../../interfaces'; import { State } from '../../interfaces'; const meta = { ':Window': visitWindow, }; const order = { Attribute: 1, Binding: 2, EventHandler: 3, Ref: 4, }; const visitors = { Attribute: visitAttribute, EventHandler: visitEventHandler, Binding: visitBinding, Ref: visitRef, }; export default function visitElement( generator: DomGenerator, block: Block, state: State, node: Node ) { if (node.name in meta) { return meta[node.name](generator, block, node); } if (generator.components.has(node.name) || node.name === ':Self') { return visitComponent(generator, block, state, node); } const childState = node._state; const name = childState.parentNode; block.builders.create.addLine( `var ${name} = ${getRenderStatement( generator, childState.namespace, node.name )};` ); block.mount(name, state.parentNode); // add CSS encapsulation attribute if (generator.cssId && (!generator.cascade || state.isTopLevel)) { block.builders.create.addLine( `${generator.helper( 'setAttribute' )}( ${name}, '${generator.cssId}', '' );` ); } function visitAttributesAndAddProps() { let intro; let outro; node.attributes .sort((a: Node, b: Node) => order[a.type] - order[b.type]) .forEach((attribute: Node) => { if (attribute.type === 'Transition') { if (attribute.intro) intro = attribute; if (attribute.outro) outro = attribute; return; } visitors[attribute.type](generator, block, childState, node, attribute); }); if (intro || outro) addTransitions(generator, block, childState, node, intro, outro); if (childState.allUsedContexts.length || childState.usesComponent) { const initialProps: string[] = []; const updates: string[] = []; if (childState.usesComponent) { initialProps.push(`component: ${block.component}`); } childState.allUsedContexts.forEach((contextName: string) => { if (contextName === 'state') return; const listName = block.listNames.get(contextName); const indexName = block.indexNames.get(contextName); initialProps.push( `${listName}: ${listName},\n${indexName}: ${indexName}` ); updates.push( `${name}._svelte.${listName} = ${listName};\n${name}._svelte.${indexName} = ${indexName};` ); }); if (initialProps.length) { block.builders.create.addBlock(deindent` ${name}._svelte = { ${initialProps.join(',\n')} }; `); } if (updates.length) { block.builders.update.addBlock(updates.join('\n')); } } } if (!state.parentNode) { // TODO we eventually need to consider what happens to elements // that belong to the same outgroup as an outroing element... block.builders.unmount.addLine( `${generator.helper('detachNode')}( ${name} );` ); } if (node.name !== 'select') { if (node.name === 'textarea') { // this is an egregious hack, but it's the easiest way to get