UNPKG

holakit

Version:

Yet another design-driven UI component set.

3,814 lines 171 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
/**
 * SSR Attribute Names
 */
var SSR_VNODE_ID = 'ssrv';
var SSR_CHILD_ID = 'ssrc';
/**
 * Default style mode id
 */
var DEFAULT_STYLE_MODE = '$';
/**
 * Reusable empty obj/array
 * Don't add values to these!!
 */
var EMPTY_OBJ = {};
/**
 * Key Name to Key Code Map
 */
var KEY_CODE_MAP = {
    'enter': 13,
    'escape': 27,
    'space': 32,
    'tab': 9,
    'left': 37,
    'up': 38,
    'right': 39,
    'down': 40
};
function getScopeId(cmpMeta, mode) {
    return ('sc-' + cmpMeta.tagNameMeta) + ((mode && mode !== DEFAULT_STYLE_MODE) ? '-' + mode : '');
}
function getElementScopeId(scopeId, isHostElement) {
    return scopeId + (isHostElement ? '-h' : '-s');
}
function initStyleTemplate(domApi, cmpMeta, encapsulation, style, styleMode, perf) {
    if (style) {
        if (false) {
            perf.mark("init_style_template_start:" + cmpMeta.tagNameMeta);
        }
        // we got a style mode for this component, let's create an id for this style
        var styleModeId = cmpMeta.tagNameMeta + (styleMode || DEFAULT_STYLE_MODE);
        if (!cmpMeta[styleModeId]) {
            // we don't have this style mode id initialized yet
            if (true) {
                // ie11's template polyfill doesn't fully do the trick and there's still issues
                // so instead of trying to clone templates with styles in them, we'll just
                // keep a map of the style text as a string to create <style> elements for es5 builds
                cmpMeta[styleModeId] = style;
            }
            else {
                // use <template> elements to clone styles
                // create the template element which will hold the styles
                // adding it to the dom via <template> so that we can
                // clone this for each potential shadow root that will need these styles
                // otherwise it'll be cloned and added to document.body.head
                // but that's for the renderer to figure out later
                var templateElm = domApi.$createElement('template');
                // keep a reference to this template element within the
                // Constructor using the style mode id as the key
                cmpMeta[styleModeId] = templateElm;
                // add the style text to the template element's innerHTML
                if (false) {
                    // hot module replacement enabled
                    // add a style id attribute, but only useful during dev
                    var styleContent = ["<style", " data-style-tag=\"" + cmpMeta.tagNameMeta + "\""];
                    domApi.$setAttribute(templateElm, 'data-tmpl-style-tag', cmpMeta.tagNameMeta);
                    if (styleMode) {
                        styleContent.push(" data-style-mode=\"" + styleMode + "\"");
                        domApi.$setAttribute(templateElm, 'data-tmpl-style-mode', styleMode);
                    }
                    if (encapsulation === 2 /* ScopedCss */ || (encapsulation === 1 /* ShadowDom */ && !domApi.$supportsShadowDom)) {
                        styleContent.push(" data-style-scoped=\"true\"");
                        domApi.$setAttribute(templateElm, 'data-tmpl-style-scoped', 'true');
                    }
                    styleContent.push(">");
                    styleContent.push(style);
                    styleContent.push("</style>");
                    templateElm.innerHTML = styleContent.join('');
                }
                else {
                    // prod mode, no style id data attributes
                    templateElm.innerHTML = "<style>" + style + "</style>";
                }
                // add our new template element to the head
                // so it can be cloned later
                domApi.$appendChild(domApi.$doc.head, templateElm);
            }
        }
        if (false) {
            perf.mark("init_style_template_end:" + cmpMeta.tagNameMeta);
            perf.measure("init_style_template:" + cmpMeta.tagNameMeta, "init_style_template_start:" + cmpMeta.tagNameMeta, "init_style_template_end:" + cmpMeta.tagNameMeta);
        }
    }
}
function attachStyles(plt, domApi, cmpMeta, hostElm) {
    // first see if we've got a style for a specific mode
    // either this host element should use scoped css
    // or it wants to use shadow dom but the browser doesn't support it
    // create a scope id which is useful for scoped css
    // and add the scope attribute to the host
    // create the style id w/ the host element's mode
    var styleId = cmpMeta.tagNameMeta + hostElm.mode;
    var styleTemplate = cmpMeta[styleId];
    var shouldScopeCss = (cmpMeta.encapsulationMeta === 2 /* ScopedCss */ || (cmpMeta.encapsulationMeta === 1 /* ShadowDom */ && !plt.domApi.$supportsShadowDom));
    if (shouldScopeCss) {
        hostElm['s-sc'] = styleTemplate
            ? getScopeId(cmpMeta, hostElm.mode)
            : getScopeId(cmpMeta);
    }
    if (!styleTemplate) {
        // doesn't look like there's a style template with the mode
        // create the style id using the default style mode and try again
        styleId = cmpMeta.tagNameMeta + DEFAULT_STYLE_MODE;
        styleTemplate = cmpMeta[styleId];
    }
    if (styleTemplate) {
        // cool, we found a style template element for this component
        var styleContainerNode = domApi.$doc.head;
        // if this browser supports shadow dom, then let's climb up
        // the dom and see if we're within a shadow dom
        if (true && domApi.$supportsShadowDom) {
            if (cmpMeta.encapsulationMeta === 1 /* ShadowDom */) {
                // we already know we're in a shadow dom
                // so shadow root is the container for these styles
                styleContainerNode = hostElm.shadowRoot;
            }
            else {
                // climb up the dom and see if we're in a shadow dom
                var root = hostElm;
                while (root = domApi.$parentNode(root)) {
                    if (root.host && root.host.shadowRoot) {
                        // looks like we are in shadow dom, let's use
                        // this shadow root as the container for these styles
                        styleContainerNode = (root.host.shadowRoot);
                        break;
                    }
                }
            }
        }
        // if this container element already has these styles
        // then there's no need to apply them again
        // create an object to keep track if we'ready applied this component style
        var appliedStyles = plt.componentAppliedStyles.get(styleContainerNode);
        if (!appliedStyles) {
            plt.componentAppliedStyles.set(styleContainerNode, appliedStyles = {});
        }
        // check if we haven't applied these styles to this container yet
        if (!appliedStyles[styleId]) {
            var styleElm = void 0;
            if (true) {
                // es5 builds are not usig <template> because of ie11 issues
                // instead the "template" is just the style text as a string
                // create a new style element and add as innerHTML
                if (true && plt.customStyle) {
                    styleElm = plt.customStyle.createHostStyle(hostElm, styleId, styleTemplate);
                }
                else {
                    styleElm = domApi.$createElement('style');
                    styleElm.innerHTML = styleTemplate;
                    // remember we don't need to do this again for this element
                    appliedStyles[styleId] = true;
                }
                if (styleElm) {
                    if (false) {
                        // add a style attributes, but only useful during dev
                        domApi.$setAttribute(styleElm, 'data-style-tag', cmpMeta.tagNameMeta);
                        if (hostElm.mode) {
                            domApi.$setAttribute(styleElm, 'data-style-mode', cmpMeta.tagNameMeta);
                        }
                        if (hostElm['s-sc']) {
                            domApi.$setAttribute(styleElm, 'data-style-scoped', 'true');
                        }
                    }
                    var dataStyles = styleContainerNode.querySelectorAll('[data-styles]');
                    domApi.$insertBefore(styleContainerNode, styleElm, (dataStyles.length && dataStyles[dataStyles.length - 1].nextSibling) || styleContainerNode.firstChild);
                }
            }
            else {
                // this browser supports the <template> element
                // and all its native content.cloneNode() goodness
                // clone the template element to create a new <style> element
                styleElm = styleTemplate.content.cloneNode(true);
                // remember we don't need to do this again for this element
                appliedStyles[styleId] = true;
                // let's make sure we put the styles below the <style data-styles> element
                // so any visibility css overrides the default
                var dataStyles = styleContainerNode.querySelectorAll('[data-styles]');
                domApi.$insertBefore(styleContainerNode, styleElm, (dataStyles.length && dataStyles[dataStyles.length - 1].nextSibling) || styleContainerNode.firstChild);
            }
        }
    }
}
var isDef = function (v) { return v != null; };
var toLowerCase = function (str) { return str.toLowerCase(); };
var dashToPascalCase = function (str) { return toLowerCase(str).split('-').map(function (segment) { return segment.charAt(0).toUpperCase() + segment.slice(1); }).join(''); };
var noop = function () { };
function createDomApi(App, win, doc) {
    // using the $ prefix so that closure is
    // cool with property renaming each of these
    if (!App.ael) {
        App.ael = function (elm, eventName, cb, opts) { return elm.addEventListener(eventName, cb, opts); };
        App.rel = function (elm, eventName, cb, opts) { return elm.removeEventListener(eventName, cb, opts); };
    }
    var unregisterListenerFns = new WeakMap();
    if (true) {
        if (typeof win.CustomEvent !== 'function') {
            // CustomEvent polyfill
            win.CustomEvent = function (event, data, evt) {
                evt = doc.createEvent('CustomEvent');
                data = data || {};
                evt.initCustomEvent(event, data.bubbles, data.cancelable, data.detail);
                return evt;
            };
            win.CustomEvent.prototype = win.Event.prototype;
        }
    }
    var domApi = {
        $doc: doc,
        $supportsShadowDom: !!doc.documentElement.attachShadow,
        $supportsEventOptions: false,
        $nodeType: function (node) { return node.nodeType; },
        $createElement: function (tagName) { return doc.createElement(tagName); },
        $createElementNS: function (namespace, tagName) { return doc.createElementNS(namespace, tagName); },
        $createTextNode: function (text) { return doc.createTextNode(text); },
        $createComment: function (data) { return doc.createComment(data); },
        $insertBefore: function (parentNode, childNode, referenceNode) { return parentNode.insertBefore(childNode, referenceNode); },
        // https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove
        // and it's polyfilled in es5 builds
        $remove: function (node) { return node.remove(); },
        $appendChild: function (parentNode, childNode) { return parentNode.appendChild(childNode); },
        $addClass: function (elm, cssClass) {
            if (true && true) {
                if (elm.classList) {
                    elm.classList.add(cssClass);
                }
                else if (elm.nodeName.toLowerCase() === 'svg') {
                    // https://caniuse.com/#search=classList
                    // IE11 really does not do <svg> properly :-/
                    var cssClasses = elm.getAttribute('class') || '';
                    if (!(cssClasses.split(' ').includes(cssClass))) {
                        cssClasses += " " + cssClass;
                    }
                    elm.setAttribute('class', cssClasses.trim());
                }
            }
            else {
                elm.classList.add(cssClass);
            }
        },
        $childNodes: function (node) { return node.childNodes; },
        $parentNode: function (node) { return node.parentNode; },
        $nextSibling: function (node) { return node.nextSibling; },
        $previousSibling: function (node) { return node.previousSibling; },
        $tagName: function (elm) { return toLowerCase(elm.nodeName); },
        $getTextContent: function (node) { return node.textContent; },
        $setTextContent: function (node, text) { return node.textContent = text; },
        $getAttribute: function (elm, key) { return elm.getAttribute(key); },
        $setAttribute: function (elm, key, val) { return elm.setAttribute(key, val); },
        $setAttributeNS: function (elm, namespaceURI, qualifiedName, val) { return elm.setAttributeNS(namespaceURI, qualifiedName, val); },
        $removeAttribute: function (elm, key) { return elm.removeAttribute(key); },
        $hasAttribute: function (elm, key) { return elm.hasAttribute(key); },
        $getMode: function (elm) { return elm.getAttribute('mode') || (App.Context || {}).mode; },
        $elementRef: function (elm, referenceName) {
            if (referenceName === 'child') {
                return elm.firstElementChild;
            }
            if (referenceName === 'parent') {
                return domApi.$parentElement(elm);
            }
            if (referenceName === 'body') {
                return doc.body;
            }
            if (referenceName === 'document') {
                return doc;
            }
            if (referenceName === 'window') {
                return win;
            }
            return elm;
        },
        $addEventListener: function (assignerElm, eventName, listenerCallback, useCapture, usePassive, attachTo, eventListenerOpts, splt) {
            // remember the original name before we possibly change it
            var assignersEventName = eventName;
            var attachToElm = assignerElm;
            // get the existing unregister listeners for
            // this element from the unregister listeners weakmap
            var assignersUnregListeners = unregisterListenerFns.get(assignerElm);
            if (assignersUnregListeners && assignersUnregListeners[assignersEventName]) {
                // removed any existing listeners for this event for the assigner element
                // this element already has this listener, so let's unregister it now
                assignersUnregListeners[assignersEventName]();
            }
            if (typeof attachTo === 'string') {
                // attachTo is a string, and is probably something like
                // "parent", "window", or "document"
                // and the eventName would be like "mouseover" or "mousemove"
                attachToElm = domApi.$elementRef(assignerElm, attachTo);
            }
            else if (typeof attachTo === 'object') {
                // we were passed in an actual element to attach to
                attachToElm = attachTo;
            }
            else {
                // depending on the event name, we could actually be attaching
                // this element to something like the document or window
                splt = eventName.split(':');
                if (splt.length > 1) {
                    // document:mousemove
                    // parent:touchend
                    // body:keyup.enter
                    attachToElm = domApi.$elementRef(assignerElm, splt[0]);
                    eventName = splt[1];
                }
            }
            if (!attachToElm) {
                // somehow we're referencing an element that doesn't exist
                // let's not continue
                return;
            }
            var eventListener = listenerCallback;
            // test to see if we're looking for an exact keycode
            splt = eventName.split('.');
            if (splt.length > 1) {
                // looks like this listener is also looking for a keycode
                // keyup.enter
                eventName = splt[0];
                eventListener = function (ev) {
                    // wrap the user's event listener with our own check to test
                    // if this keyboard event has the keycode they're looking for
                    if (ev.keyCode === KEY_CODE_MAP[splt[1]]) {
                        listenerCallback(ev);
                    }
                };
            }
            // create the actual event listener options to use
            // this browser may not support event options
            eventListenerOpts = domApi.$supportsEventOptions ? {
                capture: !!useCapture,
                passive: !!usePassive
            } : !!useCapture;
            // ok, good to go, let's add the actual listener to the dom element
            App.ael(attachToElm, eventName, eventListener, eventListenerOpts);
            if (!assignersUnregListeners) {
                // we don't already have a collection, let's create it
                unregisterListenerFns.set(assignerElm, assignersUnregListeners = {});
            }
            // add the unregister listener to this element's collection
            assignersUnregListeners[assignersEventName] = function () {
                // looks like it's time to say goodbye
                attachToElm && App.rel(attachToElm, eventName, eventListener, eventListenerOpts);
                assignersUnregListeners[assignersEventName] = null;
            };
        },
        $removeEventListener: function (elm, eventName) {
            // get the unregister listener functions for this element
            var assignersUnregListeners = unregisterListenerFns.get(elm);
            if (assignersUnregListeners) {
                // this element has unregister listeners
                if (eventName) {
                    // passed in one specific event name to remove
                    assignersUnregListeners[eventName] && assignersUnregListeners[eventName]();
                }
                else {
                    // remove all event listeners
                    Object.keys(assignersUnregListeners).forEach(function (assignersEventName) {
                        assignersUnregListeners[assignersEventName] && assignersUnregListeners[assignersEventName]();
                    });
                }
            }
        },
        $dispatchEvent: function (elm, eventName, data) {
            // create and return the custom event, allows for cancel checks
            var e = new win.CustomEvent(eventName, data);
            elm && elm.dispatchEvent(e);
            return e;
        },
        $parentElement: function (elm, parentNode) {
            // if the parent node is a document fragment (shadow root)
            // then use the "host" property on it
            // otherwise use the parent node
            return ((parentNode = domApi.$parentNode(elm)) && domApi.$nodeType(parentNode) === 11 /* DocumentFragment */) ? parentNode.host : parentNode;
        }
    };
    if (false) {
        if (win.location.search.indexOf('shadow=false') > 0) {
            // by adding ?shadow=false it'll force the slot polyfill
            // only add this check when in dev mode
            domApi.$supportsShadowDom = false;
        }
    }
    if (true) {
        domApi.$attachShadow = function (elm, shadowRootInit) { return elm.attachShadow(shadowRootInit); };
    }
    if (false || false) {
        // test if this browser supports event options or not
        try {
            win.addEventListener('e', null, Object.defineProperty({}, 'passive', {
                get: function () { return domApi.$supportsEventOptions = true; }
            }));
        }
        catch (e) { }
    }
    return domApi;
}
function elementHasProperty(plt, elm, memberName) {
    // within the browser, the element's prototype
    // already has its getter/setter set, but on the
    // server the prototype is shared causing issues
    // so instead the server's elm has the getter/setter
    // directly on the actual element instance, not its prototype
    // so at the time of this function being called, the server
    // side element is unaware if the element has this property
    // name. So for server-side only, do this trick below
    // don't worry, this runtime code doesn't show on the client
    var hasOwnProperty = elm.hasOwnProperty(memberName);
    if (!hasOwnProperty) {
        // element doesn't
        var cmpMeta = plt.getComponentMeta(elm);
        if (cmpMeta) {
            if (cmpMeta.componentConstructor && cmpMeta.componentConstructor.properties) {
                // if we have the constructor property data, let's check that
                var member = cmpMeta.componentConstructor.properties[memberName];
                hasOwnProperty = !!(member && member.type);
            }
            if (!hasOwnProperty && cmpMeta.membersMeta) {
                // if we have the component's metadata, let's check that
                var member = cmpMeta.membersMeta[memberName];
                hasOwnProperty = !!(member && member.propType);
            }
        }
    }
    return hasOwnProperty;
}
function updateAttribute(elm, memberName, newValue, isBooleanAttr) {
    if (isBooleanAttr === void 0) { isBooleanAttr = typeof newValue === 'boolean'; }
    var isXlinkNs = (memberName !== (memberName = memberName.replace(/^xlink\:?/, '')));
    if (newValue == null || (isBooleanAttr && (!newValue || newValue === 'false'))) {
        if (isXlinkNs) {
            elm.removeAttributeNS(XLINK_NS$1, toLowerCase(memberName));
        }
        else {
            elm.removeAttribute(memberName);
        }
    }
    else if (typeof newValue !== 'function') {
        if (isBooleanAttr) {
            newValue = '';
        }
        else {
            newValue = newValue.toString();
        }
        if (isXlinkNs) {
            elm.setAttributeNS(XLINK_NS$1, toLowerCase(memberName), newValue);
        }
        else {
            elm.setAttribute(memberName, newValue);
        }
    }
}
var XLINK_NS$1 = 'http://www.w3.org/1999/xlink';
function setAccessor(plt, elm, memberName, oldValue, newValue, isSvg, isHostElement) {
    if (memberName === 'class' && !isSvg) {
        // Class
        if (oldValue !== newValue) {
            var oldList_1 = parseClassList(oldValue);
            var newList_1 = parseClassList(newValue);
            // remove classes in oldList, not included in newList
            var toRemove_1 = oldList_1.filter(function (item) { return !newList_1.includes(item); });
            var classList_1 = parseClassList(elm.className)
                .filter(function (item) { return !toRemove_1.includes(item); });
            // add classes from newValue that are not in oldList or classList
            var toAdd = newList_1.filter(function (item) { return !oldList_1.includes(item) && !classList_1.includes(item); });
            classList_1.push.apply(classList_1, toAdd);
            elm.className = classList_1.join(' ');
        }
    }
    else if (memberName === 'style') {
        // update style attribute, css properties and values
        for (var prop in oldValue) {
            if (!newValue || newValue[prop] == null) {
                if (/-/.test(prop)) {
                    elm.style.removeProperty(prop);
                }
                else {
                    elm.style[prop] = '';
                }
            }
        }
        for (var prop in newValue) {
            if (!oldValue || newValue[prop] !== oldValue[prop]) {
                if (/-/.test(prop)) {
                    elm.style.setProperty(prop, newValue[prop]);
                }
                else {
                    elm.style[prop] = newValue[prop];
                }
            }
        }
    }
    else if ((memberName[0] === 'o' && memberName[1] === 'n' && /[A-Z]/.test(memberName[2])) && (!(memberName in elm))) {
        // Event Handlers
        // so if the member name starts with "on" and the 3rd characters is
        // a capital letter, and it's not already a member on the element,
        // then we're assuming it's an event listener
        if (toLowerCase(memberName) in elm) {
            // standard event
            // the JSX attribute could have been "onMouseOver" and the
            // member name "onmouseover" is on the element's prototype
            // so let's add the listener "mouseover", which is all lowercased
            memberName = toLowerCase(memberName.substring(2));
        }
        else {
            // custom event
            // the JSX attribute could have been "onMyCustomEvent"
            // so let's trim off the "on" prefix and lowercase the first character
            // and add the listener "myCustomEvent"
            // except for the first character, we keep the event name case
            memberName = toLowerCase(memberName[2]) + memberName.substring(3);
        }
        if (newValue) {
            if (newValue !== oldValue) {
                // add listener
                plt.domApi.$addEventListener(elm, memberName, newValue);
            }
        }
        else {
            // remove listener
            plt.domApi.$removeEventListener(elm, memberName);
        }
    }
    else if (memberName !== 'list' && memberName !== 'type' && !isSvg &&
        (memberName in elm || (['object', 'function'].indexOf(typeof newValue) !== -1) && newValue !== null)
        || (!true && elementHasProperty(plt, elm, memberName))) {
        // Properties
        // - list and type are attributes that get applied as values on the element
        // - all svgs get values as attributes not props
        // - check if elm contains name or if the value is array, object, or function
        var cmpMeta = plt.getComponentMeta(elm);
        if (cmpMeta && cmpMeta.membersMeta && cmpMeta.membersMeta[memberName]) {
            // we know for a fact that this element is a known component
            // and this component has this member name as a property,
            // let's set the known @Prop on this element
            // set it directly as property on the element
            setProperty(elm, memberName, newValue);
            if (false && isHostElement && cmpMeta.membersMeta[memberName].reflectToAttrib) {
                // we also want to set this data to the attribute
                updateAttribute(elm, cmpMeta.membersMeta[memberName].attribName, newValue, cmpMeta.membersMeta[memberName].propType === 4 /* Boolean */);
            }
        }
        else if (memberName !== 'ref') {
            // this member name is a property on this element, but it's not a component
            // this is a native property like "value" or something
            // also we can ignore the "ref" member name at this point
            setProperty(elm, memberName, newValue == null ? '' : newValue);
            if (newValue == null || newValue === false) {
                plt.domApi.$removeAttribute(elm, memberName);
            }
        }
    }
    else if (newValue != null && memberName !== 'key') {
        // Element Attributes
        updateAttribute(elm, memberName, newValue);
    }
    else if (isSvg || plt.domApi.$hasAttribute(elm, memberName) && (newValue == null || newValue === false)) {
        // remove svg attribute
        plt.domApi.$removeAttribute(elm, memberName);
    }
}
function parseClassList(value) {
    return (value == null || value === '') ? [] : value.trim().split(/\s+/);
}
/**
 * Attempt to set a DOM property to the given value.
 * IE & FF throw for certain property-value combinations.
 */
function setProperty(elm, name, value) {
    try {
        elm[name] = value;
    }
    catch (e) { }
}
function updateElement(plt, oldVnode, newVnode, isSvgMode, memberName) {
    // if the element passed in is a shadow root, which is a document fragment
    // then we want to be adding attrs/props to the shadow root's "host" element
    // if it's not a shadow root, then we add attrs/props to the same element
    var elm = (newVnode.elm.nodeType === 11 /* DocumentFragment */ && newVnode.elm.host) ? newVnode.elm.host : newVnode.elm;
    var oldVnodeAttrs = (oldVnode && oldVnode.vattrs) || EMPTY_OBJ;
    var newVnodeAttrs = newVnode.vattrs || EMPTY_OBJ;
    // remove attributes no longer present on the vnode by setting them to undefined
    for (memberName in oldVnodeAttrs) {
        if (!(newVnodeAttrs && newVnodeAttrs[memberName] != null) && oldVnodeAttrs[memberName] != null) {
            setAccessor(plt, elm, memberName, oldVnodeAttrs[memberName], undefined, isSvgMode, newVnode.ishost);
        }
    }
    // add new & update changed attributes
    for (memberName in newVnodeAttrs) {
        if (!(memberName in oldVnodeAttrs) || newVnodeAttrs[memberName] !== (memberName === 'value' || memberName === 'checked' ? elm[memberName] : oldVnodeAttrs[memberName])) {
            setAccessor(plt, elm, memberName, oldVnodeAttrs[memberName], newVnodeAttrs[memberName], isSvgMode, newVnode.ishost);
        }
    }
}
var isSvgMode = false;
function createRendererPatch(plt, domApi) {
    // createRenderer() is only created once per app
    // the patch() function which createRenderer() returned is the function
    // which gets called numerous times by each component
    // internal variables to be reused per patch() call
    var useNativeShadowDom, ssrId, scopeId, checkSlotFallbackVisibility, checkSlotRelocate, contentRef, hostTagName, hostElm;
    function createElm(oldParentVNode, newParentVNode, childIndex, parentElm, i, elm, childNode, newVNode, oldVNode) {
        newVNode = newParentVNode.vchildren[childIndex];
        if (true && !useNativeShadowDom) {
            // remember for later we need to check to relocate nodes
            checkSlotRelocate = true;
            if (newVNode.vtag === 'slot') {
                if (scopeId) {
                    // scoped css needs to add its scoped id to the parent element
                    domApi.$addClass(parentElm, scopeId + '-s');
                }
                if (!newVNode.vchildren) {
                    // slot element does not have fallback content
                    // create an html comment we'll use to always reference
                    // where actual slot content should sit next to
                    newVNode.isSlotReference = true;
                }
                else {
                    // slot element has fallback content
                    // still create an element that "mocks" the slot element
                    newVNode.isSlotFallback = true;
                }
            }
        }
        if (isDef(newVNode.vtext)) {
            // create text node
            newVNode.elm = domApi.$createTextNode(newVNode.vtext);
        }
        else if (true && newVNode.isSlotReference) {
            // create a slot reference html text node
            newVNode.elm = domApi.$createTextNode('');
        }
        else {
            // create element
            elm = newVNode.elm = ((true && (isSvgMode || newVNode.vtag === 'svg')) ?
                domApi.$createElementNS('http://www.w3.org/2000/svg', newVNode.vtag) :
                domApi.$createElement((true && newVNode.isSlotFallback) ? 'slot-fb' : newVNode.vtag));
            if (plt.isDefinedComponent(elm)) {
                plt.isCmpReady.delete(hostElm);
            }
            if (true) {
                isSvgMode = newVNode.vtag === 'svg' ? true : (newVNode.vtag === 'foreignObject' ? false : isSvgMode);
            }
            // add css classes, attrs, props, listeners, etc.
            updateElement(plt, null, newVNode, isSvgMode);
            if (isDef(scopeId) && elm['s-si'] !== scopeId) {
                // if there is a scopeId and this is the initial render
                // then let's add the scopeId as an attribute
                domApi.$addClass(elm, (elm['s-si'] = scopeId));
            }
            if (false && isDef(ssrId)) {
                // SSR ONLY: this is an SSR render and this
                // logic does not run on the client
                // give this element the SSR child id that can be read by the client
                domApi.$setAttribute(elm, SSR_CHILD_ID, ssrId + '.' + childIndex + (hasChildNodes(newVNode.vchildren) ? '' : '.'));
            }
            if (newVNode.vchildren) {
                for (i = 0; i < newVNode.vchildren.length; ++i) {
                    // create the node
                    childNode = createElm(oldParentVNode, newVNode, i, elm);
                    // return node could have been null
                    if (childNode) {
                        if (false && isDef(ssrId) && childNode.nodeType === 3 /* TextNode */ && !childNode['s-cr']) {
                            // SSR ONLY: add the text node's start comment
                            domApi.$appendChild(elm, domApi.$createComment('s.' + ssrId + '.' + i));
                        }
                        // append our new node
                        domApi.$appendChild(elm, childNode);
                        if (false && isDef(ssrId) && childNode.nodeType === 3 /* TextNode */ && !childNode['s-cr']) {
                            // SSR ONLY: add the text node's end comment
                            domApi.$appendChild(elm, domApi.$createComment('/'));
                            domApi.$appendChild(elm, domApi.$createTextNode(' '));
                        }
                    }
                }
            }
            if (true && newVNode.vtag === 'svg') {
                // Only reset the SVG context when we're exiting SVG element
                isSvgMode = false;
            }
        }
        if (true) {
            newVNode.elm['s-hn'] = hostTagName;
            if (newVNode.isSlotFallback || newVNode.isSlotReference) {
                // remember the content reference comment
                newVNode.elm['s-sr'] = true;
                // remember the content reference comment
                newVNode.elm['s-cr'] = contentRef;
                // remember the slot name, or empty string for default slot
                newVNode.elm['s-sn'] = newVNode.vname || '';
                // check if we've got an old vnode for this slot
                oldVNode = oldParentVNode && oldParentVNode.vchildren && oldParentVNode.vchildren[childIndex];
                if (oldVNode && oldVNode.vtag === newVNode.vtag && oldParentVNode.elm) {
                    // we've got an old slot vnode and the wrapper is being replaced
                    // so let's move the old slot content back to it's original location
                    putBackInOriginalLocation(oldParentVNode.elm);
                }
            }
        }
        return newVNode.elm;
    }
    function putBackInOriginalLocation(parentElm, recursive, i, childNode) {
        plt.tmpDisconnected = true;
        var oldSlotChildNodes = domApi.$childNodes(parentElm);
        for (i = oldSlotChildNodes.length - 1; i >= 0; i--) {
            childNode = oldSlotChildNodes[i];
            if (childNode['s-hn'] !== hostTagName && childNode['s-ol']) {
                // this child node in the old element is from another component
                // remove this node from the old slot's parent
                domApi.$remove(childNode);
                // and relocate it back to it's original location
                domApi.$insertBefore(parentReferenceNode(childNode), childNode, referenceNode(childNode));
                // remove the old original location comment entirely
                // later on the patch function will know what to do
                // and move this to the correct spot in need be
                domApi.$remove(childNode['s-ol']);
                childNode['s-ol'] = null;
                checkSlotRelocate = true;
            }
            if (recursive) {
                putBackInOriginalLocation(childNode, recursive);
            }
        }
        plt.tmpDisconnected = false;
    }
    function addVnodes(parentElm, before, parentVNode, vnodes, startIdx, endIdx, containerElm, childNode) {
        var contentRef = parentElm['s-cr'];
        containerElm = ((contentRef && domApi.$parentNode(contentRef)) || parentElm);
        if (containerElm.shadowRoot && domApi.$tagName(containerElm) === hostTagName) {
            containerElm = containerElm.shadowRoot;
        }
        for (; startIdx <= endIdx; ++startIdx) {
            if (vnodes[startIdx]) {
                childNode = isDef(vnodes[startIdx].vtext) ?
                    domApi.$createTextNode(vnodes[startIdx].vtext) :
                    createElm(null, parentVNode, startIdx, parentElm);
                if (childNode) {
                    vnodes[startIdx].elm = childNode;
                    domApi.$insertBefore(containerElm, childNode, referenceNode(before));
                }
            }
        }
    }
    function removeVnodes(vnodes, startIdx, endIdx, node) {
        for (; startIdx <= endIdx; ++startIdx) {
            if (isDef(vnodes[startIdx])) {
                node = vnodes[startIdx].elm;
                if (true) {
                    // we're removing this element
                    // so it's possible we need to show slot fallback content now
                    checkSlotFallbackVisibility = true;
                    if (node['s-ol']) {
                        // remove the original location comment
                        domApi.$remove(node['s-ol']);
                    }
                    else {
                        // it's possible that child nodes of the node
                        // that's being removed are slot nodes
                        putBackInOriginalLocation(node, true);
                    }
                }
                // remove the vnode's element from the dom
                domApi.$remove(node);
            }
        }
    }
    function updateChildren(parentElm, oldCh, newVNode, newCh, idxInOld, i, node, elmToMove) {
        var oldStartIdx = 0, newStartIdx = 0;
        var oldEndIdx = oldCh.length - 1;
        var oldStartVnode = oldCh[0];
        var oldEndVnode = oldCh[oldEndIdx];
        var newEndIdx = newCh.length - 1;
        var newStartVnode = newCh[0];
        var newEndVnode = newCh[newEndIdx];
        while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
            if (oldStartVnode == null) {
                // Vnode might have been moved left
                oldStartVnode = oldCh[++oldStartIdx];
            }
            else if (oldEndVnode == null) {
                oldEndVnode = oldCh[--oldEndIdx];
            }
            else if (newStartVnode == null) {
                newStartVnode = newCh[++newStartIdx];
            }
            else if (newEndVnode == null) {
                newEndVnode = newCh[--newEndIdx];
            }
            else if (isSameVnode(oldStartVnode, newStartVnode)) {
                patchVNode(oldStartVnode, newStartVnode);
                oldStartVnode = oldCh[++oldStartIdx];
                newStartVnode = newCh[++newStartIdx];
            }
            else if (isSameVnode(oldEndVnode, newEndVnode)) {
                patchVNode(oldEndVnode, newEndVnode);
                oldEndVnode = oldCh[--oldEndIdx];
                newEndVnode = newCh[--newEndIdx];
            }
            else if (isSameVnode(oldStartVnode, newEndVnode)) {
                // Vnode moved right
                if (oldStartVnode.vtag === 'slot' || newEndVnode.vtag === 'slot') {
                    putBackInOriginalLocation(domApi.$parentNode(oldStartVnode.elm));
                }
                patchVNode(oldStartVnode, newEndVnode);
                domApi.$insertBefore(parentElm, oldStartVnode.elm, domApi.$nextSibling(oldEndVnode.elm));
                oldStartVnode = oldCh[++oldStartIdx];
                newEndVnode = newCh[--newEndIdx];
            }
            else if (isSameVnode(oldEndVnode, newStartVnode)) {
                // Vnode moved left
                if (oldStartVnode.vtag === 'slot' || newEndVnode.vtag === 'slot') {
                    putBackInOriginalLocation(domApi.$parentNode(oldEndVnode.elm));
                }
                patchVNode(oldEndVnode, newStartVnode);
                domApi.$insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);
                oldEndVnode = oldCh[--oldEndIdx];
                newStartVnode = newCh[++newStartIdx];
            }
            else {
                // createKeyToOldIdx
                idxInOld = null;
                for (i = oldStartIdx; i <= oldEndIdx; ++i) {
                    if (oldCh[i] && isDef(oldCh[i].vkey) && oldCh[i].vkey === newStartVnode.vkey) {
                        idxInOld = i;
                        break;
                    }
                }
                if (isDef(idxInOld)) {
                    elmToMove = oldCh[idxInOld];
                    if (elmToMove.vtag !== newStartVnode.vtag) {
                        node = createElm(oldCh && oldCh[newStartIdx], newVNode, idxInOld, parentElm);
                    }
                    else {
                        patchVNode(elmToMove, newStartVnode);
                        oldCh[idxInOld] = undefined;
                        node = elmToMove.elm;
                    }
                    newStartVnode = newCh[++newStartIdx];
                }
                else {
                    // new element
                    node = createElm(oldCh && oldCh[newStartIdx], newVNode, newStartIdx, parentElm);
                    newStartVnode = newCh[++newStartIdx];
                }
                if (node) {
                    domApi.$insertBefore(parentReferenceNode(oldStartVnode.elm), node, referenceNode(oldStartVnode.elm));
                }
            }
        }
        if (oldStartIdx > oldEndIdx) {
            addVnodes(parentElm, (newCh[newEndIdx + 1] == null ? null : newCh[newEndIdx + 1].elm), newVNode, newCh, newStartIdx, newEndIdx);
        }
        else if (newStartIdx > newEndIdx) {
            removeVnodes(oldCh, oldStartIdx, oldEndIdx);
        }
    }
    function isSameVnode(vnode1, vnode2) {
        // compare if two vnode to see if they're "technically" the same
        // need to have the same element tag, and same key to be the same
        if (vnode1.vtag === vnode2.vtag && vnode1.vkey === vnode2.vkey) {
            if (true) {
                if (vnode1.vtag === 'slot') {
                    return vnode1.vname === vnode2.vname;
                }
            }
            return true;
        }
        return false;
    }
    function referenceNode(node) {
        if (true) {
            if (node && node['s-ol']) {
                // this node was relocated to a new location in the dom
                // because of some other component's slot
                // but we still have an html comment in place of where
                // it's original location was according to it's original vdom
                return node['s-ol'];
            }
        }
        return node;
    }
    function parentReferenceNode(node) {
        return domApi.$parentNode(node['s-ol'] ? node['s-ol'] : node);
    }
    function patchVNode(oldVNode, newVNode, defaultHolder) {
        var elm = newVNode.elm = oldVNode.elm;
        var oldChildren = oldVNode.vchildren;
        var newChildren = newVNode.vchildren;
        if (true) {
            // test if we're rendering an svg element, or still rendering nodes inside of one
            // only add this to the when the compiler sees we're using an svg somewhere
            isSvgMode = newVNode.elm &&
                isDef(domApi.$parentElement(newVNode.elm)) &&
                newVNode.elm.ownerSVGElement !== undefined;
            isSvgMode = newVNode.vtag === 'svg' ? true : (newVNode.vtag === 'foreignObject' ? false : isSvgMode);
        }
        if (!isDef(newVNode.vtext)) {
            // element node
            if (newVNode.vtag !== 'slot') {
                // either this is the first render of an element OR it's an update
                // AND we already know it's possible it could have changed
                // this updates the element's css classes, attrs, props, listeners, etc.
                updateElement(plt, oldVNode, newVNode, isSvgMode);
            }
            if (isDef(oldChildren) && isDef(newChildren)) {
                // looks like there's child vnodes for both the old and new vnodes
                updateChildren(elm, oldChildren, newVNode, newChildren);
            }
            else if (isDef(newChildren)) {
                // no old child vnodes, but there are new child vnodes to add
                if (isDef(oldVNode.vtext)) {
                    // the old vnode was text, so be sure to clear it out
                    domApi.$setTextContent(elm, '');
                }
                // add the new vnode children
                addVnodes(elm, null, newVNode, newChildren, 0, newChildren.length - 1);
            }
            else if (isDef(oldChildren)) {
                // no new child vnodes, but there are old child vnodes to remove
                removeVnodes(oldChildren, 0, oldChildren.length - 1);
            }
        }
        else if (true && (defaultHolder = elm['s-cr'])) {
            // this element has slotted content
            domApi.$setTextContent(domApi.$parentNode(defaultHolder), newVNode.vtext);
        }
        else if (oldVNode.vtext !== newVNode.vtext) {
            // update the text content for the text only vnode
            // and also only if the text is different than before
            domApi.$setTextContent(elm, newVNode.vtext);
        }
        if (true) {
            // reset svgMode when svg node is fully patched
            if (isSvgMode && 'svg' === newVNode.vtag) {
                isSvgMode = false;
            }
        }
    }
    function updateFallbackSlotVisibility(elm, childNode, childNodes, i, ilen, j, slotNameAttr, nodeType) {
        childNodes = domApi.$childNodes(elm);
        for (i = 0, ilen = childNodes.length; i < ilen; i++) {
            childNode = childNodes[i];
            if (domApi.$nodeType(childNode) === 1 /* ElementNode */) {
                if (childNode['s-sr']) {
                    // this is a slot fallback node
                    // get the slot name for this slot reference node
                    slotNameAttr = childNode['s-sn'];
                    // by default always show a fallback slot node
                    // then hide it if there are other slots in the light dom
                    childNode.hidden = false;
                    for (j = 0; j < ilen; j++) {
                        if (childNodes[j]['s-hn'] !== childNode['s-hn']) {
                            // this sibling node is from a different component
                            nodeType = domApi.$nodeType(childNodes[j]);
                            if (slotNameAttr !== '') {
                                // this is a named fallback slot node
                                if (nodeType === 1 /* ElementNode */ && slotNameAttr === domApi.$getAttribute(childNodes[j], 'slot')) {
                                    childNode.hidden = true;
                                    break;
                                }
                            }
                            else {
                                // this is a default fallback slot node
                                // any element or text node (with content)
                                // should hide the default fallback slot node
                                if (nodeType === 1 /* ElementNode */ || (nodeType === 3 /* TextNode */ && domApi.$getTextContent(childNodes[j]).trim() !== '')) {
                                    childNode.hidden = true;
                                    break;
                                }
                            }
                        }
                    }
                }
                // keep drilling down
                updateFallbackSlotVisibility(childNode);
            }
        }
    }
    var relocateNodes = [];
    function relocateSlotContent(elm, childNodes, childNode, node, i, ilen, j, hostContentNodes, slotNameAttr, nodeType) {
        childNodes = domApi.$childNodes(elm);
        for (i = 0, ilen = childNodes.length; i < ilen; i++) {
            childNode = childNodes[i];
            if (childNode['s-sr'] && (node = childNode['s-cr'])) {
                // first got the content reference comment node
                // then we got it's parent, which is where all the host content is in now
                hostContentNodes = domApi.$childNodes(domApi.$parentNode(node));
                slotNameAttr = childNode['s-sn'];
                for (j = hostContentNodes.length - 1; j >= 0; j--) {
                    node = hostContentNodes[j];
                    if (!node['s-cn'] && !node['s-nr'] && node['s-hn'] !== childNode['s-hn']) {
                        // let's do some relocating to its new home
                        // but never relocate a content reference node
                        // that is suppose to always represent the original content location
                        nodeType = domApi.$nodeType(node);
                        if (((nodeType === 3 /* TextNode */ || nodeType === 8 /* CommentNode */) && slotNameAttr === '') ||
                            (nodeType === 1 /* ElementNode */ && domApi.$getAttribute(node, 'slot') === null && slotNameAttr === '') ||
                            (nodeType === 1 /* ElementNode */ && domApi.$getAttribute(node, 'slot') === slotNameAttr)) {
                            // it's possible we've already decided to relocate this node
                            if (!relocateNodes.some(function (r) { return r.nodeToRelocate === node; })) {
                                // made some changes to slots
                                // let's make sure we also double check
                                // fallbacks are correctly hidden or shown
                                checkSlotFallbackVisibility = true;
                                node['s-sn'] = slotNameAttr;
                                // add to our list of nodes to relocate
                                relocateNodes.push({
                                    slotRefNode: childNode,
                                    nodeToRelocate: node
                                });
                            }
                        }
                    }
                }
            }
            if (domApi.$nodeType(childNode) === 1 /* ElementNode */) {
                relocateSlotContent(childNode);
            }
        }
    }
    return function patch(hostElement, oldVNode, newVNode, useNativeShadowDomVal, encapsulation, ssrPatchId, i, relocateNode, orgLocationNode, refNode, parentNodeRef, insertBeforeNode) {
        // patchVNode() is synchronous
        // so it is safe to set these variables and internally
        // the same patch() call will reference the same data
        hostElm = hostElement;
        hostTagName = domApi.$tagName(hostElm);
        contentRef = hostElm['s-cr'];
        useNativeShadowDom = useNativeShadowDomVal;
        if (false) {
            if (encapsulation !== 'shadow') {
                ssrId = ssrPatchId;
            }
            else {
                ssrId = null;
            }
        }
        if (true) {
            // get the scopeId
            scopeId = hostElm['s-sc'];
            // always reset
            checkSlotRelocate = checkSlotFallbackVisibility = false;
        }
        // synchronous patch
        patchVNode(oldVNode, newVNode);
        if (false && isDef(ssrId)) {
            // SSR ONLY: we've been given an SSR id, so the host element
            // should be given the ssr id attribute
            domApi.$setAttribute(oldVNode.elm, SSR_VNODE_ID, ssrId);
        }
        if (true) {
            if (checkSlotRelocate) {
                relocateSlotContent(newVNode.elm);
                for (i = 0; i < relocateNodes.length; i++) {
                    relocateNode = relocateNodes[i];
                    if (!relocateNode.nodeToRelocate['s-ol']) {
                        // add a reference node marking this node's original location
                        // keep a reference to this node for later lookups
                        orgLocationNode = domApi.$createTextNode('');
                        orgLocationNode['s-nr'] = relocateNode.nodeToRelocate;
                        domApi.$insertBefore(domApi.$parentNode(relocateNode.nodeToRelocate), (relocateNode.nodeToRelocate['s-ol'] = orgLocationNode), relocateNode.nodeToRelocate);
                    }
                }
                // while we're moving nodes around existing nodes, temporarily disable
                // the disconnectCallback from working
                plt.tmpDisconnected = true;
                for (i = 0; i < relocateNodes.length; i++) {
                    relocateNode = relocateNodes[i];
                    // by default we're just going to insert it directly
                    // after the slot reference node
                    parentNodeRef = domApi.$parentNode(relocateNode.slotRefNode);
                    insertBeforeNode = domApi.$nextSibling(relocateNode.slotRefNode);
                    orgLocationNode = relocateNode.nodeToRelocate['s-ol'];
                    while (orgLocationNode = domApi.$previousSibling(orgLocationNode)) {
                        if ((refNode = orgLocationNode['s-nr']) && refNode) {
                            if (refNode['s-sn'] === relocateNode.nodeToRelocate['s-sn']) {
                                if (parentNodeRef === domApi.$parentNode(refNode)) {
                                    if ((refNode = domApi.$nextSibling(refNode)) && refNode && !refNode['s-nr']) {
                                        insertBeforeNode = refNode;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    if ((!insertBeforeNode && parentNodeRef !== domApi.$parentNode(relocateNode.nodeToRelocate)) ||
                        (domApi.$nextSibling(relocateNode.nodeToRelocate) !== insertBeforeNode)) {
                        // we've checked that it's worth while to relocate
                        // since that the node to relocate
                        // has a different next sibling or parent relocated
                        if (relocateNode.nodeToRelocate !== insertBeforeNode) {
                            // remove the node from the dom
                            domApi.$remove(relocateNode.nodeToRelocate);
                            // add it back to the dom but in its new home
                            domApi.$insertBefore(parentNodeRef, relocateNode.nodeToRelocate, insertBeforeNode);
                        }
                    }
                }
                // done moving nodes around
                // allow the disconnect callback to work again
                plt.tmpDisconnected = false;
            }
            if (checkSlotFallbackVisibility) {
                updateFallbackSlotVisibility(newVNode.elm);
            }
            // always reset
            relocateNodes.length = 0;
        }
        // return our new vnode
        return newVNode;
    };
}
function callNodeRefs(vNode, isDestroy) {
    if (vNode) {
        vNode.vattrs && vNode.vattrs.ref && vNode.vattrs.ref(isDestroy ? null : vNode.elm);
        vNode.vchildren && vNode.vchildren.forEach(function (vChild) {
            callNodeRefs(vChild, isDestroy);
        });
    }
}
function hasChildNodes(children) {
    // SSR ONLY: check if there are any more nested child elements
    // if there aren't, this info is useful so the client runtime
    // doesn't have to climb down and check so many elements
    if (children) {
        for (var i = 0; i < children.length; i++) {
            if (children[i].vtag !== 'slot' || hasChildNodes(children[i].vchildren)) {
                return true;
            }
        }
    }
    return false;
}
function createVNodesFromSsr(plt, domApi, rootElm) {
    var allSsrElms = rootElm.querySelectorAll("[" + SSR_VNODE_ID + "]");
    var ilen = allSsrElms.length;
    var elm, ssrVNodeId, ssrVNode, i, j, jlen;
    if (ilen > 0) {
        plt.isCmpReady.set(rootElm, true);
        for (i = 0; i < ilen; i++) {
            elm = allSsrElms[i];
            ssrVNodeId = domApi.$getAttribute(elm, SSR_VNODE_ID);
            ssrVNode = {};
            ssrVNode.vtag = domApi.$tagName(ssrVNode.elm = elm);
            plt.vnodeMap.set(elm, ssrVNode);
            for (j = 0, jlen = elm.childNodes.length; j < jlen; j++) {
                addChildSsrVNodes(domApi, elm.childNodes[j], ssrVNode, ssrVNodeId, true);
            }
        }
    }
}
function addChildSsrVNodes(domApi, node, parentVNode, ssrVNodeId, checkNestedElements) {
    var nodeType = domApi.$nodeType(node);
    var previousComment;
    var childVNodeId, childVNodeSplt, childVNode;
    if (checkNestedElements && nodeType === 1 /* ElementNode */) {
        childVNodeId = domApi.$getAttribute(node, SSR_CHILD_ID);
        if (childVNodeId) {
            // split the start comment's data with a period
            childVNodeSplt = childVNodeId.split('.');
            // ensure this this element is a child element of the ssr vnode
            if (childVNodeSplt[0] === ssrVNodeId) {
                // cool, this element is a child to the parent vnode
                childVNode = {};
                childVNode.vtag = domApi.$tagName(childVNode.elm = node);
                // this is a new child vnode
                // so ensure its parent vnode has the vchildren array
                if (!parentVNode.vchildren) {
                    parentVNode.vchildren = [];
                }
                // add our child vnode to a specific index of the vnode's children
                parentVNode.vchildren[childVNodeSplt[1]] = childVNode;
                // this is now the new parent vnode for all the next child checks
                parentVNode = childVNode;
                // if there's a trailing period, then it means there aren't any
                // more nested elements, but maybe nested text nodes
                // either way, don't keep walking down the tree after this next call
                checkNestedElements = (childVNodeSplt[2] !== '');
            }
        }
        // keep drilling down through the elements
        for (var i = 0; i < node.childNodes.length; i++) {
            addChildSsrVNodes(domApi, node.childNodes[i], parentVNode, ssrVNodeId, checkNestedElements);
        }
    }
    else if (nodeType === 3 /* TextNode */ &&
        (previousComment = node.previousSibling) &&
        domApi.$nodeType(previousComment) === 8 /* CommentNode */) {
        // split the start comment's data with a period
        childVNodeSplt = domApi.$getTextContent(previousComment).split('.');
        // ensure this is an ssr text node start comment
        // which should start with an "s" and delimited by periods
        if (childVNodeSplt[0] === 's' && childVNodeSplt[1] === ssrVNodeId) {
            // cool, this is a text node and it's got a start comment
            childVNode = { vtext: domApi.$getTextContent(node) };
            childVNode.elm = node;
            // this is a new child vnode
            // so ensure its parent vnode has the vchildren array
            if (!parentVNode.vchildren) {
                parentVNode.vchildren = [];
            }
            // add our child vnode to a specific index of the vnode's children
            parentVNode.vchildren[childVNodeSplt[2]] = childVNode;
        }
    }
}
function createQueueClient(App, win) {
    var now = function () { return win.performance.now(); };
    var resolved = Promise.resolve();
    var highPriority = [];
    var domReads = [];
    var domWrites = [];
    var domWritesLow = [];
    var congestion = 0;
    var rafPending = false;
    if (!App.raf) {
        App.raf = win.requestAnimationFrame.bind(win);
    }
    function queueTask(queue) {
        return function (cb) {
            // queue dom reads
            queue.push(cb);
            if (!rafPending) {
                rafPending = true;
                App.raf(flush);
            }
        };
    }
    function consume(queue) {
        for (var i = 0; i < queue.length; i++) {
            try {
                queue[i](now());
            }
            catch (e) {
                console.error(e);
            }
        }
        queue.length = 0;
    }
    function consumeTimeout(queue, timeout) {
        var i = 0;
        var ts;
        while (i < queue.length && (ts = now()) < timeout) {
            try {
                queue[i++](ts);
            }
            catch (e) {
                console.error(e);
            }
        }
        if (i === queue.length) {
            queue.length = 0;
        }
        else if (i !== 0) {
            queue.splice(0, i);
        }
    }
    function flush() {
        congestion++;
        // always force a bunch of medium callbacks to run, but still have
        // a throttle on how many can run in a certain time
        // DOM READS!!!
        consume(domReads);
        var start = now() + (7 * Math.ceil(congestion * (1.0 / 22.0)));
        // DOM WRITES!!!
        consumeTimeout(domWrites, start);
        consumeTimeout(domWritesLow, start);
        if (domWrites.length > 0) {
            domWritesLow.push.apply(domWritesLow, domWrites);
            domWrites.length = 0;
        }
        if (rafPending = ((domReads.length + domWrites.length + domWritesLow.length) > 0)) {
            // still more to do yet, but we've run out of time
            // let's let this thing cool off and try again in the next tick
            App.raf(flush);
        }
        else {
            congestion = 0;
        }
    }
    return {
        tick: function (cb) {
            // queue high priority work to happen in next tick
            // uses Promise.resolve() for next tick
            highPriority.push(cb);
            if (highPriority.length === 1) {
                resolved.then(function () { return consume(highPriority); });
            }
        },
        read: queueTask(domReads),
        write: queueTask(domWrites),
    };
}
function initElementListeners(plt, elm) {
    // so the element was just connected, which means it's in the DOM
    // however, the component instance hasn't been created yet
    // but what if an event it should be listening to get emitted right now??
    // let's add our listeners right now to our element, and if it happens
    // to receive events between now and the instance being created let's
    // queue up all of the event data and fire it off on the instance when it's ready
    var cmpMeta = plt.getComponentMeta(elm);
    if (cmpMeta.listenersMeta) {
        // we've got listens
        cmpMeta.listenersMeta.forEach(function (listenMeta) {
            // go through each listener
            if (!listenMeta.eventDisabled) {
                // only add ones that are not already disabled
                plt.domApi.$addEventListener(elm, listenMeta.eventName, createListenerCallback(plt, elm, listenMeta.eventMethodName), listenMeta.eventCapture, listenMeta.eventPassive);
            }
        });
    }
}
function createListenerCallback(plt, elm, eventMethodName, val) {
    // create the function that gets called when the element receives
    // an event which it should be listening for
    return function (ev) {
        // get the instance if it exists
        val = plt.instanceMap.get(elm);
        if (val) {
            // instance is ready, let's call it's member method for this event
            val[eventMethodName](ev);
        }
        else {
            // instance is not ready!!
            // let's queue up this event data and replay it later
            // when the instance is ready
            val = (plt.queuedEvents.get(elm) || []);
            val.push(eventMethodName, ev);
            plt.queuedEvents.set(elm, val);
        }
    };
}
function enableEventListener(plt, instance, eventName, shouldEnable, attachTo, passive) {
    if (instance) {
        // cool, we've got an instance, it's get the element it's on
        var elm = plt.hostElementMap.get(instance);
        var cmpMeta = plt.getComponentMeta(elm);
        if (cmpMeta && cmpMeta.listenersMeta) {
            // alrighty, so this cmp has listener meta
            if (shouldEnable) {
                // we want to enable this event
                // find which listen meta we're talking about
                var listenMeta_1 = cmpMeta.listenersMeta.find(function (l) { return l.eventName === eventName; });
                if (listenMeta_1) {
                    // found the listen meta, so let's add the listener
                    plt.domApi.$addEventListener(elm, eventName, function (ev) { return instance[listenMeta_1.eventMethodName](ev); }, listenMeta_1.eventCapture, (passive === undefined) ? listenMeta_1.eventPassive : !!passive, attachTo);
                }
            }
            else {
                // we're disabling the event listener
                // so let's just remove it entirely
                plt.domApi.$removeEventListener(elm, eventName);
            }
        }
    }
}
function generateDevInspector(namespace, win, plt, components) {
    var devInspector = win.devInspector = (win.devInspector || {});
    devInspector.apps = devInspector.apps || [];
    devInspector.apps.push(generateDevInspectorApp(namespace, plt, components));
    if (!devInspector.getInstance) {
        devInspector.getInstance = function (elm) {
            return Promise.all(devInspector.apps.map(function (app) {
                return app.getInstance(elm);
            })).then(function (results) {
                return results.find(function (instance) { return !!instance; });
            });
        };
    }
    if (!devInspector.getComponents) {
        devInspector.getComponents = function () {
            var appsMetadata = [];
            devInspector.apps.forEach(function (app) {
                appsMetadata.push(app.getComponents());
            });
            return Promise.all(appsMetadata).then(function (appMetadata) {
                var allMetadata = [];
                appMetadata.forEach(function (metadata) {
                    metadata.forEach(function (m) {
                        allMetadata.push(m);
                    });
                });
                return allMetadata;
            });
        };
    }
    return devInspector;
}
function generateDevInspectorApp(namespace, plt, components) {
    var app = {
        namespace: namespace,
        getInstance: function (elm) {
            if (elm && elm.tagName) {
                return Promise.all([
                    getComponentMeta(plt, elm.tagName),
                    getComponentInstance(plt, elm)
                ]).then(function (results) {
                    if (results[0] && results[1]) {
                        var cmp = {
                            meta: results[0],
                            instance: results[1]
                        };
                        return cmp;
                    }
                    return null;
                });
            }
            return Promise.resolve(null);
        },
        getComponent: function (tagName) {
            return getComponentMeta(plt, tagName);
        },
        getComponents: function () {
            return Promise.all(components.map(function (cmp) {
                return getComponentMeta(plt, cmp[0]);
            })).then(function (metadata) {
                return metadata.filter(function (m) { return m; });
            });
        }
    };
    return app;
}
function getMembersMeta(properties) {
    return Object.keys(properties).reduce(function (membersMap, memberKey) {
        var prop = properties[memberKey];
        var category;
        var member = {
            name: memberKey
        };
        if (prop.state) {
            category = 'states';
            member.watchers = prop.watchCallbacks || [];
        }
        else if (prop.elementRef) {
            category = 'elements';
        }
        else if (prop.method) {
            category = 'methods';
        }
        else {
            category = 'props';
            var type = 'any';
            if (prop.type) {
                type = prop.type;
                if (typeof prop.type === 'function') {
                    type = prop.type.name;
                }
            }
            member.type = type.toLowerCase();
            member.mutable = prop.mutable || false;
            member.connect = prop.connect || '-';
            member.context = prop.connect || '-';
            member.watchers = prop.watchCallbacks || [];
        }
        membersMap[category].push(member);
        return membersMap;
    }, {
        props: [],
        states: [],
        elements: [],
        methods: []
    });
}
function getComponentMeta(plt, tagName) {
    var elm = { nodeName: tagName };
    var internalMeta = plt.getComponentMeta(elm);
    if (!internalMeta || !internalMeta.componentConstructor) {
        return Promise.resolve(null);
    }
    var cmpCtr = internalMeta.componentConstructor;
    var members = getMembersMeta(cmpCtr.properties || {});
    var listeners = (internalMeta.listenersMeta || []).map(function (listenerMeta) {
        return {
            event: listenerMeta.eventName,
            capture: listenerMeta.eventCapture,
            disabled: listenerMeta.eventDisabled,
            passive: listenerMeta.eventPassive,
            method: listenerMeta.eventMethodName
        };
    });
    var emmiters = cmpCtr.events || [];
    var meta = Object.assign({ tag: cmpCtr.is, bundle: (internalMeta.bundleIds || 'unknown'), encapsulation: cmpCtr.encapsulation || 'none' }, members, { events: {
            emmiters: emmiters,
            listeners: listeners
        } });
    return Promise.resolve(meta);
}
function getComponentInstance(plt, elm) {
    return Promise.resolve(plt.instanceMap.get(elm));
}
/**
 * Production h() function based on Preact by
 * Jason Miller (@developit)
 * Licensed under the MIT License
 * https://github.com/developit/preact/blob/master/LICENSE
 *
 * Modified for Stencil's compiler and vdom
 */
var stack = [];
function h(nodeName, vnodeData) {
    var children = null;
    var lastSimple = false;
    var simple = false;
    for (var i = arguments.length; i-- > 2;) {
        stack.push(arguments[i]);
    }
    while (stack.length > 0) {
        var child = stack.pop();
        if (child && child.pop !== undefined) {
            for (i = child.length; i--;) {
                stack.push(child[i]);
            }
        }
        else {
            if (typeof child === 'boolean') {
                child = null;
            }
            if ((simple = typeof nodeName !== 'function')) {
                if (child == null) {
                    child = '';
                }
                else if (typeof child === 'number') {
                    child = String(child);
                }
                else if (typeof child !== 'string') {
                    simple = false;
                }
            }
            if (simple && lastSimple) {
                children[children.length - 1].vtext += child;
            }
            else if (children === null) {
                children = [simple ? { vtext: child } : child];
            }
            else {
                children.push(simple ? { vtext: child } : child);
            }
            lastSimple = simple;
        }
    }
    var vkey;
    var vname;
    if (vnodeData != null) {
        // normalize class / classname attributes
        if (vnodeData['className']) {
            vnodeData['class'] = vnodeData['className'];
        }
        if (typeof vnodeData['class'] === 'object') {
            for (i in vnodeData['class']) {
                if (vnodeData['class'][i]) {
                    stack.push(i);
                }
            }
            vnodeData['class'] = stack.join(' ');
            stack.length = 0;
        }
        if (vnodeData.key != null) {
            vkey = vnodeData.key;
        }
        if (vnodeData.name != null) {
            vname = vnodeData.name;
        }
    }
    if (typeof nodeName === 'function') {
        // nodeName is a functional component
        return nodeName(vnodeData, children || [], utils);
    }
    return {
        vtag: nodeName,
        vchildren: children,
        vtext: undefined,
        vattrs: vnodeData,
        vkey: vkey,
        vname: vname,
        elm: undefined,
        ishost: false
    };
}
function childToVNode(child) {
    return {
        vtag: child['vtag'],
        vchildren: child['vchildren'],
        vtext: child['vtext'],
        vattrs: child['vattrs'],
        vkey: child['vkey'],
        vname: child['vname']
    };
}
function VNodeToChild(vnode) {
    return {
        'vtag': vnode.vtag,
        'vchildren': vnode.vchildren,
        'vtext': vnode.vtext,
        'vattrs': vnode.vattrs,
        'vkey': vnode.vkey,
        'vname': vnode.vname
    };
}
var utils = {
    'forEach': function (children, cb) {
        children.forEach(function (item, index, array) { return cb(VNodeToChild(item), index, array); });
    },
    'map': function (children, cb) {
        return children.map(function (item, index, array) { return childToVNode(cb(VNodeToChild(item), index, array)); });
    }
};
function initCoreComponentOnReady(plt, App, win, apps, queuedComponentOnReadys, i) {
    // add componentOnReady() to the App object
    // this also is used to know that the App's core is ready
    App.componentOnReady = function (elm, resolve) {
        if (!elm.nodeName.includes('-')) {
            resolve(null);
            return false;
        }
        var cmpMeta = plt.getComponentMeta(elm);
        if (cmpMeta) {
            if (plt.isCmpReady.has(elm)) {
                // element has already loaded, pass the resolve the element component
                // so we know that the resolve knows it this element is an app component
                resolve(elm);
            }
            else {
                // element hasn't loaded yet or it has an update in progress
                // add this resolve specifically to this elements on ready queue
                var onReadyCallbacks = plt.onReadyCallbacksMap.get(elm) || [];
                onReadyCallbacks.push(resolve);
                plt.onReadyCallbacksMap.set(elm, onReadyCallbacks);
            }
        }
        // return a boolean if this app recognized this element or not
        return !!cmpMeta;
    };
    if (queuedComponentOnReadys) {
        // we've got some componentOnReadys in the queue before the app was ready
        for (i = queuedComponentOnReadys.length - 1; i >= 0; i--) {
            // go through each element and see if this app recongizes it
            if (App.componentOnReady(queuedComponentOnReadys[i][0], queuedComponentOnReadys[i][1])) {
                // turns out this element belongs to this app
                // remove the resolve from the queue so in the end
                // all that's left in the queue are elements not apart of any apps
                queuedComponentOnReadys.splice(i, 1);
            }
        }
        for (i = 0; i < apps.length; i++) {
            if (!win[apps[i]].componentOnReady) {
                // there is at least 1 apps that isn't ready yet
                // so let's stop here cuz there's still app cores loading
                return;
            }
        }
        // if we got to this point then that means all of the apps are ready
        // and they would have removed any of their elements from queuedComponentOnReadys
        // so let's do the cleanup of the  remaining queuedComponentOnReadys
        for (i = 0; i < queuedComponentOnReadys.length; i++) {
            // resolve any queued componentsOnReadys that are left over
            // since these elements were not apart of any apps
            // call the resolve fn, but pass null so it's know this wasn't a known app component
            queuedComponentOnReadys[i][1](null);
        }
        queuedComponentOnReadys.length = 0;
    }
}
function attributeChangedCallback(attrPropsMap, elm, attribName, newVal) {
    // look up to see if we have a property wired up to this attribute name
    var propName = attrPropsMap[toLowerCase(attribName)];
    if (propName) {
        // there is not need to cast the value since, it's already casted when
        // the prop is setted
        elm[propName] = newVal;
    }
}
function initHostSnapshot(domApi, cmpMeta, hostElm, hostSnapshot, attribName) {
    // the host element has connected to the dom
    // and we've waited a tick to make sure all frameworks
    // have finished adding attributes and child nodes to the host
    // before we go all out and hydrate this beast
    // let's first take a snapshot of its original layout before render
    if (!hostElm.mode) {
        // looks like mode wasn't set as a property directly yet
        // first check if there's an attribute
        // next check the app's global
        hostElm.mode = domApi.$getMode(hostElm);
    }
    if (true) {
        // if the slot polyfill is required we'll need to put some nodes
        // in here to act as original content anchors as we move nodes around
        // host element has been connected to the DOM
        if (!hostElm['s-cr'] && !domApi.$getAttribute(hostElm, SSR_VNODE_ID) && (!domApi.$supportsShadowDom || cmpMeta.encapsulationMeta !== 1 /* ShadowDom */)) {
            // only required when we're NOT using native shadow dom (slot)
            // or this browser doesn't support native shadow dom
            // and this host element was NOT created with SSR
            // let's pick out the inner content for slot projection
            // create a node to represent where the original
            // content was first placed, which is useful later on
            hostElm['s-cr'] = domApi.$createTextNode('');
            hostElm['s-cr']['s-cn'] = true;
            domApi.$insertBefore(hostElm, hostElm['s-cr'], domApi.$childNodes(hostElm)[0]);
        }
        if (!domApi.$supportsShadowDom && cmpMeta.encapsulationMeta === 1 /* ShadowDom */) {
            // this component should use shadow dom
            // but this browser doesn't support it
            // so let's polyfill a few things for the user
            if (false && true) {
                // it's possible we're manually forcing the slot polyfill
                // but this browser may already support the read-only shadowRoot
                // do an extra check here, but only for dev mode on the client
                if (!('shadowRoot' in HTMLElement.prototype)) {
                    hostElm.shadowRoot = hostElm;
                }
            }
            else {
                hostElm.shadowRoot = hostElm;
            }
        }
    }
    if (true) {
        if (cmpMeta.encapsulationMeta === 1 /* ShadowDom */ && domApi.$supportsShadowDom && !hostElm.shadowRoot) {
            // this component is using shadow dom
            // and this browser supports shadow dom
            // add the read-only property "shadowRoot" to the host element
            domApi.$attachShadow(hostElm, { mode: 'open' });
        }
    }
    // create a host snapshot object we'll
    // use to store all host data about to be read later
    hostSnapshot = {
        $id: hostElm['s-id'],
        $attributes: {}
    };
    // loop through and gather up all the original attributes on the host
    // this is useful later when we're creating the component instance
    cmpMeta.membersMeta && Object.keys(cmpMeta.membersMeta).forEach(function (memberName) {
        if (attribName = cmpMeta.membersMeta[memberName].attribName) {
            hostSnapshot.$attributes[attribName] = domApi.$getAttribute(hostElm, attribName);
        }
    });
    return hostSnapshot;
}
function connectedCallback(plt, cmpMeta, elm, perf) {
    if (false) {
        // initialize our event listeners on the host element
        // we do this now so that we can listening to events that may
        // have fired even before the instance is ready
        if (!plt.hasListenersMap.has(elm)) {
            // it's possible we've already connected
            // then disconnected
            // and the same element is reconnected again
            plt.hasListenersMap.set(elm, true);
            initElementListeners(plt, elm);
        }
    }
    // this element just connected, which may be re-connecting
    // ensure we remove it from our map of disconnected
    plt.isDisconnectedMap.delete(elm);
    if (!plt.hasConnectedMap.has(elm)) {
        if (!elm['s-id']) {
            // assign a unique id to this host element
            // it's possible this was already given an element id
            elm['s-id'] = plt.nextId();
        }
        if (false) {
            perf.mark("connected_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
        }
        plt.hasConnectedComponent = true;
        plt.processingCmp.add(elm);
        // first time we've connected
        plt.hasConnectedMap.set(elm, true);
        // register this component as an actively
        // loading child to its parent component
        registerWithParentComponent(plt, elm);
        // add to the queue to load the bundle
        // it's important to have an async tick in here so we can
        // ensure the "mode" attribute has been added to the element
        // place in high priority since it's not much work and we need
        // to know as fast as possible, but still an async tick in between
        plt.queue.tick(function () {
            // start loading this component mode's bundle
            // if it's already loaded then the callback will be synchronous
            plt.hostSnapshotMap.set(elm, initHostSnapshot(plt.domApi, cmpMeta, elm));
            if (false) {
                perf.mark("connected_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
                perf.measure("connected:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "connected_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "connected_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
            }
            plt.requestBundle(cmpMeta, elm);
        });
    }
}
function registerWithParentComponent(plt, elm, ancestorHostElement) {
    // find the first ancestor host element (if there is one) and register
    // this element as one of the actively loading child elements for its ancestor
    ancestorHostElement = elm;
    while (ancestorHostElement = plt.domApi.$parentElement(ancestorHostElement)) {
        // climb up the ancestors looking for the first registered component
        if (plt.isDefinedComponent(ancestorHostElement)) {
            // we found this elements the first ancestor host element
            // if the ancestor already loaded then do nothing, it's too late
            if (!plt.isCmpReady.has(elm)) {
                // keep a reference to this element's ancestor host element
                // elm._ancestorHostElement = ancestorHostElement;
                plt.ancestorHostElementMap.set(elm, ancestorHostElement);
                // ensure there is an array to contain a reference to each of the child elements
                // and set this element as one of the ancestor's child elements it should wait on
                (ancestorHostElement['s-ld'] = ancestorHostElement['s-ld'] || []).push(elm);
            }
            break;
        }
    }
}
function initEventEmitters(plt, cmpEvents, instance) {
    if (cmpEvents) {
        var elm_1 = plt.hostElementMap.get(instance);
        cmpEvents.forEach(function (eventMeta) {
            instance[eventMeta.method] = {
                emit: function (data) { return plt.emitEvent(elm_1, eventMeta.name, {
                    bubbles: eventMeta.bubbles,
                    composed: eventMeta.composed,
                    cancelable: eventMeta.cancelable,
                    detail: data
                }); }
            };
        });
    }
}
function parseComponentLoader(cmpRegistryData) {
    // tag name will always be lower case
    // parse member meta
    // this data only includes props that are attributes that need to be observed
    // it does not include all of the props yet
    var tagNameMeta = cmpRegistryData[0], bundleIds = cmpRegistryData[1], memberData = cmpRegistryData[3], encapsulationMeta = cmpRegistryData[4], listenerMeta = cmpRegistryData[5];
    var membersMeta = {
        // every component defaults to always have
        // the mode and color properties
        // but only color should observe any attribute changes
        'color': { attribName: 'color' }
    };
    if (memberData) {
        for (var i = 0; i < memberData.length; i++) {
            var d = memberData[i];
            membersMeta[d[0]] = {
                memberType: d[1],
                reflectToAttrib: !!d[2],
                attribName: typeof d[3] === 'string' ? d[3] : d[3] ? d[0] : 0,
                propType: d[4]
            };
        }
    }
    return {
        tagNameMeta: tagNameMeta,
        // map of the bundle ids
        // can contain modes, and array of esm and es5 bundle ids
        bundleIds: bundleIds,
        membersMeta: Object.assign({}, membersMeta),
        // encapsulation
        encapsulationMeta: encapsulationMeta,
        // parse listener meta
        listenersMeta: listenerMeta ? listenerMeta.map(parseListenerData) : undefined
    };
}
function parseListenerData(listenerData) {
    return {
        eventName: listenerData[0],
        eventMethodName: listenerData[1],
        eventDisabled: !!listenerData[2],
        eventPassive: !!listenerData[3],
        eventCapture: !!listenerData[4]
    };
}
function parsePropertyValue(propType, propValue) {
    // ensure this value is of the correct prop type
    // we're testing both formats of the "propType" value because
    // we could have either gotten the data from the attribute changed callback,
    // which wouldn't have Constructor data yet, and because this method is reused
    // within proxy where we don't have meta data, but only constructor data
    if (isDef(propValue) && typeof propValue !== 'object' && typeof propValue !== 'function') {
        if (propType === Boolean || propType === 4 /* Boolean */) {
            // per the HTML spec, any string value means it is a boolean true value
            // but we'll cheat here and say that the string "false" is the boolean false
            return (propValue === 'false' ? false : propValue === '' || !!propValue);
        }
        if (propType === Number || propType === 8 /* Number */) {
            // force it to be a number
            return parseFloat(propValue);
        }
        if (propType === String || propType === 2 /* String */) {
            // could have been passed as a number or boolean
            // but we still want it as a string
            return propValue.toString();
        }
    }
    // not sure exactly what type we want
    // so no need to change to a different type
    return propValue;
}
function render(plt, cmpMeta, hostElm, instance, perf) {
    try {
        if (false) {
            perf.mark("render_start:" + hostElm.nodeName.toLowerCase());
        }
        // if this component has a render function, let's fire
        // it off and generate the child vnodes for this host element
        // note that we do not create the host element cuz it already exists
        var hostMeta = cmpMeta.componentConstructor.host;
        var encapsulation = cmpMeta.componentConstructor.encapsulation;
        // test if this component should be shadow dom
        // and if so does the browser supports it
        var useNativeShadowDom = (encapsulation === 'shadow' && plt.domApi.$supportsShadowDom);
        var reflectHostAttr = void 0;
        var rootElm = hostElm;
        if (false) {
            reflectHostAttr = reflectInstanceValuesToHostAttributes(cmpMeta.componentConstructor.properties, instance);
        }
        // this component SHOULD use native slot/shadow dom
        // this browser DOES support native shadow dom
        // and this is the first render
        // let's create that shadow root
        // test if this component should be shadow dom
        // and if so does the browser supports it
        if (true && useNativeShadowDom) {
            rootElm = hostElm.shadowRoot;
        }
        if (true && !hostElm['s-rn']) {
            // attach the styles this component needs, if any
            // this fn figures out if the styles should go in a
            // shadow root or if they should be global
            plt.attachStyles(plt, plt.domApi, cmpMeta, hostElm);
            var scopeId = hostElm['s-sc'];
            if (scopeId) {
                plt.domApi.$addClass(hostElm, getElementScopeId(scopeId, true));
                if (encapsulation === 'scoped') {
                    plt.domApi.$addClass(hostElm, getElementScopeId(scopeId));
                }
            }
        }
        if (instance.render || instance.hostData || hostMeta || reflectHostAttr) {
            // tell the platform we're actively rendering
            // if a value is changed within a render() then
            // this tells the platform not to queue the change
            plt.activeRender = true;
            var vnodeChildren = instance.render && instance.render();
            var vnodeHostData = void 0;
            if (false) {
                // user component provided a "hostData()" method
                // the returned data/attributes are used on the host element
                vnodeHostData = instance.hostData && instance.hostData();
                if (false) {
                    if (vnodeHostData && cmpMeta.membersMeta) {
                        var foundHostKeys = Object.keys(vnodeHostData).reduce(function (err, k) {
                            if (cmpMeta.membersMeta[k]) {
                                return err.concat(k);
                            }
                            if (cmpMeta.membersMeta[dashToPascalCase(k)]) {
                                return err.concat(dashToPascalCase(k));
                            }
                            return err;
                        }, []);
                        if (foundHostKeys.length > 0) {
                            throw new Error("The following keys were attempted to be set with hostData() from the " +
                                (cmpMeta.tagNameMeta + " component: " + foundHostKeys.join(', ') + ". ") +
                                "If you would like to modify these please set @Prop({ mutable: true, reflectToAttr: true}) " +
                                "on the @Prop() decorator.");
                        }
                    }
                }
            }
            if (false && reflectHostAttr) {
                vnodeHostData = vnodeHostData ? Object.assign(vnodeHostData, reflectHostAttr) : reflectHostAttr;
            }
            // tell the platform we're done rendering
            // now any changes will again queue
            plt.activeRender = false;
            if (false && hostMeta) {
                // component meta data has a "theme"
                // use this to automatically generate a good css class
                // from the mode and color to add to the host element
                vnodeHostData = applyComponentHostData(vnodeHostData, hostMeta, instance);
            }
            // looks like we've got child nodes to render into this host element
            // or we need to update the css class/attrs on the host element
            // if we haven't already created a vnode, then we give the renderer the actual element
            // if this is a re-render, then give the renderer the last vnode we already created
            var oldVNode = plt.vnodeMap.get(hostElm) || {};
            oldVNode.elm = rootElm;
            var hostVNode = h(null, vnodeHostData, vnodeChildren);
            if (false) {
                // only care if we're reflecting values to the host element
                hostVNode.ishost = true;
            }
            // each patch always gets a new vnode
            // the host element itself isn't patched because it already exists
            // kick off the actual render and any DOM updates
            plt.vnodeMap.set(hostElm, plt.render(hostElm, oldVNode, hostVNode, useNativeShadowDom, encapsulation));
        }
        // update styles!
        if (true && plt.customStyle) {
            plt.customStyle.updateHost(hostElm);
        }
        // it's official, this element has rendered
        hostElm['s-rn'] = true;
        if (hostElm['s-rc']) {
            // ok, so turns out there are some child host elements
            // waiting on this parent element to load
            // let's fire off all update callbacks waiting
            hostElm['s-rc'].forEach(function (cb) { return cb(); });
            hostElm['s-rc'] = null;
        }
        if (false) {
            perf.mark("render_end:" + hostElm.nodeName.toLowerCase());
            perf.measure("render:" + hostElm.nodeName.toLowerCase(), "render_start:" + hostElm.nodeName.toLowerCase(), "render_end:" + hostElm.nodeName.toLowerCase());
        }
    }
    catch (e) {
        plt.activeRender = false;
        plt.onError(e, 8 /* RenderError */, hostElm, true);
    }
}
function applyComponentHostData(vnodeHostData, hostMeta, instance) {
    vnodeHostData = vnodeHostData || {};
    // component meta data has a "theme"
    // use this to automatically generate a good css class
    // from the mode and color to add to the host element
    Object.keys(hostMeta).forEach(function (key) {
        if (key === 'theme') {
            // host: { theme: 'button' }
            // adds css classes w/ mode and color combinations
            // class="button button-md button-primary button-md-primary"
            convertCssNamesToObj(vnodeHostData['class'] = vnodeHostData['class'] || {}, hostMeta[key], instance.mode, instance.color);
        }
        else if (key === 'class') {
            // host: { class: 'multiple css-classes' }
            // class="multiple css-classes"
            convertCssNamesToObj(vnodeHostData[key] = vnodeHostData[key] || {}, hostMeta[key]);
        }
        else {
            // rando attribute/properties
            vnodeHostData[key] = hostMeta[key];
        }
    });
    return vnodeHostData;
}
function convertCssNamesToObj(cssClassObj, className, mode, color) {
    className.split(' ').forEach(function (cssClass) {
        cssClassObj[cssClass] = true;
        if (mode) {
            cssClassObj[cssClass + "-" + mode] = true;
            if (color) {
                cssClassObj[cssClass + "-" + mode + "-" + color] = cssClassObj[cssClass + "-" + color] = true;
            }
        }
    });
}
function reflectInstanceValuesToHostAttributes(properties, instance, reflectHostAttr) {
    if (properties) {
        Object.keys(properties).forEach(function (memberName) {
            if (properties[memberName].reflectToAttr) {
                reflectHostAttr = reflectHostAttr || {};
                reflectHostAttr[memberName] = instance[memberName];
            }
        });
    }
    return reflectHostAttr;
}
function queueUpdate(plt, elm, perf) {
    if (false) {
        perf.mark("queue:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
    }
    // we're actively processing this component
    plt.processingCmp.add(elm);
    // only run patch if it isn't queued already
    if (!plt.isQueuedForUpdate.has(elm)) {
        plt.isQueuedForUpdate.set(elm, true);
        // run the patch in the next tick
        // vdom diff and patch the host element for differences
        if (plt.isAppLoaded) {
            // app has already loaded
            // let's queue this work in the dom write phase
            plt.queue.write(function () { return update(plt, elm, perf); });
        }
        else {
            // app hasn't finished loading yet
            // so let's use next tick to do everything
            // as fast as possible
            plt.queue.tick(function () { return update(plt, elm, perf); });
        }
    }
}
function update(plt, elm, perf, isInitialLoad, instance, ancestorHostElement) {
    return __awaiter(this, void 0, void 0, function () {
        var e_1, e_2;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    if (false) {
                        perf.mark("update_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
                    }
                    // no longer queued for update
                    plt.isQueuedForUpdate.delete(elm);
                    if (!!plt.isDisconnectedMap.has(elm)) return [3 /*break*/, 12];
                    instance = plt.instanceMap.get(elm);
                    isInitialLoad = !instance;
                    if (!isInitialLoad) return [3 /*break*/, 6];
                    ancestorHostElement = plt.ancestorHostElementMap.get(elm);
                    if (ancestorHostElement && !ancestorHostElement['s-rn']) {
                        // this is the intial load
                        // this element has an ancestor host element
                        // but the ancestor host element has NOT rendered yet
                        // so let's just cool our jets and wait for the ancestor to render
                        (ancestorHostElement['s-rc'] = ancestorHostElement['s-rc'] || []).push(function () {
                            // this will get fired off when the ancestor host element
                            // finally gets around to rendering its lazy self
                            update(plt, elm, perf);
                        });
                        return [2 /*return*/];
                    }
                    // haven't created a component instance for this host element yet!
                    // create the instance from the user's component class
                    // https://www.youtube.com/watch?v=olLxrojmvMg
                    instance = initComponentInstance(plt, elm, plt.hostSnapshotMap.get(elm), perf);
                    if (!(false && instance)) return [3 /*break*/, 5];
                    _a.label = 1;
                case 1:
                    _a.trys.push([1, 4, , 5]);
                    if (!instance.componentWillLoad) return [3 /*break*/, 3];
                    if (false) {
                        perf.mark("componentWillLoad_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
                    }
                    return [4 /*yield*/, instance.componentWillLoad()];
                case 2:
                    _a.sent();
                    if (false) {
                        perf.mark("componentWillLoad_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
                        perf.measure("componentWillLoad:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "componentWillLoad_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "componentWillLoad_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
                    }
                    _a.label = 3;
                case 3: return [3 /*break*/, 5];
                case 4:
                    e_1 = _a.sent();
                    plt.onError(e_1, 3 /* WillLoadError */, elm);
                    return [3 /*break*/, 5];
                case 5: return [3 /*break*/, 11];
                case 6:
                    if (!(false && instance)) return [3 /*break*/, 11];
                    _a.label = 7;
                case 7:
                    _a.trys.push([7, 10, , 11]);
                    if (!instance.componentWillUpdate) return [3 /*break*/, 9];
                    if (false) {
                        perf.mark("componentWillUpdate_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
                    }
                    return [4 /*yield*/, instance.componentWillUpdate()];
                case 8:
                    _a.sent();
                    if (false) {
                        perf.mark("componentWillUpdate_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
                    }
                    _a.label = 9;
                case 9: return [3 /*break*/, 11];
                case 10:
                    e_2 = _a.sent();
                    plt.onError(e_2, 5 /* WillUpdateError */, elm);
                    return [3 /*break*/, 11];
                case 11:
                    // if this component has a render function, let's fire
                    // it off and generate a vnode for this
                    render(plt, plt.getComponentMeta(elm), elm, instance, perf);
                    if (false) {
                        perf.mark("update_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
                        perf.measure("update:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "update_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "update_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
                    }
                    elm['s-init']();
                    if (false) {
                        elm['s-hmr-load'] && elm['s-hmr-load']();
                    }
                    _a.label = 12;
                case 12: return [2 /*return*/];
            }
        });
    });
}
function defineMember(plt, property, elm, instance, memberName, hostSnapshot, perf, hostAttributes, hostAttrValue) {
    function getComponentProp(values) {
        // component instance prop/state getter
        // get the property value directly from our internal values
        values = plt.valuesMap.get(plt.hostElementMap.get(this));
        return values && values[memberName];
    }
    function setComponentProp(newValue, elm) {
        // component instance prop/state setter (cannot be arrow fn)
        elm = plt.hostElementMap.get(this);
        if (elm) {
            if (property.state || property.mutable) {
                setValue(plt, elm, memberName, newValue, perf);
            }
            else if (false) {
                console.warn("@Prop() \"" + memberName + "\" on \"" + elm.tagName + "\" cannot be modified.");
            }
        }
    }
    if (property.type || property.state) {
        var values = plt.valuesMap.get(elm);
        if (!property.state) {
            if (property.attr && (values[memberName] === undefined || values[memberName] === '')) {
                // check the prop value from the host element attribute
                if ((hostAttributes = hostSnapshot && hostSnapshot.$attributes) && isDef(hostAttrValue = hostAttributes[property.attr])) {
                    // looks like we've got an attribute value
                    // let's set it to our internal values
                    values[memberName] = parsePropertyValue(property.type, hostAttrValue);
                }
            }
            if (true) {
                // client-side
                // within the browser, the element's prototype
                // already has its getter/setter set, but on the
                // server the prototype is shared causing issues
                // so instead the server's elm has the getter/setter
                // directly on the actual element instance, not its prototype
                // so on the browser we can use "hasOwnProperty"
                if (elm.hasOwnProperty(memberName)) {
                    // @Prop or @Prop({mutable:true})
                    // property values on the host element should override
                    // any default values on the component instance
                    if (values[memberName] === undefined) {
                        values[memberName] = parsePropertyValue(property.type, elm[memberName]);
                    }
                    // for the client only, let's delete its "own" property
                    // this way our already assigned getter/setter on the prototype kicks in
                    // the very special case is to NOT do this for "mode"
                    if (memberName !== 'mode') {
                        delete elm[memberName];
                    }
                }
            }
            else {
                // server-side
                // server-side elm has the getter/setter
                // on the actual element instance, not its prototype
                // on the server we cannot accurately use "hasOwnProperty"
                // instead we'll do a direct lookup to see if the
                // constructor has this property
                if (elementHasProperty(plt, elm, memberName)) {
                    // @Prop or @Prop({mutable:true})
                    // property values on the host element should override
                    // any default values on the component instance
                    if (values[memberName] === undefined) {
                        values[memberName] = elm[memberName];
                    }
                }
            }
        }
        if (instance.hasOwnProperty(memberName) && values[memberName] === undefined) {
            // @Prop() or @Prop({mutable:true}) or @State()
            // we haven't yet got a value from the above checks so let's
            // read any "own" property instance values already set
            // to our internal value as the source of getter data
            // we're about to define a property and it'll overwrite this "own" property
            values[memberName] = instance[memberName];
        }
        if (property.watchCallbacks) {
            values[WATCH_CB_PREFIX + memberName] = property.watchCallbacks.slice();
        }
        // add getter/setter to the component instance
        // these will be pointed to the internal data set from the above checks
        definePropertyGetterSetter(instance, memberName, getComponentProp, setComponentProp);
    }
    else if (true && property.elementRef) {
        // @Element()
        // add a getter to the element reference using
        // the member name the component meta provided
        definePropertyValue(instance, memberName, elm);
    }
    else if (false && property.method) {
        // @Method()
        // add a property "value" on the host element
        // which we'll bind to the instance's method
        definePropertyValue(elm, memberName, instance[memberName].bind(instance));
    }
    else if (false && property.context) {
        // @Prop({ context: 'config' })
        var contextObj = plt.getContextItem(property.context);
        if (contextObj !== undefined) {
            definePropertyValue(instance, memberName, (contextObj.getContext && contextObj.getContext(elm)) || contextObj);
        }
    }
    else if (false && property.connect) {
        // @Prop({ connect: 'ion-loading-ctrl' })
        definePropertyValue(instance, memberName, plt.propConnect(property.connect));
    }
}
function setValue(plt, elm, memberName, newVal, perf, instance) {
    // get the internal values object, which should always come from the host element instance
    // create the _values object if it doesn't already exist
    var values = plt.valuesMap.get(elm);
    if (!values) {
        plt.valuesMap.set(elm, values = {});
    }
    var oldVal = values[memberName];
    // check our new property value against our internal value
    if (newVal !== oldVal) {
        // gadzooks! the property's value has changed!!
        // set our new value!
        // https://youtu.be/dFtLONl4cNc?t=22
        values[memberName] = newVal;
        instance = plt.instanceMap.get(elm);
        if (instance) {
            // get an array of method names of watch functions to call
            if (false) {
                var watchMethods = values[WATCH_CB_PREFIX + memberName];
                if (watchMethods) {
                    // this instance is watching for when this property changed
                    for (var i = 0; i < watchMethods.length; i++) {
                        try {
                            // fire off each of the watch methods that are watching this property
                            instance[watchMethods[i]].call(instance, newVal, oldVal, memberName);
                        }
                        catch (e) {
                            console.error(e);
                        }
                    }
                }
            }
            if (!plt.activeRender && elm['s-rn']) {
                // looks like this value actually changed, so we've got work to do!
                // but only if we've already rendered, otherwise just chill out
                // queue that we need to do an update, but don't worry about queuing
                // up millions cuz this function ensures it only runs once
                queueUpdate(plt, elm, perf);
            }
        }
    }
}
function definePropertyValue(obj, propertyKey, value) {
    // minification shortcut
    Object.defineProperty(obj, propertyKey, {
        'configurable': true,
        'value': value
    });
}
function definePropertyGetterSetter(obj, propertyKey, get, set) {
    // minification shortcut
    Object.defineProperty(obj, propertyKey, {
        'configurable': true,
        'get': get,
        'set': set
    });
}
var WATCH_CB_PREFIX = "wc-";
function proxyComponentInstance(plt, cmpConstructor, elm, instance, hostSnapshot, perf) {
    if (false) {
        perf.mark("proxy_instance_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
    }
    // at this point we've got a specific node of a host element, and created a component class instance
    // and we've already created getters/setters on both the host element and component class prototypes
    // let's upgrade any data that might have been set on the host element already
    // and let's have the getters/setters kick in and do their jobs
    // let's automatically add a reference to the host element on the instance
    plt.hostElementMap.set(instance, elm);
    // create the values object if it doesn't already exist
    // this will hold all of the internal getter/setter values
    if (!plt.valuesMap.has(elm)) {
        plt.valuesMap.set(elm, {});
    }
    // get the properties from the constructor
    // and add default "mode" and "color" properties
    Object.entries(Object.assign({ color: { type: String } }, cmpConstructor.properties, { mode: { type: String } })).forEach(function (_a) {
        var memberName = _a[0], property = _a[1];
        // define each of the members and initialize what their role is
        defineMember(plt, property, elm, instance, memberName, hostSnapshot, perf);
    });
    if (false) {
        perf.mark("proxy_instance_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
        perf.measure("proxy_instance:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "proxy_instance_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "proxy_instance_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
    }
}
function initComponentInstance(plt, elm, hostSnapshot, perf, instance, componentConstructor, queuedEvents, i) {
    try {
        if (false) {
            perf.mark("init_instance_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
        }
        // using the user's component class, let's create a new instance
        componentConstructor = plt.getComponentMeta(elm).componentConstructor;
        instance = new componentConstructor();
        // ok cool, we've got an host element now, and a actual instance
        // and there were no errors creating the instance
        // let's upgrade the data on the host element
        // and let the getters/setters do their jobs
        proxyComponentInstance(plt, componentConstructor, elm, instance, hostSnapshot, perf);
        if (false) {
            // add each of the event emitters which wire up instance methods
            // to fire off dom events from the host element
            initEventEmitters(plt, componentConstructor.events, instance);
        }
        if (false) {
            try {
                // replay any event listeners on the instance that
                // were queued up between the time the element was
                // connected and before the instance was ready
                queuedEvents = plt.queuedEvents.get(elm);
                if (queuedEvents) {
                    // events may have already fired before the instance was even ready
                    // now that the instance is ready, let's replay all of the events that
                    // we queued up earlier that were originally meant for the instance
                    for (i = 0; i < queuedEvents.length; i += 2) {
                        // data was added in sets of two
                        // first item the eventMethodName
                        // second item is the event data
                        // take a look at initElementListener()
                        instance[queuedEvents[i]](queuedEvents[i + 1]);
                    }
                    plt.queuedEvents.delete(elm);
                }
            }
            catch (e) {
                plt.onError(e, 2 /* QueueEventsError */, elm);
            }
        }
    }
    catch (e) {
        // something done went wrong trying to create a component instance
        // create a dumby instance so other stuff can load
        // but chances are the app isn't fully working cuz this component has issues
        instance = {};
        plt.onError(e, 7 /* InitInstanceError */, elm, true);
    }
    plt.instanceMap.set(elm, instance);
    if (false) {
        perf.mark("init_instance_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
        perf.measure("init_instance:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "init_instance_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "init_instance_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
    }
    return instance;
}
function initComponentLoaded(plt, elm, hydratedCssClass, perf, instance, onReadyCallbacks, hasCmpLoaded) {
    if (true && !allChildrenHaveConnected(plt, elm)) {
        // this check needs to be done when using the customElements polyfill
        // since the polyfill uses MutationObserver which causes the
        // connectedCallbacks to fire async, which isn't ideal for the code below
        return;
    }
    // all is good, this component has been told it's time to finish loading
    // it's possible that we've already decided to destroy this element
    // check if this element has any actively loading child elements
    if ((instance = plt.instanceMap.get(elm)) &&
        !plt.isDisconnectedMap.has(elm) &&
        (!elm['s-ld'] || !elm['s-ld'].length)) {
        // cool, so at this point this element isn't already being destroyed
        // and it does not have any child elements that are still loading
        // all of this element's children have loaded (if any)
        plt.isCmpReady.set(elm, true);
        if (!(hasCmpLoaded = plt.isCmpLoaded.has(elm))) {
            if (false) {
                perf.mark("init_loaded_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
            }
            // remember that this component has loaded
            // isCmpLoaded map is useful to know if we should fire
            // the lifecycle componentDidLoad() or componentDidUpdate()
            plt.isCmpLoaded.set(elm, true);
            // ensure we remove any child references cuz it doesn't matter at this point
            elm['s-ld'] = undefined;
            // add the css class that this element has officially hydrated
            plt.domApi.$addClass(elm, hydratedCssClass);
        }
        try {
            // fire off the ref if it exists
            callNodeRefs(plt.vnodeMap.get(elm));
            // fire off the user's elm.componentOnReady() callbacks that were
            // put directly on the element (well before anything was ready)
            if (onReadyCallbacks = plt.onReadyCallbacksMap.get(elm)) {
                onReadyCallbacks.forEach(function (cb) { return cb(elm); });
                plt.onReadyCallbacksMap.delete(elm);
            }
            if (false && !hasCmpLoaded && instance.componentDidLoad) {
                // we've never loaded this component
                // fire off the user's componentDidLoad method (if one was provided)
                // componentDidLoad only runs ONCE, after the instance's element has been
                // assigned as the host element, and AFTER render() has been called
                // and all the child componenets have finished loading
                if (false) {
                    perf.mark("componentDidLoad_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
                }
                instance.componentDidLoad();
                if (false) {
                    perf.mark("componentDidLoad_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
                    perf.measure("componentDidLoad:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "componentDidLoad_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "componentDidLoad_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
                }
            }
            else if (false && hasCmpLoaded && instance.componentDidUpdate) {
                // we've already loaded this component
                // fire off the user's componentDidUpdate method (if one was provided)
                // componentDidUpdate runs AFTER render() has been called
                // and all child components have finished updating
                if (false) {
                    perf.mark("componentDidUpdate_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
                }
                instance.componentDidUpdate();
                if (false) {
                    perf.mark("componentDidUpdate_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
                    perf.measure("componentDidUpdate:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "componentDidUpdate_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "componentDidUpdate_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
                }
            }
        }
        catch (e) {
            plt.onError(e, 4 /* DidLoadError */, elm);
        }
        if (false && !hasCmpLoaded) {
            perf.mark("init_loaded_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
            perf.measure("init_loaded:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "init_loaded_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "init_loaded_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
            perf.measure("loaded:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "connected_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "init_loaded_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
        }
        // ( •_•)
        // ( •_•)>⌐■-■
        // (⌐■_■)
        // load events fire from bottom to top
        // the deepest elements load first then bubbles up
        propagateComponentReady(plt, elm);
    }
}
function allChildrenHaveConnected(plt, elm) {
    // Note: in IE11 <svg> does not have the "children" property
    for (var i = 0; i < elm.childNodes.length; i++) {
        var child = elm.childNodes[i];
        if (child.nodeType === 1 /* ElementNode */) {
            if (plt.getComponentMeta(child) && !plt.hasConnectedMap.has(child)) {
                // this is a defined componnent
                // but it hasn't connected yet
                return false;
            }
            if (!allChildrenHaveConnected(plt, child)) {
                // one of the defined child components hasn't connected yet
                return false;
            }
        }
    }
    // everything has connected, we're good
    return true;
}
function propagateComponentReady(plt, elm, index, ancestorsActivelyLoadingChildren, ancestorHostElement, cb) {
    // we're no longer processing this component
    plt.processingCmp.delete(elm);
    // load events fire from bottom to top
    // the deepest elements load first then bubbles up
    if ((ancestorHostElement = plt.ancestorHostElementMap.get(elm))) {
        // ok so this element already has a known ancestor host element
        // let's make sure we remove this element from its ancestor's
        // known list of child elements which are actively loading
        ancestorsActivelyLoadingChildren = ancestorHostElement['s-ld'];
        if (ancestorsActivelyLoadingChildren) {
            index = ancestorsActivelyLoadingChildren.indexOf(elm);
            if (index > -1) {
                // yup, this element is in the list of child elements to wait on
                // remove it so we can work to get the length down to 0
                ancestorsActivelyLoadingChildren.splice(index, 1);
            }
            // the ancestor's initLoad method will do the actual checks
            // to see if the ancestor is actually loaded or not
            // then let's call the ancestor's initLoad method if there's no length
            // (which actually ends up as this method again but for the ancestor)
            if (!ancestorsActivelyLoadingChildren.length) {
                ancestorHostElement['s-init'] && ancestorHostElement['s-init']();
            }
        }
        plt.ancestorHostElementMap.delete(elm);
    }
    if (plt.onAppReadyCallbacks.length && !plt.processingCmp.size) {
        // we've got some promises waiting on the entire app to be done processing
        // so it should have an empty queue and no longer rendering
        while ((cb = plt.onAppReadyCallbacks.shift())) {
            cb();
        }
    }
}
function disconnectedCallback(plt, elm, perf) {
    // only disconnect if we're not temporarily disconnected
    // tmpDisconnected will happen when slot nodes are being relocated
    if (!plt.tmpDisconnected && isDisconnected(plt.domApi, elm)) {
        if (false) {
            perf.mark("disconnected_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
        }
        // ok, let's officially destroy this thing
        // set this to true so that any of our pending async stuff
        // doesn't continue since we already decided to destroy this node
        // elm._hasDestroyed = true;
        plt.isDisconnectedMap.set(elm, true);
        // double check that we've informed the ancestor host elements
        // that they're good to go and loaded (cuz this one is on its way out)
        propagateComponentReady(plt, elm);
        // since we're disconnecting, call all of the JSX ref's with null
        callNodeRefs(plt.vnodeMap.get(elm), true);
        // detatch any event listeners that may have been added
        // because we're not passing an exact event name it'll
        // remove all of this element's event, which is good
        plt.domApi.$removeEventListener(elm);
        plt.hasListenersMap.delete(elm);
        if (false) {
            // call instance componentDidUnload
            // if we've created an instance for this
            var instance = plt.instanceMap.get(elm);
            if (instance && instance.componentDidUnload) {
                // call the user's componentDidUnload if there is one
                instance.componentDidUnload();
            }
        }
        // clear CSS var-shim tracking
        if (true && plt.customStyle) {
            plt.customStyle.removeHost(elm);
        }
        // clear any references to other elements
        // more than likely we've already deleted these references
        // but let's double check there pal
        [
            plt.ancestorHostElementMap,
            plt.onReadyCallbacksMap,
            plt.hostSnapshotMap
        ].forEach(function (wm) { return wm.delete(elm); });
        if (false) {
            perf.mark("disconnected_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
            perf.measure("disconnected:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "disconnected_start:" + elm.nodeName.toLowerCase() + ":" + elm['s-id'], "disconnected_end:" + elm.nodeName.toLowerCase() + ":" + elm['s-id']);
        }
    }
}
function isDisconnected(domApi, elm) {
    while (elm) {
        if (!domApi.$parentNode(elm)) {
            return domApi.$nodeType(elm) !== 9 /* DocumentNode */;
        }
        elm = domApi.$parentNode(elm);
    }
}
function hmrStart(plt, cmpMeta, elm, hmrVersionId) {
    // ¯\_(ツ)_/¯
    // keep the existing state
    // forget the constructor
    cmpMeta.componentConstructor = null;
    // no sir, this component has never loaded, not once, ever
    plt.isCmpLoaded.delete(elm);
    plt.isCmpReady.delete(elm);
    // forget the instance
    var instance = plt.instanceMap.get(elm);
    if (instance) {
        plt.hostElementMap.delete(instance);
        plt.instanceMap.delete(elm);
    }
    // detatch any event listeners that may have been added
    // because we're not passing an exact event name it'll
    // remove all of this element's event, which is good
    plt.domApi.$removeEventListener(elm);
    plt.hasListenersMap.delete(elm);
    cmpMeta.listenersMeta = null;
    // create a callback for when this component finishes hmr
    elm['s-hmr-load'] = function () {
        // finished hmr for this element
        delete elm['s-hmr-load'];
        hmrFinish(plt, cmpMeta, elm);
    };
    // create the new host snapshot from the element
    plt.hostSnapshotMap.set(elm, initHostSnapshot(plt.domApi, cmpMeta, elm));
    // request the bundle again
    plt.requestBundle(cmpMeta, elm, hmrVersionId);
}
function hmrFinish(plt, cmpMeta, elm) {
    if (!plt.hasListenersMap.has(elm)) {
        plt.hasListenersMap.set(elm, true);
        // initElementListeners works off of cmp metadata
        // but we just got new data from the constructor
        // so let's update the cmp metadata w/ constructor listener data
        if (cmpMeta.componentConstructor && cmpMeta.componentConstructor.listeners) {
            cmpMeta.listenersMeta = cmpMeta.componentConstructor.listeners.map(function (lstn) {
                var listenerMeta = {
                    eventMethodName: lstn.method,
                    eventName: lstn.name,
                    eventCapture: !!lstn.capture,
                    eventPassive: !!lstn.passive,
                    eventDisabled: !!lstn.disabled,
                };
                return listenerMeta;
            });
            initElementListeners(plt, elm);
        }
    }
}
function proxyHostElementPrototype(plt, membersEntries, hostPrototype, perf) {
    // create getters/setters on the host element prototype to represent the public API
    // the setters allows us to know when data has changed so we can re-render
    if (!true) {
        // in just a server-side build
        // let's set the properties to the values immediately
        var values_1 = plt.valuesMap.get(hostPrototype);
        if (!values_1) {
            plt.valuesMap.set(hostPrototype, values_1 = {});
        }
        membersEntries.forEach(function (_a) {
            var memberName = _a[0], member = _a[1];
            var memberType = member.memberType;
            if (memberType & (1 /* Prop */ | 2 /* PropMutable */)) {
                values_1[memberName] = hostPrototype[memberName];
            }
        });
    }
    membersEntries.forEach(function (_a) {
        var memberName = _a[0], member = _a[1];
        // add getters/setters
        var memberType = member.memberType;
        if (memberType & (1 /* Prop */ | 2 /* PropMutable */)) {
            // @Prop() or @Prop({ mutable: true })
            definePropertyGetterSetter(hostPrototype, memberName, function getHostElementProp() {
                // host element getter (cannot be arrow fn)
                // yup, ugly, srynotsry
                return (plt.valuesMap.get(this) || {})[memberName];
            }, function setHostElementProp(newValue) {
                // host element setter (cannot be arrow fn)
                setValue(plt, this, memberName, parsePropertyValue(member.propType, newValue), perf);
            });
        }
        else if (memberType === 32 /* Method */) {
            // @Method()
            // add a placeholder noop value on the host element's prototype
            // incase this method gets called before setup
            definePropertyValue(hostPrototype, memberName, noop);
        }
    });
}
function initHostElement(plt, cmpMeta, HostElementConstructor, hydratedCssClass, perf) {
    // let's wire up our functions to the host element's prototype
    // we can also inject our platform into each one that needs that api
    // note: these cannot be arrow functions cuz "this" is important here hombre
    HostElementConstructor.connectedCallback = function () {
        // coolsville, our host element has just hit the DOM
        connectedCallback(plt, cmpMeta, this, perf);
    };
    HostElementConstructor.disconnectedCallback = function () {
        // the element has left the builing
        disconnectedCallback(plt, this, perf);
    };
    HostElementConstructor['s-init'] = function () {
        initComponentLoaded(plt, this, hydratedCssClass, perf);
    };
    HostElementConstructor.forceUpdate = function () {
        queueUpdate(plt, this, perf);
    };
    if (false) {
        HostElementConstructor['s-hmr'] = function (hmrVersionId) {
            hmrStart(plt, cmpMeta, this, hmrVersionId);
        };
    }
    if (cmpMeta.membersMeta) {
        var entries = Object.entries(cmpMeta.membersMeta);
        if (true) {
            var attrToProp_1 = {};
            entries.forEach(function (_a) {
                var propName = _a[0], attribName = _a[1].attribName;
                if (attribName) {
                    attrToProp_1[attribName] = propName;
                }
            });
            attrToProp_1 = Object.assign({}, attrToProp_1);
            HostElementConstructor.attributeChangedCallback = function (attribName, _oldVal, newVal) {
                // the browser has just informed us that an attribute
                // on the host element has changed
                attributeChangedCallback(attrToProp_1, this, attribName, newVal);
            };
        }
        // add getters/setters to the host element members
        // these would come from the @Prop and @Method decorators that
        // should create the public API to this component
        proxyHostElementPrototype(plt, entries, HostElementConstructor, perf);
    }
}
function proxyController(domApi, controllerComponents, ctrlTag) {
    return {
        'create': proxyProp(domApi, controllerComponents, ctrlTag, 'create'),
        'componentOnReady': proxyProp(domApi, controllerComponents, ctrlTag, 'componentOnReady')
    };
}
function proxyProp(domApi, controllerComponents, ctrlTag, proxyMethodName) {
    return function () {
        var args = arguments;
        return loadComponent(domApi, controllerComponents, ctrlTag)
            .then(function (ctrlElm) { return ctrlElm[proxyMethodName].apply(ctrlElm, args); });
    };
}
function loadComponent(domApi, controllerComponents, ctrlTag) {
    var ctrlElm = controllerComponents[ctrlTag];
    var body = domApi.$doc.body;
    if (body) {
        if (!ctrlElm) {
            ctrlElm = body.querySelector(ctrlTag);
        }
        if (!ctrlElm) {
            ctrlElm = controllerComponents[ctrlTag] = domApi.$createElement(ctrlTag);
            domApi.$appendChild(body, ctrlElm);
        }
        return ctrlElm.componentOnReady();
    }
    return Promise.resolve();
}
function createPlatformMainLegacy(namespace, Context, win, doc, resourcesUrl, hydratedCssClass, components, customStyle) {
    var perf = win.performance;
    if (false) {
        perf.mark("app_load_start");
    }
    var cmpRegistry = { 'html': {} };
    var bundleQueue = [];
    var loadedBundles = new Map();
    var pendingBundleRequests = new Set();
    var controllerComponents = {};
    var App = win[namespace] = win[namespace] || {};
    var domApi = createDomApi(App, win, doc);
    if (false && true && domApi.$supportsShadowDom && customStyle) {
        console.error('Unsupported browser. Native shadow-dom available but CSS Custom Properites are not.');
    }
    // set App Context
    Context.isServer = Context.isPrerender = !(Context.isClient = true);
    Context.window = win;
    Context.location = win.location;
    Context.document = doc;
    Context.resourcesUrl = Context.publicPath = resourcesUrl;
    if (false) {
        Context.enableListener = function (instance, eventName, enabled, attachTo, passive) { return enableEventListener(plt, instance, eventName, enabled, attachTo, passive); };
    }
    if (false) {
        Context.emit = function (elm, eventName, data) { return domApi.$dispatchEvent(elm, Context.eventNameFn ? Context.eventNameFn(eventName) : eventName, data); };
    }
    // add the h() fn to the app's global namespace
    App.h = h;
    App.Context = Context;
    // keep a global set of tags we've already defined
    var globalDefined = win['s-defined'] = (win['s-defined'] || {});
    // internal id increment for unique ids
    var ids = 0;
    // create the platform api which is used throughout common core code
    var plt = {
        domApi: domApi,
        defineComponent: defineComponent,
        emitEvent: Context.emit,
        customStyle: customStyle,
        getComponentMeta: function (elm) { return cmpRegistry[domApi.$tagName(elm)]; },
        getContextItem: function (contextKey) { return Context[contextKey]; },
        isClient: true,
        isDefinedComponent: function (elm) { return !!(globalDefined[domApi.$tagName(elm)] || plt.getComponentMeta(elm)); },
        onError: function (err, type, elm) { return console.error(err, type, elm && elm.tagName); },
        nextId: function () { return namespace + (ids++); },
        propConnect: function (ctrlTag) { return proxyController(domApi, controllerComponents, ctrlTag); },
        queue: (Context.queue = createQueueClient(App, win)),
        requestBundle: requestBundle,
        isAppLoaded: false,
        activeRender: false,
        tmpDisconnected: false,
        ancestorHostElementMap: new WeakMap(),
        componentAppliedStyles: new WeakMap(),
        hasConnectedMap: new WeakMap(),
        hasListenersMap: new WeakMap(),
        isCmpLoaded: new WeakMap(),
        isCmpReady: new WeakMap(),
        hostElementMap: new WeakMap(),
        hostSnapshotMap: new WeakMap(),
        instanceMap: new WeakMap(),
        isDisconnectedMap: new WeakMap(),
        isQueuedForUpdate: new WeakMap(),
        onReadyCallbacksMap: new WeakMap(),
        queuedEvents: new WeakMap(),
        vnodeMap: new WeakMap(),
        valuesMap: new WeakMap(),
        processingCmp: new Set(),
        onAppReadyCallbacks: []
    };
    // create a method that returns a promise
    // which gets resolved when the app's queue is empty
    // and app is idle, works for both initial load and updates
    App.onReady = function () { return new Promise(function (resolve) { return plt.queue.write(function () { return plt.processingCmp.size ? plt.onAppReadyCallbacks.push(resolve) : resolve(); }); }); };
    // create the renderer that will be used
    plt.render = createRendererPatch(plt, domApi);
    // setup the root element which is the mighty <html> tag
    // the <html> has the final say of when the app has loaded
    var rootElm = domApi.$doc.documentElement;
    rootElm['s-ld'] = [];
    rootElm['s-rn'] = true;
    // this will fire when all components have finished loaded
    rootElm['s-init'] = function () {
        plt.isCmpReady.set(rootElm, App.loaded = plt.isAppLoaded = true);
        domApi.$dispatchEvent(win, 'appload', { detail: { namespace: namespace } });
        if (false) {
            perf.mark('app_load_end');
            perf.measure('app_load', 'app_load_start', 'app_load_end');
        }
    };
    // if the HTML was generated from SSR
    // then let's walk the tree and generate vnodes out of the data
    createVNodesFromSsr(plt, domApi, rootElm);
    function defineComponent(cmpMeta, HostElementConstructor) {
        if (!win.customElements.get(cmpMeta.tagNameMeta)) {
            // keep a map of all the defined components
            globalDefined[cmpMeta.tagNameMeta] = true;
            // initialize the members on the host element prototype
            // keep a ref to the metadata with the tag as the key
            initHostElement(plt, (cmpRegistry[cmpMeta.tagNameMeta] = cmpMeta), HostElementConstructor.prototype, hydratedCssClass, perf);
            if (true) {
                // add which attributes should be observed
                var observedAttributes = [];
                // at this point the membersMeta only includes attributes which should
                // be observed, it does not include all props yet, so it's safe to
                // loop through all of the props (attrs) and observed them
                for (var propName in cmpMeta.membersMeta) {
                    if (cmpMeta.membersMeta[propName].attribName) {
                        observedAttributes.push(
                        // add this attribute to our array of attributes we need to observe
                        cmpMeta.membersMeta[propName].attribName);
                    }
                }
                // set the array of all the attributes to keep an eye on
                // https://www.youtube.com/watch?v=RBs21CFBALI
                HostElementConstructor.observedAttributes = observedAttributes;
            }
            if (false) {
                perf.mark("define_start:" + cmpMeta.tagNameMeta);
            }
            // define the custom element
            win.customElements.define(cmpMeta.tagNameMeta, HostElementConstructor);
            if (false) {
                perf.mark("define_end:" + cmpMeta.tagNameMeta);
                perf.measure("define:" + cmpMeta.tagNameMeta, "define_start:" + cmpMeta.tagNameMeta, "define_end:" + cmpMeta.tagNameMeta);
            }
        }
    }
    function getLoadedBundle(bundleId, hmrVersionId) {
        if (false && hmrVersionId) {
            loadedBundles.delete(bundleId.replace(/^\.\//, ''));
        }
        if (bundleId == null) {
            return null;
        }
        return loadedBundles.get(bundleId.replace(/^\.\//, ''));
    }
    function isLoadedBundle(id) {
        if (id === 'exports' || id === 'require') {
            return true;
        }
        return !!getLoadedBundle(id);
    }
    function execBundleCallback(bundleId, deps, callback) {
        var bundleExports = {};
        try {
            callback.apply(null, deps.map(function (d) {
                if (d === 'exports')
                    return bundleExports;
                if (d === 'require')
                    return userRequire;
                return getLoadedBundle(d);
            }));
        }
        catch (e) {
            console.error(e);
        }
        // If name is undefined then this callback was fired by component callback
        if (bundleId === undefined) {
            return;
        }
        loadedBundles.set(bundleId, bundleExports);
        // If name contains chunk then this callback was associated with a dependent bundle loading
        // let's add a reference to the constructors on each components metadata
        // each key in moduleImports is a PascalCased tag name
        if (bundleId && !bundleId.endsWith('.js')) {
            Object.keys(bundleExports).forEach(function (pascalCasedTagName) {
                var normalizedTagName = pascalCasedTagName.replace(/-/g, '').toLowerCase();
                var registryTags = Object.keys(cmpRegistry);
                for (var i = 0; i < registryTags.length; i++) {
                    var normalizedRegistryTag = registryTags[i].replace(/-/g, '').toLowerCase();
                    if (normalizedRegistryTag === normalizedTagName) {
                        var cmpMeta = cmpRegistry[registryTags[i]];
                        if (cmpMeta) {
                            // get the component constructor from the module
                            cmpMeta.componentConstructor = bundleExports[pascalCasedTagName];
                            initStyleTemplate(domApi, cmpMeta, cmpMeta.encapsulationMeta, cmpMeta.componentConstructor.style, cmpMeta.componentConstructor.styleMode, perf);
                        }
                        break;
                    }
                }
            });
        }
    }
    function userRequire(ids, resolve) {
        loadBundle(undefined, ids, resolve);
    }
    /**
     * Check to see if any items in the bundle queue can be executed
     */
    function checkQueue() {
        for (var i = bundleQueue.length - 1; i >= 0; i--) {
            var _a = bundleQueue[i], bundleId = _a[0], dependentsList = _a[1], importer = _a[2];
            if (dependentsList.every(isLoadedBundle) && !isLoadedBundle(bundleId)) {
                bundleQueue.splice(i, 1);
                execBundleCallback(bundleId, dependentsList, importer);
            }
        }
    }
    /**
     * This function is called anytime a JS file is loaded
     */
    function loadBundle(bundleId, dependentsList, importer) {
        var missingDependents = dependentsList.filter(function (d) { return !isLoadedBundle(d); });
        missingDependents.forEach(function (d) {
            requestUrl(resourcesUrl + d.replace('.js', '.es5.js'));
        });
        bundleQueue.push([bundleId, dependentsList, importer]);
        // If any dependents are not yet met then queue the bundle execution
        if (missingDependents.length === 0) {
            checkQueue();
        }
    }
    App.loadBundle = loadBundle;
    var requestBundleQueue = [];
    if (true && customStyle) {
        customStyle.init().then(function () {
            // loaded all the css, let's run all the request bundle callbacks
            while (requestBundleQueue.length) {
                requestBundleQueue.shift()();
            }
            // set to null to we know we're loaded
            requestBundleQueue = null;
        });
    }
    // This is executed by the component's connected callback.
    function requestBundle(cmpMeta, elm, hmrVersionId) {
        var bundleId = (typeof cmpMeta.bundleIds === 'string') ?
            cmpMeta.bundleIds :
            cmpMeta.bundleIds[elm.mode];
        if (getLoadedBundle(bundleId, hmrVersionId)) {
            // sweet, we've already loaded this bundle
            queueUpdate(plt, elm, perf);
        }
        else {
            // never seen this bundle before, let's start the request
            // and add it to the callbacks to fire when it has loaded
            bundleQueue.push([undefined, [bundleId], function () {
                    queueUpdate(plt, elm, perf);
                }]);
            // when to request the bundle depends is we're using the css shim or not
            if (true && customStyle) {
                // using css shim, so we've gotta wait until it's ready
                if (requestBundleQueue) {
                    // add this to the loadBundleQueue to run when css is ready
                    requestBundleQueue.push(function () { return requestComponentBundle(bundleId, hmrVersionId); });
                }
                else {
                    // css already all loaded
                    requestComponentBundle(bundleId, hmrVersionId);
                }
            }
            else {
                // not using css shim, so no need to wait on css shim to finish
                // figure out which bundle to request and kick it off
                requestComponentBundle(bundleId, hmrVersionId);
            }
        }
    }
    function requestComponentBundle(bundleId, hmrVersionId) {
        // create the url we'll be requesting
        // always use the es5/jsonp callback module
        var useScopedCss = true && !domApi.$supportsShadowDom;
        var url = resourcesUrl + bundleId + (useScopedCss ? '.sc' : '') + '.es5.entry.js';
        if (false && hmrVersionId) {
            url += '?s-hmr=' + hmrVersionId;
        }
        requestUrl(url);
    }
    // Use JSONP to load in bundles
    function requestUrl(url) {
        var tmrId;
        var scriptElm;
        function onScriptComplete() {
            clearTimeout(tmrId);
            scriptElm.onerror = scriptElm.onload = null;
            domApi.$remove(scriptElm);
            // remove from our list of active requests
            pendingBundleRequests.delete(url);
        }
        if (!pendingBundleRequests.has(url)) {
            // we're not already actively requesting this url
            // let's kick off the bundle request and
            // remember that we're now actively requesting this url
            pendingBundleRequests.add(url);
            // create a sript element to add to the document.head
            scriptElm = domApi.$createElement('script');
            scriptElm.charset = 'utf-8';
            scriptElm.async = true;
            scriptElm.src = url;
            // create a fallback timeout if something goes wrong
            tmrId = setTimeout(onScriptComplete, 120000);
            // add script completed listener to this script element
            scriptElm.onerror = scriptElm.onload = onScriptComplete;
            // inject a script tag in the head
            // kick off the actual request
            domApi.$appendChild(domApi.$doc.head, scriptElm);
        }
    }
    if (true) {
        plt.attachStyles = function (plt, domApi, cmpMeta, elm) {
            attachStyles(plt, domApi, cmpMeta, elm);
        };
    }
    if (false) {
        generateDevInspector(namespace, win, plt, components);
    }
    // register all the components now that everything's ready
    if (false) {
        perf.mark("define_custom_elements_start");
    }
    components
        .map(function (data) {
        var cmpMeta = parseComponentLoader(data);
        return cmpRegistry[cmpMeta.tagNameMeta] = cmpMeta;
    })
        .forEach(function (cmpMeta) {
        // es5 way of extending HTMLElement
        function HostElement(self) {
            return HTMLElement.call(this, self);
        }
        HostElement.prototype = Object.create(HTMLElement.prototype, { constructor: { value: HostElement, configurable: true } });
        defineComponent(cmpMeta, HostElement);
    });
    if (false) {
        perf.mark("define_custom_elements_end");
        perf.measure("define_custom_elements", "define_custom_elements_start", "define_custom_elements_end");
    }
    if (!plt.hasConnectedComponent) {
        // we just defined call the custom elements but no
        // connectedCallbacks happened, so no components in the dom :(
        rootElm['s-init']();
    }
    // create the componentOnReady fn
    initCoreComponentOnReady(plt, App, win, win['s-apps'], win['s-cr']);
    // notify that the app has initialized and the core script is ready
    // but note that the components have not fully loaded yet
    App.initialized = true;
}
/*
Extremely simple css parser. Intended to be not more than what we need
and definitely not necessarily correct =).
*/
/** @unrestricted */
var StyleNode = /** @class */ (function () {
    function StyleNode() {
        this.start = 0;
        this.end = 0;
        this.previous = null;
        this.parent = null;
        this.rules = null;
        this.parsedCssText = '';
        this.cssText = '';
        this.atRule = false;
        this.type = 0;
        this.keyframesName = '';
        this.selector = '';
        this.parsedSelector = '';
    }
    return StyleNode;
}());
// given a string of css, return a simple rule tree
/**
 * @param {string} text
 * @return {StyleNode}
 */
function parse(text) {
    text = clean(text);
    return parseCss(lex(text), text);
}
// remove stuff we don't care about that may hinder parsing
/**
 * @param {string} cssText
 * @return {string}
 */
function clean(cssText) {
    return cssText.replace(RX.comments, '').replace(RX.port, '');
}
// super simple {...} lexer that returns a node tree
/**
 * @param {string} text
 * @return {StyleNode}
 */
function lex(text) {
    var root = new StyleNode();
    root['start'] = 0;
    root['end'] = text.length;
    var n = root;
    for (var i = 0, l = text.length; i < l; i++) {
        if (text[i] === OPEN_BRACE) {
            if (!n['rules']) {
                n['rules'] = [];
            }
            var p = n;
            var previous = p['rules'][p['rules'].length - 1] || null;
            n = new StyleNode();
            n['start'] = i + 1;
            n['parent'] = p;
            n['previous'] = previous;
            p['rules'].push(n);
        }
        else if (text[i] === CLOSE_BRACE) {
            n['end'] = i + 1;
            n = n['parent'] || root;
        }
    }
    return root;
}
// add selectors/cssText to node tree
/**
 * @param {StyleNode} node
 * @param {string} text
 * @return {StyleNode}
 */
function parseCss(node, text) {
    var t = text.substring(node['start'], node['end'] - 1);
    node['parsedCssText'] = node['cssText'] = t.trim();
    if (node.parent) {
        var ss = node.previous ? node.previous['end'] : node.parent['start'];
        t = text.substring(ss, node['start'] - 1);
        t = _expandUnicodeEscapes(t);
        t = t.replace(RX.multipleSpaces, ' ');
        // TODO(sorvell): ad hoc; make selector include only after last ;
        // helps with mixin syntax
        t = t.substring(t.lastIndexOf(';') + 1);
        var s = node['parsedSelector'] = node['selector'] = t.trim();
        node['atRule'] = (s.indexOf(AT_START) === 0);
        // note, support a subset of rule types...
        if (node['atRule']) {
            if (s.indexOf(MEDIA_START) === 0) {
                node['type'] = types.MEDIA_RULE;
            }
            else if (s.match(RX.keyframesRule)) {
                node['type'] = types.KEYFRAMES_RULE;
                node['keyframesName'] = node['selector'].split(RX.multipleSpaces).pop();
            }
        }
        else {
            if (s.indexOf(VAR_START) === 0) {
                node['type'] = types.MIXIN_RULE;
            }
            else {
                node['type'] = types.STYLE_RULE;
            }
        }
    }
    var r$ = node['rules'];
    if (r$) {
        for (var i = 0, l = r$.length, r = void 0; (i < l) && (r = r$[i]); i++) {
            parseCss(r, text);
        }
    }
    return node;
}
/**
 * conversion of sort unicode escapes with spaces like `\33 ` (and longer) into
 * expanded form that doesn't require trailing space `\000033`
 * @param {string} s
 * @return {string}
 */
function _expandUnicodeEscapes(s) {
    return s.replace(/\\([0-9a-f]{1,6})\s/gi, function () {
        var code = arguments[1], repeat = 6 - code.length;
        while (repeat--) {
            code = '0' + code;
        }
        return '\\' + code;
    });
}
/** @enum {number} */
var types = {
    STYLE_RULE: 1,
    KEYFRAMES_RULE: 7,
    MEDIA_RULE: 4,
    MIXIN_RULE: 1000
};
var OPEN_BRACE = '{';
var CLOSE_BRACE = '}';
// helper regexp's
var RX = {
    comments: /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,
    port: /@import[^;]*;/gim,
    customProp: /(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?(?:[;\n]|$)/gim,
    mixinProp: /(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?{[^}]*?}(?:[;\n]|$)?/gim,
    mixinApply: /@apply\s*\(?[^);]*\)?\s*(?:[;\n]|$)?/gim,
    varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim,
    keyframesRule: /^@[^\s]*keyframes/,
    multipleSpaces: /\s+/g
};
var VAR_START = '--';
var MEDIA_START = '@media';
var AT_START = '@';
function findRegex(regex, cssText, offset) {
    regex['lastIndex'] = 0;
    var r = cssText.substring(offset).match(regex);
    if (r) {
        var start = offset + r['index'];
        return {
            start: start,
            end: start + r[0].length
        };
    }
    return null;
}
var VAR_USAGE_START = /\bvar\(/;
var VAR_ASSIGN_START = /\B--[\w-]+\s*:/;
var COMMENTS = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim;
var TRAILING_LINES = /^[\t ]+\n/gm;
var EMPTY_SELECTORS = /[^{}]*{\s*}/gm;
function resolveVar(props, prop, fallback) {
    if (props[prop]) {
        return props[prop];
    }
    if (fallback) {
        return executeTemplate(fallback, props);
    }
    return '';
}
function findVarEndIndex(cssText, offset) {
    var count = 0;
    var i = offset;
    for (; i < cssText.length; i++) {
        var c = cssText[i];
        if (c === '(') {
            count++;
        }
        else if (c === ')') {
            count--;
            if (count <= 0) {
                return i + 1;
            }
        }
    }
    return i;
}
function parseVar(cssText, offset) {
    var varPos = findRegex(VAR_USAGE_START, cssText, offset);
    if (!varPos) {
        return null;
    }
    var endVar = findVarEndIndex(cssText, varPos.start);
    var varContent = cssText.substring(varPos.end, endVar - 1);
    var _a = varContent.split(','), propName = _a[0], fallback = _a.slice(1);
    return {
        start: varPos.start,
        end: endVar,
        propName: propName.trim(),
        fallback: fallback.length > 0 ? fallback.join(',').trim() : undefined
    };
}
function compileVar(cssText, template, offset) {
    var varMeta = parseVar(cssText, offset);
    if (!varMeta) {
        template.push(cssText.substring(offset, cssText.length));
        return cssText.length;
    }
    var propName = varMeta.propName;
    var fallback = varMeta.fallback != null ? compileTemplate(varMeta.fallback) : undefined;
    template.push(cssText.substring(offset, varMeta.start), function (params) { return resolveVar(params, propName, fallback); });
    return varMeta.end;
}
function executeTemplate(template, props) {
    var final = '';
    for (var i = 0; i < template.length; i++) {
        var s = template[i];
        final += (typeof s === 'string')
            ? s
            : s(props);
    }
    return final;
}
function findEndValue(cssText, offset) {
    var onStr = false;
    var double = false;
    var i = offset;
    for (; i < cssText.length; i++) {
        var c = cssText[i];
        if (onStr) {
            if (double && c === '"') {
                onStr = false;
            }
            if (!double && c === '\'') {
                onStr = false;
            }
        }
        else {
            if (c === '"') {
                onStr = true;
                double = true;
            }
            else if (c === '\'') {
                onStr = true;
                double = false;
            }
            else if (c === ';') {
                return i + 1;
            }
            else if (c === '}') {
                return i;
            }
        }
    }
    return i;
}
function removeCustomAssigns(cssText) {
    var final = '';
    var offset = 0;
    while (true) {
        var assignPos = findRegex(VAR_ASSIGN_START, cssText, offset);
        var start = assignPos ? assignPos.start : cssText.length;
        final += cssText.substring(offset, start);
        if (assignPos) {
            offset = findEndValue(cssText, start);
        }
        else {
            break;
        }
    }
    return final;
}
function compileTemplate(cssText) {
    var index = 0;
    cssText = cssText.replace(COMMENTS, '');
    cssText = removeCustomAssigns(cssText)
        .replace(EMPTY_SELECTORS, '')
        .replace(TRAILING_LINES, '');
    var segments = [];
    while (index < cssText.length) {
        index = compileVar(cssText, segments, index);
    }
    return segments;
}
function resolveValues(selectors) {
    var props = {};
    selectors.forEach(function (selector) {
        selector.declarations.forEach(function (dec) {
            props[dec.prop] = dec.value;
        });
    });
    var propsValues = {};
    var entries = Object.entries(props);
    var _loop_1 = function (i) {
        var dirty = false;
        entries.forEach(function (_a) {
            var key = _a[0], value = _a[1];
            var propValue = executeTemplate(value, propsValues);
            if (propValue !== propsValues[key]) {
                propsValues[key] = propValue;
                dirty = true;
            }
        });
        if (!dirty) {
            return "break";
        }
    };
    for (var i = 0; i < 10; i++) {
        var state_1 = _loop_1(i);
        if (state_1 === "break")
            break;
    }
    return propsValues;
}
function getSelectors(root, index) {
    if (index === void 0) { index = 0; }
    if (!root.rules) {
        return [];
    }
    var selectors = [];
    root.rules
        .filter(function (rule) { return rule.type === types.STYLE_RULE; })
        .forEach(function (rule) {
        var declarations = getDeclarations(rule.cssText);
        if (declarations.length > 0) {
            rule.parsedSelector.split(',').forEach(function (selector) {
                selector = selector.trim();
                selectors.push({
                    selector: selector,
                    declarations: declarations,
                    specificity: computeSpecificity(selector),
                    nu: index
                });
            });
        }
        index++;
    });
    return selectors;
}
function computeSpecificity(_selector) {
    return 1;
}
var IMPORTANT = '!important';
var FIND_DECLARATIONS = /(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};{])+)|\{([^}]*)\}(?:(?=[;\s}])|$))/gm;
function getDeclarations(cssText) {
    var declarations = [];
    var xArray;
    while (xArray = FIND_DECLARATIONS.exec(cssText.trim())) {
        var _a = normalizeValue(xArray[2]), value = _a.value, important = _a.important;
        declarations.push({
            prop: xArray[1].trim(),
            value: compileTemplate(value),
            important: important,
        });
    }
    return declarations;
}
function normalizeValue(value) {
    var regex = /\s+/gim;
    value = value.replace(regex, ' ').trim();
    var important = value.endsWith(IMPORTANT);
    if (important) {
        value = value.substr(0, value.length - IMPORTANT.length).trim();
    }
    return {
        value: value,
        important: important
    };
}
function getActiveSelectors(hostEl, hostScopeMap, globalScopes) {
    // computes the css scopes that might affect this particular element
    var scopes = globalScopes.concat(getScopesForElement(hostScopeMap, hostEl));
    // each scope might have an array of associated selectors
    // let's flatten the complete array of selectors from all the scopes
    var selectorSet = getSelectorsForScopes(scopes);
    // we filter to only the selectors that matches the hostEl
    var activeSelectors = selectorSet.filter(function (selector) { return matches(hostEl, selector.selector); });
    // sort selectors by specifity
    return sortSelectors(activeSelectors);
}
function getScopesForElement(hostTemplateMap, node) {
    var scopes = [];
    while (node) {
        var scope = hostTemplateMap.get(node);
        if (scope) {
            scopes.push(scope);
        }
        node = node.parentElement;
    }
    return scopes;
}
function getSelectorsForScopes(scopes) {
    var selectors = [];
    scopes.forEach(function (scope) {
        selectors.push.apply(selectors, scope.selectors);
    });
    return selectors;
}
function sortSelectors(selectors) {
    selectors.sort(function (a, b) {
        if (a.specificity === b.specificity) {
            return a.nu - b.nu;
        }
        return a.specificity - b.specificity;
    });
    return selectors;
}
function matches(el, selector) {
    return el.matches(selector);
}
function parseCSS(original) {
    var ast = parse(original);
    var template = compileTemplate(original);
    var selectors = getSelectors(ast);
    return {
        original: original,
        template: template,
        selectors: selectors,
        isDynamic: template.length > 1
    };
}
function addGlobalStyle(globalScopes, styleEl) {
    var css = parseCSS(styleEl.innerHTML);
    css.styleEl = styleEl;
    globalScopes.push(css);
}
function updateGlobalScopes(scopes) {
    var selectors = getSelectorsForScopes(scopes);
    var props = resolveValues(selectors);
    scopes.forEach(function (scope) {
        if (scope.isDynamic) {
            scope.styleEl.innerHTML = executeTemplate(scope.template, props);
        }
    });
}
function reScope(scope, cssScopeId) {
    var template = scope.template.map(function (segment) {
        return (typeof segment === 'string')
            ? replaceScope(segment, scope.cssScopeId, cssScopeId)
            : segment;
    });
    var selectors = scope.selectors.map(function (sel) {
        return Object.assign({}, sel, { selector: replaceScope(sel.selector, scope.cssScopeId, cssScopeId) });
    });
    return Object.assign({}, scope, { template: template,
        selectors: selectors,
        cssScopeId: cssScopeId });
}
function replaceScope(original, oldScopeId, newScopeId) {
    original = replaceAll(original, "\\." + oldScopeId, "." + newScopeId);
    return original;
}
function replaceAll(input, find, replace) {
    return input.replace(new RegExp(find, 'g'), replace);
}
function loadDocument(doc, globalScopes) {
    return loadDocumentLinks(doc, globalScopes).then(function () {
        loadDocumentStyles(doc, globalScopes);
    });
}
function loadDocumentLinks(doc, globalScopes) {
    var promises = [];
    var linkElms = doc.querySelectorAll('link[rel="stylesheet"][href]');
    for (var i = 0; i < linkElms.length; i++) {
        promises.push(addGlobalLink(doc, globalScopes, linkElms[i]));
    }
    return Promise.all(promises);
}
function loadDocumentStyles(doc, globalScopes) {
    var styleElms = doc.querySelectorAll('style');
    for (var i = 0; i < styleElms.length; i++) {
        addGlobalStyle(globalScopes, styleElms[i]);
    }
}
function addGlobalLink(doc, globalScopes, linkElm) {
    var url = linkElm.href;
    return fetch(url).then(function (rsp) { return rsp.text(); }).then(function (text) {
        if (hasCssVariables(text) && linkElm.parentNode) {
            if (hasRelativeUrls(text)) {
                text = fixRelativeUrls(text, url);
            }
            var styleEl = doc.createElement('style');
            styleEl.innerHTML = text;
            addGlobalStyle(globalScopes, styleEl);
            linkElm.parentNode.insertBefore(styleEl, linkElm);
            linkElm.remove();
        }
    }).catch(function (err) {
        console.error(err);
    });
}
// This regexp tries to determine when a variable is declared, for example:
//
// .my-el { --highlight-color: green; }
//
// but we don't want to trigger when a classname uses "--" or a pseudo-class is
// used. We assume that the only characters that can preceed a variable
// declaration are "{", from an opening block, ";" from a preceeding rule, or a
// space. This prevents the regexp from matching a word in a selector, since
// they would need to start with a "." or "#". (We assume element names don't
// start with "--").
var CSS_VARIABLE_REGEXP = /[\s;{]--[-a-zA-Z0-9]+\s*:/m;
function hasCssVariables(css) {
    return css.indexOf('var(') > -1 || CSS_VARIABLE_REGEXP.test(css);
}
// This regexp find all url() usages with relative urls
var CSS_URL_REGEXP = /url[\s]*\([\s]*['"]?(?![http|/])([^\'\"\)]*)[\s]*['"]?\)[\s]*/gim;
function hasRelativeUrls(css) {
    CSS_URL_REGEXP.lastIndex = 0;
    return CSS_URL_REGEXP.test(css);
}
function fixRelativeUrls(css, originalUrl) {
    // get the basepath from the original import url
    var basePath = originalUrl.replace(/[^/]*$/, '');
    // replace the relative url, with the new relative url
    return css.replace(CSS_URL_REGEXP, function (fullMatch, url) {
        // rhe new relative path is the base path + uri
        // TODO: normalize relative URL
        var relativeUrl = basePath + url;
        return fullMatch.replace(url, relativeUrl);
    });
}
function supportsCssVars(win) {
    return !!(win.CSS && win.CSS.supports && win.CSS.supports('color', 'var(--c)'));
}
var CustomStyle = /** @class */ (function () {
    function CustomStyle(win, doc) {
        this.win = win;
        this.doc = doc;
        this.count = 0;
        this.hostStyleMap = new WeakMap();
        this.hostScopeMap = new WeakMap();
        this.globalScopes = [];
        this.scopesMap = new Map();
    }
    CustomStyle.prototype.init = function () {
        var _this = this;
        return new Promise(function (resolve) {
            _this.win.requestAnimationFrame(function () {
                loadDocument(_this.doc, _this.globalScopes).then(function () { return resolve(); });
            });
        });
    };
    CustomStyle.prototype.addLink = function (linkEl) {
        var _this = this;
        return addGlobalLink(this.doc, this.globalScopes, linkEl).then(function () {
            _this.updateGlobal();
        });
    };
    CustomStyle.prototype.addGlobalStyle = function (styleEl) {
        addGlobalStyle(this.globalScopes, styleEl);
        this.updateGlobal();
    };
    CustomStyle.prototype.createHostStyle = function (hostEl, templateName, cssText) {
        if (this.hostScopeMap.has(hostEl)) {
            return null;
        }
        var cssScopeId = hostEl['s-sc'];
        var baseScope = this.registerHostTemplate(cssText, templateName, cssScopeId);
        var isDynamicScoped = baseScope.isDynamic && baseScope.cssScopeId;
        var needStyleEl = isDynamicScoped || !baseScope.styleEl;
        if (!needStyleEl) {
            return null;
        }
        var styleEl = this.doc.createElement('style');
        if (isDynamicScoped) {
            var newScopeId = baseScope.cssScopeId + "-" + this.count;
            hostEl['s-sc'] = newScopeId;
            this.hostStyleMap.set(hostEl, styleEl);
            this.hostScopeMap.set(hostEl, reScope(baseScope, newScopeId));
            this.count++;
        }
        else {
            baseScope.styleEl = styleEl;
            if (!baseScope.isDynamic) {
                styleEl.innerHTML = executeTemplate(baseScope.template, {});
            }
            this.globalScopes.push(baseScope);
            this.updateGlobal();
            this.hostScopeMap.set(hostEl, baseScope);
        }
        return styleEl;
    };
    CustomStyle.prototype.removeHost = function (hostEl) {
        var css = this.hostStyleMap.get(hostEl);
        if (css) {
            css.remove();
        }
        this.hostStyleMap.delete(hostEl);
        this.hostScopeMap.delete(hostEl);
    };
    CustomStyle.prototype.updateHost = function (hostEl) {
        var scope = this.hostScopeMap.get(hostEl);
        if (scope && scope.isDynamic && scope.cssScopeId) {
            var styleEl = this.hostStyleMap.get(hostEl);
            if (styleEl) {
                var selectors = getActiveSelectors(hostEl, this.hostScopeMap, this.globalScopes);
                var props = resolveValues(selectors);
                styleEl.innerHTML = executeTemplate(scope.template, props);
            }
        }
    };
    CustomStyle.prototype.updateGlobal = function () {
        updateGlobalScopes(this.globalScopes);
    };
    CustomStyle.prototype.registerHostTemplate = function (cssText, scopeName, cssScopeId) {
        var scope = this.scopesMap.get(scopeName);
        if (!scope) {
            scope = parseCSS(cssText);
            scope.cssScopeId = cssScopeId;
            this.scopesMap.set(scopeName, scope);
        }
        return scope;
    };
    return CustomStyle;
}());
// es5 build which does not use es module imports or dynamic imports
// and requires the es5 way of extending HTMLElement
var customStyle;
if (true) {
    var needShim = !supportsCssVars(window);
    if (false) {
        if (window.location.search.indexOf('cssvars=false') > 0) {
            // by adding ?shadow=false it'll force the slot polyfill
            // only add this check when in dev mode
            needShim = true;
        }
    }
    if (needShim) {
        customStyle = new CustomStyle(window, document);
    }
}
createPlatformMainLegacy(namespace, Context, window, document, resourcesUrl, hydratedCssClass, components, customStyle);