let resolveStep = () => {} let logger = () => {} export function morph(from, toHtml, options) { monkeyPatchDomSetAttributeToAllowAtSymbols() // We're defining these globals and methods inside this function (instead of outside) // because it's an async function and if run twice, they would overwrite // each other. let fromEl let toEl let key, lookahead, updating, updated, removing, removed, adding, added function assignOptions(options = {}) { let defaultGetKey = el => el.getAttribute('key') let noop = () => {} updating = options.updating || noop updated = options.updated || noop removing = options.removing || noop removed = options.removed || noop adding = options.adding || noop added = options.added || noop key = options.key || defaultGetKey lookahead = options.lookahead || false } function patch(from, to) { if (differentElementNamesTypesOrKeys(from, to)) { return swapElements(from, to) } let updateChildrenOnly = false if (shouldSkip(updating, from, to, () => updateChildrenOnly = true)) return // Initialize the server-side HTML element with Alpine... if (from.nodeType === 1 && window.Alpine) { window.Alpine.cloneNode(from, to) } if (textOrComment(to)) { patchNodeValue(from, to) updated(from, to) return } if (! updateChildrenOnly) { patchAttributes(from, to) } updated(from, to) patchChildren(from, to) } function differentElementNamesTypesOrKeys(from, to) { return from.nodeType != to.nodeType || from.nodeName != to.nodeName || getKey(from) != getKey(to) } function swapElements(from, to) { if (shouldSkip(removing, from)) return let toCloned = to.cloneNode(true) if (shouldSkip(adding, toCloned)) return from.replaceWith(toCloned) removed(from) added(toCloned) } function patchNodeValue(from, to) { let value = to.nodeValue if (from.nodeValue !== value) { // Change text node... from.nodeValue = value } } function patchAttributes(from, to) { if (from._x_transitioning) return if (from._x_isShown && ! to._x_isShown) { return } if (! from._x_isShown && to._x_isShown) { return } let domAttributes = Array.from(from.attributes) let toAttributes = Array.from(to.attributes) for (let i = domAttributes.length - 1; i >= 0; i--) { let name = domAttributes[i].name; if (! to.hasAttribute(name)) { // Remove attribute... from.removeAttribute(name) } } for (let i = toAttributes.length - 1; i >= 0; i--) { let name = toAttributes[i].name let value = toAttributes[i].value if (from.getAttribute(name) !== value) { from.setAttribute(name, value) } } } function patchChildren(from, to) { // If we hit a