` tag we check the equality
* of the VNodes corresponding to the `
` tags and, since they are the
* same tag in the same position, we'd be able to avoid completely
* re-rendering the subtree under them with a new DOM element and would just
* call out to `patch` to handle reconciling their children and so on.
*
* 3. Check, for both windows, to see if the element at the beginning of the
* window corresponds to the element at the end of the other window. This is
* a heuristic which will let us identify _some_ situations in which
* elements have changed position, for instance it _should_ detect that the
* children nodes themselves have not changed but merely moved in the
* following example:
*
* oldVNode: `
`
* newVNode: `
`
*
* If we find cases like this then we also need to move the concrete DOM
* elements corresponding to the moved children to write the re-order to the
* DOM.
*
* 4. Finally, if VNodes have the `key` attribute set on them we check for any
* nodes in the old children which have the same key as the first element in
* our window on the new children. If we find such a node we handle calling
* out to `patch`, moving relevant DOM nodes, and so on, in accordance with
* what we find.
*
* Finally, once we've narrowed our 'windows' to the point that either of them
* collapse (i.e. they have length 0) we then handle any remaining VNode
* insertion or deletion that needs to happen to get a DOM state that correctly
* reflects the new child VNodes. If, for instance, after our window on the old
* children has collapsed we still have more nodes on the new children that
* we haven't dealt with yet then we need to add them, or if the new children
* collapse but we still have unhandled _old_ children then we need to make
* sure the corresponding DOM nodes are removed.
*
* @param parentElm the node into which the parent VNode is rendered
* @param oldCh the old children of the parent node
* @param newVNode the new VNode which will replace the parent
* @param newCh the new children of the parent node
*/
const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
let oldStartIdx = 0;
let newStartIdx = 0;
let idxInOld = 0;
let i = 0;
let oldEndIdx = oldCh.length - 1;
let oldStartVnode = oldCh[0];
let oldEndVnode = oldCh[oldEndIdx];
let newEndIdx = newCh.length - 1;
let newStartVnode = newCh[0];
let newEndVnode = newCh[newEndIdx];
let node;
let elmToMove;
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)) {
// if the start nodes are the same then we should patch the new VNode
// onto the old one, and increment our `newStartIdx` and `oldStartIdx`
// indices to reflect that. We don't need to move any DOM Nodes around
// since things are matched up in order.
patch(oldStartVnode, newStartVnode);
oldStartVnode = oldCh[++oldStartIdx];
newStartVnode = newCh[++newStartIdx];
}
else if (isSameVnode(oldEndVnode, newEndVnode)) {
// likewise, if the end nodes are the same we patch new onto old and
// decrement our end indices, and also likewise in this case we don't
// need to move any DOM Nodes.
patch(oldEndVnode, newEndVnode);
oldEndVnode = oldCh[--oldEndIdx];
newEndVnode = newCh[--newEndIdx];
}
else if (isSameVnode(oldStartVnode, newEndVnode)) {
patch(oldStartVnode, newEndVnode);
// We need to move the element for `oldStartVnode` into a position which
// will be appropriate for `newEndVnode`. For this we can use
// `.insertBefore` and `oldEndVnode.$elm$.nextSibling`. If there is a
// sibling for `oldEndVnode.$elm$` then we want to move the DOM node for
// `oldStartVnode` between `oldEndVnode` and it's sibling, like so:
//
//
//
//
//
//
//
// ```
// In this case if we do not unshadow here and use the value of the shadowing property, attributeChangedCallback
// will be called with `newValue = "some-value"` and will set the shadowed property (this.someAttribute = "another-value")
// to the value that was set inline i.e. "some-value" from above example. When
// the connectedCallback attempts to unshadow it will use "some-value" as the initial value rather than "another-value"
//
// The case where the attribute was NOT set inline but was not set programmatically shall be handled/unshadowed
// by connectedCallback as this attributeChangedCallback will not fire.
//
// https://developers.google.com/web/fundamentals/web-components/best-practices#lazy-properties
//
// TODO(STENCIL-16) we should think about whether or not we actually want to be reflecting the attributes to
// properties here given that this goes against best practices outlined here
// https://developers.google.com/web/fundamentals/web-components/best-practices#avoid-reentrancy
if (this.hasOwnProperty(propName)) {
newValue = this[propName];
delete this[propName];
}
else if (prototype.hasOwnProperty(propName) &&
typeof this[propName] === 'number' &&
this[propName] == newValue) {
// if the propName exists on the prototype of `Cstr`, this update may be a result of Stencil using native
// APIs to reflect props as attributes. Calls to `setAttribute(someElement, propName)` will result in
// `propName` to be converted to a `DOMString`, which may not be what we want for other primitive props.
return;
}
this[propName] = newValue === null && typeof this[propName] === 'boolean' ? false : newValue;
});
};
// create an array of attributes to observe
// and also create a map of html attribute name to js property name
Cstr.observedAttributes = members
.filter(([_, m]) => m[0] & 15 /* MEMBER_FLAGS.HasAttribute */) // filter to only keep props that should match attributes
.map(([propName, m]) => {
const attrName = m[1] || propName;
attrNameToPropName.set(attrName, propName);
if (m[0] & 512 /* MEMBER_FLAGS.ReflectAttr */) {
cmpMeta.$attrsToReflect$.push([propName, attrName]);
}
return attrName;
});
}
}
return Cstr;
};
const initializeComponent = async (elm, hostRef, cmpMeta, hmrVersionId, Cstr) => {
// initializeComponent
if ((hostRef.$flags$ & 32 /* HOST_FLAGS.hasInitializedComponent */) === 0) {
{
// we haven't initialized this element yet
hostRef.$flags$ |= 32 /* HOST_FLAGS.hasInitializedComponent */;
// lazy loaded components
// request the component's implementation to be
// wired up with the host element
Cstr = loadModule(cmpMeta);
if (Cstr.then) {
// Await creates a micro-task avoid if possible
const endLoad = uniqueTime();
Cstr = await Cstr;
endLoad();
}
if (!Cstr.isProxied) {
// we've never proxied this Constructor before
// let's add the getters/setters to its prototype before
// the first time we create an instance of the implementation
{
cmpMeta.$watchers$ = Cstr.watchers;
}
proxyComponent(Cstr, cmpMeta, 2 /* PROXY_FLAGS.proxyState */);
Cstr.isProxied = true;
}
const endNewInstance = createTime('createInstance', cmpMeta.$tagName$);
// ok, time to construct the instance
// but let's keep track of when we start and stop
// so that the getters/setters don't incorrectly step on data
{
hostRef.$flags$ |= 8 /* HOST_FLAGS.isConstructingInstance */;
}
// construct the lazy-loaded component implementation
// passing the hostRef is very important during
// construction in order to directly wire together the
// host element and the lazy-loaded instance
try {
new Cstr(hostRef);
}
catch (e) {
consoleError(e);
}
{
hostRef.$flags$ &= ~8 /* HOST_FLAGS.isConstructingInstance */;
}
{
hostRef.$flags$ |= 128 /* HOST_FLAGS.isWatchReady */;
}
endNewInstance();
fireConnectedCallback(hostRef.$lazyInstance$);
}
if (Cstr.style) {
// this component has styles but we haven't registered them yet
let style = Cstr.style;
const scopeId = getScopeId(cmpMeta);
if (!styles.has(scopeId)) {
const endRegisterStyles = createTime('registerStyles', cmpMeta.$tagName$);
registerStyle(scopeId, style, !!(cmpMeta.$flags$ & 1 /* CMP_FLAGS.shadowDomEncapsulation */));
endRegisterStyles();
}
}
}
// we've successfully created a lazy instance
const ancestorComponent = hostRef.$ancestorComponent$;
const schedule = () => scheduleUpdate(hostRef, true);
if (ancestorComponent && ancestorComponent['s-rc']) {
// this is the initial load and this component it has an ancestor component
// but the ancestor component has NOT fired its will update lifecycle yet
// so let's just cool our jets and wait for the ancestor to continue first
// this will get fired off when the ancestor component
// finally gets around to rendering its lazy self
// fire off the initial update
ancestorComponent['s-rc'].push(schedule);
}
else {
schedule();
}
};
const fireConnectedCallback = (instance) => {
{
safeCall(instance, 'connectedCallback');
}
};
const connectedCallback = (elm) => {
if ((plt.$flags$ & 1 /* PLATFORM_FLAGS.isTmpDisconnected */) === 0) {
const hostRef = getHostRef(elm);
const cmpMeta = hostRef.$cmpMeta$;
const endConnected = createTime('connectedCallback', cmpMeta.$tagName$);
if (!(hostRef.$flags$ & 1 /* HOST_FLAGS.hasConnected */)) {
// first time this component has connected
hostRef.$flags$ |= 1 /* HOST_FLAGS.hasConnected */;
let hostId;
{
hostId = elm.getAttribute(HYDRATE_ID);
if (hostId) {
if (cmpMeta.$flags$ & 1 /* CMP_FLAGS.shadowDomEncapsulation */) {
const scopeId = addStyle(elm.shadowRoot, cmpMeta);
elm.classList.remove(scopeId + '-h', scopeId + '-s');
}
initializeClientHydrate(elm, cmpMeta.$tagName$, hostId, hostRef);
}
}
{
// find the first ancestor component (if there is one) and register
// this component as one of the actively loading child components for its ancestor
let ancestorComponent = elm;
while ((ancestorComponent = ancestorComponent.parentNode || ancestorComponent.host)) {
// climb up the ancestors looking for the first
// component that hasn't finished its lifecycle update yet
if ((ancestorComponent.nodeType === 1 /* NODE_TYPE.ElementNode */ &&
ancestorComponent.hasAttribute('s-id') &&
ancestorComponent['s-p']) ||
ancestorComponent['s-p']) {
// we found this components first ancestor component
// keep a reference to this component's ancestor component
attachToAncestor(hostRef, (hostRef.$ancestorComponent$ = ancestorComponent));
break;
}
}
}
// Lazy properties
// https://developers.google.com/web/fundamentals/web-components/best-practices#lazy-properties
if (cmpMeta.$members$) {
Object.entries(cmpMeta.$members$).map(([memberName, [memberFlags]]) => {
if (memberFlags & 31 /* MEMBER_FLAGS.Prop */ && elm.hasOwnProperty(memberName)) {
const value = elm[memberName];
delete elm[memberName];
elm[memberName] = value;
}
});
}
{
initializeComponent(elm, hostRef, cmpMeta);
}
}
else {
// not the first time this has connected
// reattach any event listeners to the host
// since they would have been removed when disconnected
addHostEventListeners(elm, hostRef, cmpMeta.$listeners$);
// fire off connectedCallback() on component instance
fireConnectedCallback(hostRef.$lazyInstance$);
}
endConnected();
}
};
const disconnectedCallback = (elm) => {
if ((plt.$flags$ & 1 /* PLATFORM_FLAGS.isTmpDisconnected */) === 0) {
const hostRef = getHostRef(elm);
const instance = hostRef.$lazyInstance$ ;
{
if (hostRef.$rmListeners$) {
hostRef.$rmListeners$.map((rmListener) => rmListener());
hostRef.$rmListeners$ = undefined;
}
}
{
safeCall(instance, 'disconnectedCallback');
}
}
};
const bootstrapLazy = (lazyBundles, options = {}) => {
const endBootstrap = createTime();
const cmpTags = [];
const exclude = options.exclude || [];
const customElements = win.customElements;
const head = doc.head;
const metaCharset = /*@__PURE__*/ head.querySelector('meta[charset]');
const visibilityStyle = /*@__PURE__*/ doc.createElement('style');
const deferredConnectedCallbacks = [];
const styles = /*@__PURE__*/ doc.querySelectorAll(`[${HYDRATED_STYLE_ID}]`);
let appLoadFallback;
let isBootstrapping = true;
let i = 0;
Object.assign(plt, options);
plt.$resourcesUrl$ = new URL(options.resourcesUrl || './', doc.baseURI).href;
{
// If the app is already hydrated there is not point to disable the
// async queue. This will improve the first input delay
plt.$flags$ |= 2 /* PLATFORM_FLAGS.appLoaded */;
}
{
for (; i < styles.length; i++) {
registerStyle(styles[i].getAttribute(HYDRATED_STYLE_ID), convertScopedToShadow(styles[i].innerHTML), true);
}
}
lazyBundles.map((lazyBundle) => {
lazyBundle[1].map((compactMeta) => {
const cmpMeta = {
$flags$: compactMeta[0],
$tagName$: compactMeta[1],
$members$: compactMeta[2],
$listeners$: compactMeta[3],
};
{
cmpMeta.$members$ = compactMeta[2];
}
{
cmpMeta.$listeners$ = compactMeta[3];
}
{
cmpMeta.$attrsToReflect$ = [];
}
{
cmpMeta.$watchers$ = {};
}
const tagName = cmpMeta.$tagName$;
const HostElement = class extends HTMLElement {
// StencilLazyHost
constructor(self) {
// @ts-ignore
super(self);
self = this;
registerHost(self, cmpMeta);
if (cmpMeta.$flags$ & 1 /* CMP_FLAGS.shadowDomEncapsulation */) {
// this component is using shadow dom
// and this browser supports shadow dom
// add the read-only property "shadowRoot" to the host element
// adding the shadow root build conditionals to minimize runtime
{
{
self.attachShadow({ mode: 'open' });
}
}
}
}
connectedCallback() {
if (appLoadFallback) {
clearTimeout(appLoadFallback);
appLoadFallback = null;
}
if (isBootstrapping) {
// connectedCallback will be processed once all components have been registered
deferredConnectedCallbacks.push(this);
}
else {
plt.jmp(() => connectedCallback(this));
}
}
disconnectedCallback() {
plt.jmp(() => disconnectedCallback(this));
}
componentOnReady() {
return getHostRef(this).$onReadyPromise$;
}
};
cmpMeta.$lazyBundleId$ = lazyBundle[0];
if (!exclude.includes(tagName) && !customElements.get(tagName)) {
cmpTags.push(tagName);
customElements.define(tagName, proxyComponent(HostElement, cmpMeta, 1 /* PROXY_FLAGS.isElementConstructor */));
}
});
});
{
visibilityStyle.innerHTML = cmpTags + HYDRATED_CSS;
visibilityStyle.setAttribute('data-styles', '');
head.insertBefore(visibilityStyle, metaCharset ? metaCharset.nextSibling : head.firstChild);
}
// Process deferred connectedCallbacks now all components have been registered
isBootstrapping = false;
if (deferredConnectedCallbacks.length) {
deferredConnectedCallbacks.map((host) => host.connectedCallback());
}
else {
{
plt.jmp(() => (appLoadFallback = setTimeout(appDidLoad, 30)));
}
}
// Fallback appLoad event
endBootstrap();
};
const Fragment = (_, children) => children;
const addHostEventListeners = (elm, hostRef, listeners, attachParentListeners) => {
if (listeners) {
listeners.map(([flags, name, method]) => {
const target = getHostListenerTarget(elm, flags) ;
const handler = hostListenerProxy(hostRef, method);
const opts = hostListenerOpts(flags);
plt.ael(target, name, handler, opts);
(hostRef.$rmListeners$ = hostRef.$rmListeners$ || []).push(() => plt.rel(target, name, handler, opts));
});
}
};
const hostListenerProxy = (hostRef, methodName) => (ev) => {
try {
{
if (hostRef.$flags$ & 256 /* HOST_FLAGS.isListenReady */) {
// instance is ready, let's call it's member method for this event
hostRef.$lazyInstance$[methodName](ev);
}
else {
(hostRef.$queuedListeners$ = hostRef.$queuedListeners$ || []).push([methodName, ev]);
}
}
}
catch (e) {
consoleError(e);
}
};
const getHostListenerTarget = (elm, flags) => {
if (flags & 4 /* LISTENER_FLAGS.TargetDocument */)
return doc;
if (flags & 8 /* LISTENER_FLAGS.TargetWindow */)
return win;
if (flags & 16 /* LISTENER_FLAGS.TargetBody */)
return doc.body;
return elm;
};
// prettier-ignore
const hostListenerOpts = (flags) => (flags & 2 /* LISTENER_FLAGS.Capture */) !== 0;
const hostRefs = /*@__PURE__*/ new WeakMap();
const getHostRef = (ref) => hostRefs.get(ref);
const registerInstance = (lazyInstance, hostRef) => hostRefs.set((hostRef.$lazyInstance$ = lazyInstance), hostRef);
const registerHost = (elm, cmpMeta) => {
const hostRef = {
$flags$: 0,
$hostElement$: elm,
$cmpMeta$: cmpMeta,
$instanceValues$: new Map(),
};
{
hostRef.$onInstancePromise$ = new Promise((r) => (hostRef.$onInstanceResolve$ = r));
}
{
hostRef.$onReadyPromise$ = new Promise((r) => (hostRef.$onReadyResolve$ = r));
elm['s-p'] = [];
elm['s-rc'] = [];
}
addHostEventListeners(elm, hostRef, cmpMeta.$listeners$);
return hostRefs.set(elm, hostRef);
};
const isMemberInElement = (elm, memberName) => memberName in elm;
const consoleError = (e, el) => (0, console.error)(e, el);
const cmpModules = /*@__PURE__*/ new Map();
const loadModule = (cmpMeta, hostRef, hmrVersionId) => {
// loadModuleImport
const exportName = cmpMeta.$tagName$.replace(/-/g, '_');
const bundleId = cmpMeta.$lazyBundleId$;
const module = cmpModules.get(bundleId) ;
if (module) {
return module[exportName];
}
/*!__STENCIL_STATIC_IMPORT_SWITCH__*/
return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(
/* @vite-ignore */
/* webpackInclude: /\.entry\.js$/ */
/* webpackExclude: /\.system\.entry\.js$/ */
/* webpackMode: "lazy" */
`./${bundleId}.entry.js${''}`)); }).then((importedModule) => {
{
cmpModules.set(bundleId, importedModule);
}
return importedModule[exportName];
}, consoleError);
};
const styles = /*@__PURE__*/ new Map();
const win = typeof window !== 'undefined' ? window : {};
const doc = win.document || { head: {} };
const plt = {
$flags$: 0,
$resourcesUrl$: '',
jmp: (h) => h(),
raf: (h) => requestAnimationFrame(h),
ael: (el, eventName, listener, opts) => el.addEventListener(eventName, listener, opts),
rel: (el, eventName, listener, opts) => el.removeEventListener(eventName, listener, opts),
ce: (eventName, opts) => new CustomEvent(eventName, opts),
};
const supportsShadow = true;
const promiseResolve = (v) => Promise.resolve(v);
const supportsConstructableStylesheets = /*@__PURE__*/ (() => {
try {
new CSSStyleSheet();
return typeof new CSSStyleSheet().replaceSync === 'function';
}
catch (e) { }
return false;
})()
;
const queueDomReads = [];
const queueDomWrites = [];
const queueTask = (queue, write) => (cb) => {
queue.push(cb);
if (!queuePending) {
queuePending = true;
if (write && plt.$flags$ & 4 /* PLATFORM_FLAGS.queueSync */) {
nextTick(flush);
}
else {
plt.raf(flush);
}
}
};
const consume = (queue) => {
for (let i = 0; i < queue.length; i++) {
try {
queue[i](performance.now());
}
catch (e) {
consoleError(e);
}
}
queue.length = 0;
};
const flush = () => {
// 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(queueDomReads);
// DOM WRITES!!!
{
consume(queueDomWrites);
if ((queuePending = queueDomReads.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
plt.raf(flush);
}
}
};
const nextTick = /*@__PURE__*/ (cb) => promiseResolve().then(cb);
const writeTask = /*@__PURE__*/ queueTask(queueDomWrites, true);
exports.Fragment = Fragment;
exports.Host = Host;
exports.NAMESPACE = NAMESPACE;
exports.bootstrapLazy = bootstrapLazy;
exports.createEvent = createEvent;
exports.doc = doc;
exports.forceUpdate = forceUpdate;
exports.getAssetPath = getAssetPath;
exports.getElement = getElement;
exports.h = h;
exports.promiseResolve = promiseResolve;
exports.registerInstance = registerInstance;