UNPKG

68.9 kBJavaScriptView Raw
1/*!
2 * Bulmil - MIT License
3 */
4'use strict';
5
6function _interopNamespace(e) {
7 if (e && e.__esModule) return e;
8 var n = Object.create(null);
9 if (e) {
10 Object.keys(e).forEach(function (k) {
11 if (k !== 'default') {
12 var d = Object.getOwnPropertyDescriptor(e, k);
13 Object.defineProperty(n, k, d.get ? d : {
14 enumerable: true,
15 get: function () {
16 return e[k];
17 }
18 });
19 }
20 });
21 }
22 n['default'] = e;
23 return Object.freeze(n);
24}
25
26const NAMESPACE = 'bulmil';
27
28let contentRef;
29let hostTagName;
30let useNativeShadowDom = false;
31let checkSlotFallbackVisibility = false;
32let checkSlotRelocate = false;
33let isSvgMode = false;
34let queuePending = false;
35const win = typeof window !== 'undefined' ? window : {};
36const doc = win.document || { head: {} };
37const plt = {
38 $flags$: 0,
39 $resourcesUrl$: '',
40 jmp: (h) => h(),
41 raf: (h) => requestAnimationFrame(h),
42 ael: (el, eventName, listener, opts) => el.addEventListener(eventName, listener, opts),
43 rel: (el, eventName, listener, opts) => el.removeEventListener(eventName, listener, opts),
44 ce: (eventName, opts) => new CustomEvent(eventName, opts),
45};
46const supportsShadow = true;
47const promiseResolve = (v) => Promise.resolve(v);
48const supportsConstructibleStylesheets = /*@__PURE__*/ (() => {
49 try {
50 new CSSStyleSheet();
51 return typeof new CSSStyleSheet().replace === 'function';
52 }
53 catch (e) { }
54 return false;
55 })()
56 ;
57const CONTENT_REF_ID = 'r';
58const ORG_LOCATION_ID = 'o';
59const SLOT_NODE_ID = 's';
60const TEXT_NODE_ID = 't';
61const HYDRATE_ID = 's-id';
62const HYDRATED_STYLE_ID = 'sty-id';
63const HYDRATE_CHILD_ID = 'c-id';
64const HYDRATED_CSS = '{visibility:hidden}.hydrated{visibility:inherit}';
65const createTime = (fnName, tagName = '') => {
66 {
67 return () => {
68 return;
69 };
70 }
71};
72const uniqueTime = (key, measureText) => {
73 {
74 return () => {
75 return;
76 };
77 }
78};
79const rootAppliedStyles = new WeakMap();
80const registerStyle = (scopeId, cssText, allowCS) => {
81 let style = styles.get(scopeId);
82 if (supportsConstructibleStylesheets && allowCS) {
83 style = (style || new CSSStyleSheet());
84 style.replace(cssText);
85 }
86 else {
87 style = cssText;
88 }
89 styles.set(scopeId, style);
90};
91const addStyle = (styleContainerNode, cmpMeta, mode, hostElm) => {
92 let scopeId = getScopeId(cmpMeta);
93 let style = styles.get(scopeId);
94 // if an element is NOT connected then getRootNode() will return the wrong root node
95 // so the fallback is to always use the document for the root node in those cases
96 styleContainerNode = styleContainerNode.nodeType === 11 /* DocumentFragment */ ? styleContainerNode : doc;
97 if (style) {
98 if (typeof style === 'string') {
99 styleContainerNode = styleContainerNode.head || styleContainerNode;
100 let appliedStyles = rootAppliedStyles.get(styleContainerNode);
101 let styleElm;
102 if (!appliedStyles) {
103 rootAppliedStyles.set(styleContainerNode, (appliedStyles = new Set()));
104 }
105 if (!appliedStyles.has(scopeId)) {
106 if (styleContainerNode.host &&
107 (styleElm = styleContainerNode.querySelector(`[${HYDRATED_STYLE_ID}="${scopeId}"]`))) {
108 // This is only happening on native shadow-dom, do not needs CSS var shim
109 styleElm.innerHTML = style;
110 }
111 else {
112 {
113 styleElm = doc.createElement('style');
114 styleElm.innerHTML = style;
115 }
116 styleContainerNode.insertBefore(styleElm, styleContainerNode.querySelector('link'));
117 }
118 if (appliedStyles) {
119 appliedStyles.add(scopeId);
120 }
121 }
122 }
123 else if (!styleContainerNode.adoptedStyleSheets.includes(style)) {
124 styleContainerNode.adoptedStyleSheets = [...styleContainerNode.adoptedStyleSheets, style];
125 }
126 }
127 return scopeId;
128};
129const attachStyles = (hostRef) => {
130 const cmpMeta = hostRef.$cmpMeta$;
131 const elm = hostRef.$hostElement$;
132 const endAttachStyles = createTime('attachStyles', cmpMeta.$tagName$);
133 addStyle(elm.getRootNode(), cmpMeta);
134 endAttachStyles();
135};
136const getScopeId = (cmp, mode) => 'sc-' + (cmp.$tagName$);
137/**
138 * Default style mode id
139 */
140/**
141 * Reusable empty obj/array
142 * Don't add values to these!!
143 */
144const EMPTY_OBJ = {};
145const isComplexType = (o) => {
146 // https://jsperf.com/typeof-fn-object/5
147 o = typeof o;
148 return o === 'object' || o === 'function';
149};
150/**
151 * Production h() function based on Preact by
152 * Jason Miller (@developit)
153 * Licensed under the MIT License
154 * https://github.com/developit/preact/blob/master/LICENSE
155 *
156 * Modified for Stencil's compiler and vdom
157 */
158// const stack: any[] = [];
159// export function h(nodeName: string | d.FunctionalComponent, vnodeData: d.PropsType, child?: d.ChildType): d.VNode;
160// export function h(nodeName: string | d.FunctionalComponent, vnodeData: d.PropsType, ...children: d.ChildType[]): d.VNode;
161const h = (nodeName, vnodeData, ...children) => {
162 let child = null;
163 let slotName = null;
164 let simple = false;
165 let lastSimple = false;
166 let vNodeChildren = [];
167 const walk = (c) => {
168 for (let i = 0; i < c.length; i++) {
169 child = c[i];
170 if (Array.isArray(child)) {
171 walk(child);
172 }
173 else if (child != null && typeof child !== 'boolean') {
174 if ((simple = typeof nodeName !== 'function' && !isComplexType(child))) {
175 child = String(child);
176 }
177 if (simple && lastSimple) {
178 // If the previous child was simple (string), we merge both
179 vNodeChildren[vNodeChildren.length - 1].$text$ += child;
180 }
181 else {
182 // Append a new vNode, if it's text, we create a text vNode
183 vNodeChildren.push(simple ? newVNode(null, child) : child);
184 }
185 lastSimple = simple;
186 }
187 }
188 };
189 walk(children);
190 if (vnodeData) {
191 if (vnodeData.name) {
192 slotName = vnodeData.name;
193 }
194 {
195 const classData = vnodeData.className || vnodeData.class;
196 if (classData) {
197 vnodeData.class =
198 typeof classData !== 'object'
199 ? classData
200 : Object.keys(classData)
201 .filter((k) => classData[k])
202 .join(' ');
203 }
204 }
205 }
206 if (typeof nodeName === 'function') {
207 // nodeName is a functional component
208 return nodeName(vnodeData === null ? {} : vnodeData, vNodeChildren, vdomFnUtils);
209 }
210 const vnode = newVNode(nodeName, null);
211 vnode.$attrs$ = vnodeData;
212 if (vNodeChildren.length > 0) {
213 vnode.$children$ = vNodeChildren;
214 }
215 {
216 vnode.$name$ = slotName;
217 }
218 return vnode;
219};
220const newVNode = (tag, text) => {
221 const vnode = {
222 $flags$: 0,
223 $tag$: tag,
224 $text$: text,
225 $elm$: null,
226 $children$: null,
227 };
228 {
229 vnode.$attrs$ = null;
230 }
231 {
232 vnode.$name$ = null;
233 }
234 return vnode;
235};
236const Host = {};
237const isHost = (node) => node && node.$tag$ === Host;
238const vdomFnUtils = {
239 forEach: (children, cb) => children.map(convertToPublic).forEach(cb),
240 map: (children, cb) => children.map(convertToPublic).map(cb).map(convertToPrivate),
241};
242const convertToPublic = (node) => ({
243 vattrs: node.$attrs$,
244 vchildren: node.$children$,
245 vkey: node.$key$,
246 vname: node.$name$,
247 vtag: node.$tag$,
248 vtext: node.$text$,
249});
250const convertToPrivate = (node) => {
251 if (typeof node.vtag === 'function') {
252 const vnodeData = Object.assign({}, node.vattrs);
253 if (node.vkey) {
254 vnodeData.key = node.vkey;
255 }
256 if (node.vname) {
257 vnodeData.name = node.vname;
258 }
259 return h(node.vtag, vnodeData, ...(node.vchildren || []));
260 }
261 const vnode = newVNode(node.vtag, node.vtext);
262 vnode.$attrs$ = node.vattrs;
263 vnode.$children$ = node.vchildren;
264 vnode.$key$ = node.vkey;
265 vnode.$name$ = node.vname;
266 return vnode;
267};
268/**
269 * Production setAccessor() function based on Preact by
270 * Jason Miller (@developit)
271 * Licensed under the MIT License
272 * https://github.com/developit/preact/blob/master/LICENSE
273 *
274 * Modified for Stencil's compiler and vdom
275 */
276const setAccessor = (elm, memberName, oldValue, newValue, isSvg, flags) => {
277 if (oldValue !== newValue) {
278 let isProp = isMemberInElement(elm, memberName);
279 let ln = memberName.toLowerCase();
280 if (memberName === 'class') {
281 const classList = elm.classList;
282 const oldClasses = parseClassList(oldValue);
283 const newClasses = parseClassList(newValue);
284 classList.remove(...oldClasses.filter((c) => c && !newClasses.includes(c)));
285 classList.add(...newClasses.filter((c) => c && !oldClasses.includes(c)));
286 }
287 else if ((!isProp ) &&
288 memberName[0] === 'o' &&
289 memberName[1] === 'n') {
290 // Event Handlers
291 // so if the member name starts with "on" and the 3rd characters is
292 // a capital letter, and it's not already a member on the element,
293 // then we're assuming it's an event listener
294 if (memberName[2] === '-') {
295 // on- prefixed events
296 // allows to be explicit about the dom event to listen without any magic
297 // under the hood:
298 // <my-cmp on-click> // listens for "click"
299 // <my-cmp on-Click> // listens for "Click"
300 // <my-cmp on-ionChange> // listens for "ionChange"
301 // <my-cmp on-EVENTS> // listens for "EVENTS"
302 memberName = memberName.slice(3);
303 }
304 else if (isMemberInElement(win, ln)) {
305 // standard event
306 // the JSX attribute could have been "onMouseOver" and the
307 // member name "onmouseover" is on the window's prototype
308 // so let's add the listener "mouseover", which is all lowercased
309 memberName = ln.slice(2);
310 }
311 else {
312 // custom event
313 // the JSX attribute could have been "onMyCustomEvent"
314 // so let's trim off the "on" prefix and lowercase the first character
315 // and add the listener "myCustomEvent"
316 // except for the first character, we keep the event name case
317 memberName = ln[2] + memberName.slice(3);
318 }
319 if (oldValue) {
320 plt.rel(elm, memberName, oldValue, false);
321 }
322 if (newValue) {
323 plt.ael(elm, memberName, newValue, false);
324 }
325 }
326 else {
327 // Set property if it exists and it's not a SVG
328 const isComplex = isComplexType(newValue);
329 if ((isProp || (isComplex && newValue !== null)) && !isSvg) {
330 try {
331 if (!elm.tagName.includes('-')) {
332 let n = newValue == null ? '' : newValue;
333 // Workaround for Safari, moving the <input> caret when re-assigning the same valued
334 if (memberName === 'list') {
335 isProp = false;
336 }
337 else if (oldValue == null || elm[memberName] != n) {
338 elm[memberName] = n;
339 }
340 }
341 else {
342 elm[memberName] = newValue;
343 }
344 }
345 catch (e) { }
346 }
347 if (newValue == null || newValue === false) {
348 if (newValue !== false || elm.getAttribute(memberName) === '') {
349 {
350 elm.removeAttribute(memberName);
351 }
352 }
353 }
354 else if ((!isProp || flags & 4 /* isHost */ || isSvg) && !isComplex) {
355 newValue = newValue === true ? '' : newValue;
356 {
357 elm.setAttribute(memberName, newValue);
358 }
359 }
360 }
361 }
362};
363const parseClassListRegex = /\s/;
364const parseClassList = (value) => (!value ? [] : value.split(parseClassListRegex));
365const updateElement = (oldVnode, newVnode, isSvgMode, memberName) => {
366 // if the element passed in is a shadow root, which is a document fragment
367 // then we want to be adding attrs/props to the shadow root's "host" element
368 // if it's not a shadow root, then we add attrs/props to the same element
369 const elm = newVnode.$elm$.nodeType === 11 /* DocumentFragment */ && newVnode.$elm$.host
370 ? newVnode.$elm$.host
371 : newVnode.$elm$;
372 const oldVnodeAttrs = (oldVnode && oldVnode.$attrs$) || EMPTY_OBJ;
373 const newVnodeAttrs = newVnode.$attrs$ || EMPTY_OBJ;
374 {
375 // remove attributes no longer present on the vnode by setting them to undefined
376 for (memberName in oldVnodeAttrs) {
377 if (!(memberName in newVnodeAttrs)) {
378 setAccessor(elm, memberName, oldVnodeAttrs[memberName], undefined, isSvgMode, newVnode.$flags$);
379 }
380 }
381 }
382 // add new & update changed attributes
383 for (memberName in newVnodeAttrs) {
384 setAccessor(elm, memberName, oldVnodeAttrs[memberName], newVnodeAttrs[memberName], isSvgMode, newVnode.$flags$);
385 }
386};
387const createElm = (oldParentVNode, newParentVNode, childIndex, parentElm) => {
388 // tslint:disable-next-line: prefer-const
389 let newVNode = newParentVNode.$children$[childIndex];
390 let i = 0;
391 let elm;
392 let childNode;
393 let oldVNode;
394 if (!useNativeShadowDom) {
395 // remember for later we need to check to relocate nodes
396 checkSlotRelocate = true;
397 if (newVNode.$tag$ === 'slot') {
398 newVNode.$flags$ |= newVNode.$children$
399 ? // slot element has fallback content
400 2 /* isSlotFallback */
401 : // slot element does not have fallback content
402 1 /* isSlotReference */;
403 }
404 }
405 if (newVNode.$text$ !== null) {
406 // create text node
407 elm = newVNode.$elm$ = doc.createTextNode(newVNode.$text$);
408 }
409 else if (newVNode.$flags$ & 1 /* isSlotReference */) {
410 // create a slot reference node
411 elm = newVNode.$elm$ =
412 doc.createTextNode('');
413 }
414 else {
415 // create element
416 elm = newVNode.$elm$ = (doc.createElement(newVNode.$flags$ & 2 /* isSlotFallback */
417 ? 'slot-fb'
418 : newVNode.$tag$));
419 // add css classes, attrs, props, listeners, etc.
420 {
421 updateElement(null, newVNode, isSvgMode);
422 }
423 if (newVNode.$children$) {
424 for (i = 0; i < newVNode.$children$.length; ++i) {
425 // create the node
426 childNode = createElm(oldParentVNode, newVNode, i);
427 // return node could have been null
428 if (childNode) {
429 // append our new node
430 elm.appendChild(childNode);
431 }
432 }
433 }
434 }
435 {
436 elm['s-hn'] = hostTagName;
437 if (newVNode.$flags$ & (2 /* isSlotFallback */ | 1 /* isSlotReference */)) {
438 // remember the content reference comment
439 elm['s-sr'] = true;
440 // remember the content reference comment
441 elm['s-cr'] = contentRef;
442 // remember the slot name, or empty string for default slot
443 elm['s-sn'] = newVNode.$name$ || '';
444 // check if we've got an old vnode for this slot
445 oldVNode = oldParentVNode && oldParentVNode.$children$ && oldParentVNode.$children$[childIndex];
446 if (oldVNode && oldVNode.$tag$ === newVNode.$tag$ && oldParentVNode.$elm$) {
447 // we've got an old slot vnode and the wrapper is being replaced
448 // so let's move the old slot content back to it's original location
449 putBackInOriginalLocation(oldParentVNode.$elm$, false);
450 }
451 }
452 }
453 return elm;
454};
455const putBackInOriginalLocation = (parentElm, recursive) => {
456 plt.$flags$ |= 1 /* isTmpDisconnected */;
457 const oldSlotChildNodes = parentElm.childNodes;
458 for (let i = oldSlotChildNodes.length - 1; i >= 0; i--) {
459 const childNode = oldSlotChildNodes[i];
460 if (childNode['s-hn'] !== hostTagName && childNode['s-ol']) {
461 // // this child node in the old element is from another component
462 // // remove this node from the old slot's parent
463 // childNode.remove();
464 // and relocate it back to it's original location
465 parentReferenceNode(childNode).insertBefore(childNode, referenceNode(childNode));
466 // remove the old original location comment entirely
467 // later on the patch function will know what to do
468 // and move this to the correct spot in need be
469 childNode['s-ol'].remove();
470 childNode['s-ol'] = undefined;
471 checkSlotRelocate = true;
472 }
473 if (recursive) {
474 putBackInOriginalLocation(childNode, recursive);
475 }
476 }
477 plt.$flags$ &= ~1 /* isTmpDisconnected */;
478};
479const addVnodes = (parentElm, before, parentVNode, vnodes, startIdx, endIdx) => {
480 let containerElm = ((parentElm['s-cr'] && parentElm['s-cr'].parentNode) || parentElm);
481 let childNode;
482 for (; startIdx <= endIdx; ++startIdx) {
483 if (vnodes[startIdx]) {
484 childNode = createElm(null, parentVNode, startIdx);
485 if (childNode) {
486 vnodes[startIdx].$elm$ = childNode;
487 containerElm.insertBefore(childNode, referenceNode(before) );
488 }
489 }
490 }
491};
492const removeVnodes = (vnodes, startIdx, endIdx, vnode, elm) => {
493 for (; startIdx <= endIdx; ++startIdx) {
494 if ((vnode = vnodes[startIdx])) {
495 elm = vnode.$elm$;
496 {
497 // we're removing this element
498 // so it's possible we need to show slot fallback content now
499 checkSlotFallbackVisibility = true;
500 if (elm['s-ol']) {
501 // remove the original location comment
502 elm['s-ol'].remove();
503 }
504 else {
505 // it's possible that child nodes of the node
506 // that's being removed are slot nodes
507 putBackInOriginalLocation(elm, true);
508 }
509 }
510 // remove the vnode's element from the dom
511 elm.remove();
512 }
513 }
514};
515const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
516 let oldStartIdx = 0;
517 let newStartIdx = 0;
518 let oldEndIdx = oldCh.length - 1;
519 let oldStartVnode = oldCh[0];
520 let oldEndVnode = oldCh[oldEndIdx];
521 let newEndIdx = newCh.length - 1;
522 let newStartVnode = newCh[0];
523 let newEndVnode = newCh[newEndIdx];
524 let node;
525 while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
526 if (oldStartVnode == null) {
527 // Vnode might have been moved left
528 oldStartVnode = oldCh[++oldStartIdx];
529 }
530 else if (oldEndVnode == null) {
531 oldEndVnode = oldCh[--oldEndIdx];
532 }
533 else if (newStartVnode == null) {
534 newStartVnode = newCh[++newStartIdx];
535 }
536 else if (newEndVnode == null) {
537 newEndVnode = newCh[--newEndIdx];
538 }
539 else if (isSameVnode(oldStartVnode, newStartVnode)) {
540 patch(oldStartVnode, newStartVnode);
541 oldStartVnode = oldCh[++oldStartIdx];
542 newStartVnode = newCh[++newStartIdx];
543 }
544 else if (isSameVnode(oldEndVnode, newEndVnode)) {
545 patch(oldEndVnode, newEndVnode);
546 oldEndVnode = oldCh[--oldEndIdx];
547 newEndVnode = newCh[--newEndIdx];
548 }
549 else if (isSameVnode(oldStartVnode, newEndVnode)) {
550 // Vnode moved right
551 if ((oldStartVnode.$tag$ === 'slot' || newEndVnode.$tag$ === 'slot')) {
552 putBackInOriginalLocation(oldStartVnode.$elm$.parentNode, false);
553 }
554 patch(oldStartVnode, newEndVnode);
555 parentElm.insertBefore(oldStartVnode.$elm$, oldEndVnode.$elm$.nextSibling);
556 oldStartVnode = oldCh[++oldStartIdx];
557 newEndVnode = newCh[--newEndIdx];
558 }
559 else if (isSameVnode(oldEndVnode, newStartVnode)) {
560 // Vnode moved left
561 if ((oldStartVnode.$tag$ === 'slot' || newEndVnode.$tag$ === 'slot')) {
562 putBackInOriginalLocation(oldEndVnode.$elm$.parentNode, false);
563 }
564 patch(oldEndVnode, newStartVnode);
565 parentElm.insertBefore(oldEndVnode.$elm$, oldStartVnode.$elm$);
566 oldEndVnode = oldCh[--oldEndIdx];
567 newStartVnode = newCh[++newStartIdx];
568 }
569 else {
570 {
571 // new element
572 node = createElm(oldCh && oldCh[newStartIdx], newVNode, newStartIdx);
573 newStartVnode = newCh[++newStartIdx];
574 }
575 if (node) {
576 {
577 parentReferenceNode(oldStartVnode.$elm$).insertBefore(node, referenceNode(oldStartVnode.$elm$));
578 }
579 }
580 }
581 }
582 if (oldStartIdx > oldEndIdx) {
583 addVnodes(parentElm, newCh[newEndIdx + 1] == null ? null : newCh[newEndIdx + 1].$elm$, newVNode, newCh, newStartIdx, newEndIdx);
584 }
585 else if (newStartIdx > newEndIdx) {
586 removeVnodes(oldCh, oldStartIdx, oldEndIdx);
587 }
588};
589const isSameVnode = (vnode1, vnode2) => {
590 // compare if two vnode to see if they're "technically" the same
591 // need to have the same element tag, and same key to be the same
592 if (vnode1.$tag$ === vnode2.$tag$) {
593 if (vnode1.$tag$ === 'slot') {
594 return vnode1.$name$ === vnode2.$name$;
595 }
596 return true;
597 }
598 return false;
599};
600const referenceNode = (node) => {
601 // this node was relocated to a new location in the dom
602 // because of some other component's slot
603 // but we still have an html comment in place of where
604 // it's original location was according to it's original vdom
605 return (node && node['s-ol']) || node;
606};
607const parentReferenceNode = (node) => (node['s-ol'] ? node['s-ol'] : node).parentNode;
608const patch = (oldVNode, newVNode) => {
609 const elm = (newVNode.$elm$ = oldVNode.$elm$);
610 const oldChildren = oldVNode.$children$;
611 const newChildren = newVNode.$children$;
612 const tag = newVNode.$tag$;
613 const text = newVNode.$text$;
614 let defaultHolder;
615 if (text === null) {
616 // element node
617 {
618 if (tag === 'slot')
619 ;
620 else {
621 // either this is the first render of an element OR it's an update
622 // AND we already know it's possible it could have changed
623 // this updates the element's css classes, attrs, props, listeners, etc.
624 updateElement(oldVNode, newVNode, isSvgMode);
625 }
626 }
627 if (oldChildren !== null && newChildren !== null) {
628 // looks like there's child vnodes for both the old and new vnodes
629 updateChildren(elm, oldChildren, newVNode, newChildren);
630 }
631 else if (newChildren !== null) {
632 // no old child vnodes, but there are new child vnodes to add
633 if (oldVNode.$text$ !== null) {
634 // the old vnode was text, so be sure to clear it out
635 elm.textContent = '';
636 }
637 // add the new vnode children
638 addVnodes(elm, null, newVNode, newChildren, 0, newChildren.length - 1);
639 }
640 else if (oldChildren !== null) {
641 // no new child vnodes, but there are old child vnodes to remove
642 removeVnodes(oldChildren, 0, oldChildren.length - 1);
643 }
644 }
645 else if ((defaultHolder = elm['s-cr'])) {
646 // this element has slotted content
647 defaultHolder.parentNode.textContent = text;
648 }
649 else if (oldVNode.$text$ !== text) {
650 // update the text content for the text only vnode
651 // and also only if the text is different than before
652 elm.data = text;
653 }
654};
655const updateFallbackSlotVisibility = (elm) => {
656 // tslint:disable-next-line: prefer-const
657 let childNodes = elm.childNodes;
658 let childNode;
659 let i;
660 let ilen;
661 let j;
662 let slotNameAttr;
663 let nodeType;
664 for (i = 0, ilen = childNodes.length; i < ilen; i++) {
665 childNode = childNodes[i];
666 if (childNode.nodeType === 1 /* ElementNode */) {
667 if (childNode['s-sr']) {
668 // this is a slot fallback node
669 // get the slot name for this slot reference node
670 slotNameAttr = childNode['s-sn'];
671 // by default always show a fallback slot node
672 // then hide it if there are other slots in the light dom
673 childNode.hidden = false;
674 for (j = 0; j < ilen; j++) {
675 nodeType = childNodes[j].nodeType;
676 if (childNodes[j]['s-hn'] !== childNode['s-hn'] || slotNameAttr !== '') {
677 // this sibling node is from a different component OR is a named fallback slot node
678 if (nodeType === 1 /* ElementNode */ && slotNameAttr === childNodes[j].getAttribute('slot')) {
679 childNode.hidden = true;
680 break;
681 }
682 }
683 else {
684 // this is a default fallback slot node
685 // any element or text node (with content)
686 // should hide the default fallback slot node
687 if (nodeType === 1 /* ElementNode */ ||
688 (nodeType === 3 /* TextNode */ && childNodes[j].textContent.trim() !== '')) {
689 childNode.hidden = true;
690 break;
691 }
692 }
693 }
694 }
695 // keep drilling down
696 updateFallbackSlotVisibility(childNode);
697 }
698 }
699};
700const relocateNodes = [];
701const relocateSlotContent = (elm) => {
702 // tslint:disable-next-line: prefer-const
703 let childNode;
704 let node;
705 let hostContentNodes;
706 let slotNameAttr;
707 let relocateNodeData;
708 let j;
709 let i = 0;
710 let childNodes = elm.childNodes;
711 let ilen = childNodes.length;
712 for (; i < ilen; i++) {
713 childNode = childNodes[i];
714 if (childNode['s-sr'] && (node = childNode['s-cr']) && node.parentNode) {
715 // first got the content reference comment node
716 // then we got it's parent, which is where all the host content is in now
717 hostContentNodes = node.parentNode.childNodes;
718 slotNameAttr = childNode['s-sn'];
719 for (j = hostContentNodes.length - 1; j >= 0; j--) {
720 node = hostContentNodes[j];
721 if (!node['s-cn'] && !node['s-nr'] && node['s-hn'] !== childNode['s-hn']) {
722 // let's do some relocating to its new home
723 // but never relocate a content reference node
724 // that is suppose to always represent the original content location
725 if (isNodeLocatedInSlot(node, slotNameAttr)) {
726 // it's possible we've already decided to relocate this node
727 relocateNodeData = relocateNodes.find((r) => r.$nodeToRelocate$ === node);
728 // made some changes to slots
729 // let's make sure we also double check
730 // fallbacks are correctly hidden or shown
731 checkSlotFallbackVisibility = true;
732 node['s-sn'] = node['s-sn'] || slotNameAttr;
733 if (relocateNodeData) {
734 // previously we never found a slot home for this node
735 // but turns out we did, so let's remember it now
736 relocateNodeData.$slotRefNode$ = childNode;
737 }
738 else {
739 // add to our list of nodes to relocate
740 relocateNodes.push({
741 $slotRefNode$: childNode,
742 $nodeToRelocate$: node,
743 });
744 }
745 if (node['s-sr']) {
746 relocateNodes.map((relocateNode) => {
747 if (isNodeLocatedInSlot(relocateNode.$nodeToRelocate$, node['s-sn'])) {
748 relocateNodeData = relocateNodes.find((r) => r.$nodeToRelocate$ === node);
749 if (relocateNodeData && !relocateNode.$slotRefNode$) {
750 relocateNode.$slotRefNode$ = relocateNodeData.$slotRefNode$;
751 }
752 }
753 });
754 }
755 }
756 else if (!relocateNodes.some((r) => r.$nodeToRelocate$ === node)) {
757 // so far this element does not have a slot home, not setting slotRefNode on purpose
758 // if we never find a home for this element then we'll need to hide it
759 relocateNodes.push({
760 $nodeToRelocate$: node,
761 });
762 }
763 }
764 }
765 }
766 if (childNode.nodeType === 1 /* ElementNode */) {
767 relocateSlotContent(childNode);
768 }
769 }
770};
771const isNodeLocatedInSlot = (nodeToRelocate, slotNameAttr) => {
772 if (nodeToRelocate.nodeType === 1 /* ElementNode */) {
773 if (nodeToRelocate.getAttribute('slot') === null && slotNameAttr === '') {
774 return true;
775 }
776 if (nodeToRelocate.getAttribute('slot') === slotNameAttr) {
777 return true;
778 }
779 return false;
780 }
781 if (nodeToRelocate['s-sn'] === slotNameAttr) {
782 return true;
783 }
784 return slotNameAttr === '';
785};
786const renderVdom = (hostRef, renderFnResults) => {
787 const hostElm = hostRef.$hostElement$;
788 const cmpMeta = hostRef.$cmpMeta$;
789 const oldVNode = hostRef.$vnode$ || newVNode(null, null);
790 const rootVnode = isHost(renderFnResults) ? renderFnResults : h(null, null, renderFnResults);
791 hostTagName = hostElm.tagName;
792 if (cmpMeta.$attrsToReflect$) {
793 rootVnode.$attrs$ = rootVnode.$attrs$ || {};
794 cmpMeta.$attrsToReflect$.map(([propName, attribute]) => (rootVnode.$attrs$[attribute] = hostElm[propName]));
795 }
796 rootVnode.$tag$ = null;
797 rootVnode.$flags$ |= 4 /* isHost */;
798 hostRef.$vnode$ = rootVnode;
799 rootVnode.$elm$ = oldVNode.$elm$ = (hostElm);
800 {
801 contentRef = hostElm['s-cr'];
802 useNativeShadowDom = (cmpMeta.$flags$ & 1 /* shadowDomEncapsulation */) !== 0;
803 // always reset
804 checkSlotFallbackVisibility = false;
805 }
806 // synchronous patch
807 patch(oldVNode, rootVnode);
808 {
809 // while we're moving nodes around existing nodes, temporarily disable
810 // the disconnectCallback from working
811 plt.$flags$ |= 1 /* isTmpDisconnected */;
812 if (checkSlotRelocate) {
813 relocateSlotContent(rootVnode.$elm$);
814 let relocateData;
815 let nodeToRelocate;
816 let orgLocationNode;
817 let parentNodeRef;
818 let insertBeforeNode;
819 let refNode;
820 let i = 0;
821 for (; i < relocateNodes.length; i++) {
822 relocateData = relocateNodes[i];
823 nodeToRelocate = relocateData.$nodeToRelocate$;
824 if (!nodeToRelocate['s-ol']) {
825 // add a reference node marking this node's original location
826 // keep a reference to this node for later lookups
827 orgLocationNode =
828 doc.createTextNode('');
829 orgLocationNode['s-nr'] = nodeToRelocate;
830 nodeToRelocate.parentNode.insertBefore((nodeToRelocate['s-ol'] = orgLocationNode), nodeToRelocate);
831 }
832 }
833 for (i = 0; i < relocateNodes.length; i++) {
834 relocateData = relocateNodes[i];
835 nodeToRelocate = relocateData.$nodeToRelocate$;
836 if (relocateData.$slotRefNode$) {
837 // by default we're just going to insert it directly
838 // after the slot reference node
839 parentNodeRef = relocateData.$slotRefNode$.parentNode;
840 insertBeforeNode = relocateData.$slotRefNode$.nextSibling;
841 orgLocationNode = nodeToRelocate['s-ol'];
842 while ((orgLocationNode = orgLocationNode.previousSibling)) {
843 refNode = orgLocationNode['s-nr'];
844 if (refNode && refNode['s-sn'] === nodeToRelocate['s-sn'] && parentNodeRef === refNode.parentNode) {
845 refNode = refNode.nextSibling;
846 if (!refNode || !refNode['s-nr']) {
847 insertBeforeNode = refNode;
848 break;
849 }
850 }
851 }
852 if ((!insertBeforeNode && parentNodeRef !== nodeToRelocate.parentNode) ||
853 nodeToRelocate.nextSibling !== insertBeforeNode) {
854 // we've checked that it's worth while to relocate
855 // since that the node to relocate
856 // has a different next sibling or parent relocated
857 if (nodeToRelocate !== insertBeforeNode) {
858 if (!nodeToRelocate['s-hn'] && nodeToRelocate['s-ol']) {
859 // probably a component in the index.html that doesn't have it's hostname set
860 nodeToRelocate['s-hn'] = nodeToRelocate['s-ol'].parentNode.nodeName;
861 }
862 // add it back to the dom but in its new home
863 parentNodeRef.insertBefore(nodeToRelocate, insertBeforeNode);
864 }
865 }
866 }
867 else {
868 // this node doesn't have a slot home to go to, so let's hide it
869 if (nodeToRelocate.nodeType === 1 /* ElementNode */) {
870 nodeToRelocate.hidden = true;
871 }
872 }
873 }
874 }
875 if (checkSlotFallbackVisibility) {
876 updateFallbackSlotVisibility(rootVnode.$elm$);
877 }
878 // done moving nodes around
879 // allow the disconnect callback to work again
880 plt.$flags$ &= ~1 /* isTmpDisconnected */;
881 // always reset
882 relocateNodes.length = 0;
883 }
884};
885/**
886 * Helper function to create & dispatch a custom Event on a provided target
887 * @param elm the target of the Event
888 * @param name the name to give the custom Event
889 * @param opts options for configuring a custom Event
890 * @returns the custom Event
891 */
892const emitEvent = (elm, name, opts) => {
893 const ev = plt.ce(name, opts);
894 elm.dispatchEvent(ev);
895 return ev;
896};
897const attachToAncestor = (hostRef, ancestorComponent) => {
898 if (ancestorComponent && !hostRef.$onRenderResolve$ && ancestorComponent['s-p']) {
899 ancestorComponent['s-p'].push(new Promise((r) => (hostRef.$onRenderResolve$ = r)));
900 }
901};
902const scheduleUpdate = (hostRef, isInitialLoad) => {
903 {
904 hostRef.$flags$ |= 16 /* isQueuedForUpdate */;
905 }
906 if (hostRef.$flags$ & 4 /* isWaitingForChildren */) {
907 hostRef.$flags$ |= 512 /* needsRerender */;
908 return;
909 }
910 attachToAncestor(hostRef, hostRef.$ancestorComponent$);
911 // there is no ancestor component or the ancestor component
912 // has already fired off its lifecycle update then
913 // fire off the initial update
914 const dispatch = () => dispatchHooks(hostRef, isInitialLoad);
915 return writeTask(dispatch) ;
916};
917const dispatchHooks = (hostRef, isInitialLoad) => {
918 const endSchedule = createTime('scheduleUpdate', hostRef.$cmpMeta$.$tagName$);
919 const instance = hostRef.$lazyInstance$ ;
920 let promise;
921 endSchedule();
922 return then(promise, () => updateComponent(hostRef, instance, isInitialLoad));
923};
924const updateComponent = async (hostRef, instance, isInitialLoad) => {
925 // updateComponent
926 const elm = hostRef.$hostElement$;
927 const endUpdate = createTime('update', hostRef.$cmpMeta$.$tagName$);
928 const rc = elm['s-rc'];
929 if (isInitialLoad) {
930 // DOM WRITE!
931 attachStyles(hostRef);
932 }
933 const endRender = createTime('render', hostRef.$cmpMeta$.$tagName$);
934 {
935 callRender(hostRef, instance);
936 }
937 if (rc) {
938 // ok, so turns out there are some child host elements
939 // waiting on this parent element to load
940 // let's fire off all update callbacks waiting
941 rc.map((cb) => cb());
942 elm['s-rc'] = undefined;
943 }
944 endRender();
945 endUpdate();
946 {
947 const childrenPromises = elm['s-p'];
948 const postUpdate = () => postUpdateComponent(hostRef);
949 if (childrenPromises.length === 0) {
950 postUpdate();
951 }
952 else {
953 Promise.all(childrenPromises).then(postUpdate);
954 hostRef.$flags$ |= 4 /* isWaitingForChildren */;
955 childrenPromises.length = 0;
956 }
957 }
958};
959const callRender = (hostRef, instance, elm) => {
960 try {
961 instance = instance.render() ;
962 {
963 hostRef.$flags$ &= ~16 /* isQueuedForUpdate */;
964 }
965 {
966 hostRef.$flags$ |= 2 /* hasRendered */;
967 }
968 {
969 {
970 // looks like we've got child nodes to render into this host element
971 // or we need to update the css class/attrs on the host element
972 // DOM WRITE!
973 {
974 renderVdom(hostRef, instance);
975 }
976 }
977 }
978 }
979 catch (e) {
980 consoleError(e, hostRef.$hostElement$);
981 }
982 return null;
983};
984const postUpdateComponent = (hostRef) => {
985 const tagName = hostRef.$cmpMeta$.$tagName$;
986 const elm = hostRef.$hostElement$;
987 const endPostUpdate = createTime('postUpdate', tagName);
988 const ancestorComponent = hostRef.$ancestorComponent$;
989 if (!(hostRef.$flags$ & 64 /* hasLoadedComponent */)) {
990 hostRef.$flags$ |= 64 /* hasLoadedComponent */;
991 {
992 // DOM WRITE!
993 addHydratedFlag(elm);
994 }
995 endPostUpdate();
996 {
997 hostRef.$onReadyResolve$(elm);
998 if (!ancestorComponent) {
999 appDidLoad();
1000 }
1001 }
1002 }
1003 else {
1004 endPostUpdate();
1005 }
1006 // load events fire from bottom to top
1007 // the deepest elements load first then bubbles up
1008 {
1009 if (hostRef.$onRenderResolve$) {
1010 hostRef.$onRenderResolve$();
1011 hostRef.$onRenderResolve$ = undefined;
1012 }
1013 if (hostRef.$flags$ & 512 /* needsRerender */) {
1014 nextTick(() => scheduleUpdate(hostRef, false));
1015 }
1016 hostRef.$flags$ &= ~(4 /* isWaitingForChildren */ | 512 /* needsRerender */);
1017 }
1018 // ( •_•)
1019 // ( •_•)>⌐■-■
1020 // (⌐■_■)
1021};
1022const appDidLoad = (who) => {
1023 // on appload
1024 // we have finish the first big initial render
1025 {
1026 addHydratedFlag(doc.documentElement);
1027 }
1028 nextTick(() => emitEvent(win, 'appload', { detail: { namespace: NAMESPACE } }));
1029};
1030const then = (promise, thenFn) => {
1031 return promise && promise.then ? promise.then(thenFn) : thenFn();
1032};
1033const addHydratedFlag = (elm) => elm.classList.add('hydrated')
1034 ;
1035const initializeClientHydrate = (hostElm, tagName, hostId, hostRef) => {
1036 const endHydrate = createTime('hydrateClient', tagName);
1037 const shadowRoot = hostElm.shadowRoot;
1038 const childRenderNodes = [];
1039 const slotNodes = [];
1040 const shadowRootNodes = null;
1041 const vnode = (hostRef.$vnode$ = newVNode(tagName, null));
1042 if (!plt.$orgLocNodes$) {
1043 initializeDocumentHydrate(doc.body, (plt.$orgLocNodes$ = new Map()));
1044 }
1045 hostElm[HYDRATE_ID] = hostId;
1046 hostElm.removeAttribute(HYDRATE_ID);
1047 clientHydrate(vnode, childRenderNodes, slotNodes, shadowRootNodes, hostElm, hostElm, hostId);
1048 childRenderNodes.map((c) => {
1049 const orgLocationId = c.$hostId$ + '.' + c.$nodeId$;
1050 const orgLocationNode = plt.$orgLocNodes$.get(orgLocationId);
1051 const node = c.$elm$;
1052 if (orgLocationNode && supportsShadow && orgLocationNode['s-en'] === '') {
1053 orgLocationNode.parentNode.insertBefore(node, orgLocationNode.nextSibling);
1054 }
1055 if (!shadowRoot) {
1056 node['s-hn'] = tagName;
1057 if (orgLocationNode) {
1058 node['s-ol'] = orgLocationNode;
1059 node['s-ol']['s-nr'] = node;
1060 }
1061 }
1062 plt.$orgLocNodes$.delete(orgLocationId);
1063 });
1064 endHydrate();
1065};
1066const clientHydrate = (parentVNode, childRenderNodes, slotNodes, shadowRootNodes, hostElm, node, hostId) => {
1067 let childNodeType;
1068 let childIdSplt;
1069 let childVNode;
1070 let i;
1071 if (node.nodeType === 1 /* ElementNode */) {
1072 childNodeType = node.getAttribute(HYDRATE_CHILD_ID);
1073 if (childNodeType) {
1074 // got the node data from the element's attribute
1075 // `${hostId}.${nodeId}.${depth}.${index}`
1076 childIdSplt = childNodeType.split('.');
1077 if (childIdSplt[0] === hostId || childIdSplt[0] === '0') {
1078 childVNode = {
1079 $flags$: 0,
1080 $hostId$: childIdSplt[0],
1081 $nodeId$: childIdSplt[1],
1082 $depth$: childIdSplt[2],
1083 $index$: childIdSplt[3],
1084 $tag$: node.tagName.toLowerCase(),
1085 $elm$: node,
1086 $attrs$: null,
1087 $children$: null,
1088 $key$: null,
1089 $name$: null,
1090 $text$: null,
1091 };
1092 childRenderNodes.push(childVNode);
1093 node.removeAttribute(HYDRATE_CHILD_ID);
1094 // this is a new child vnode
1095 // so ensure its parent vnode has the vchildren array
1096 if (!parentVNode.$children$) {
1097 parentVNode.$children$ = [];
1098 }
1099 // add our child vnode to a specific index of the vnode's children
1100 parentVNode.$children$[childVNode.$index$] = childVNode;
1101 // this is now the new parent vnode for all the next child checks
1102 parentVNode = childVNode;
1103 if (shadowRootNodes && childVNode.$depth$ === '0') {
1104 shadowRootNodes[childVNode.$index$] = childVNode.$elm$;
1105 }
1106 }
1107 }
1108 // recursively drill down, end to start so we can remove nodes
1109 for (i = node.childNodes.length - 1; i >= 0; i--) {
1110 clientHydrate(parentVNode, childRenderNodes, slotNodes, shadowRootNodes, hostElm, node.childNodes[i], hostId);
1111 }
1112 if (node.shadowRoot) {
1113 // keep drilling down through the shadow root nodes
1114 for (i = node.shadowRoot.childNodes.length - 1; i >= 0; i--) {
1115 clientHydrate(parentVNode, childRenderNodes, slotNodes, shadowRootNodes, hostElm, node.shadowRoot.childNodes[i], hostId);
1116 }
1117 }
1118 }
1119 else if (node.nodeType === 8 /* CommentNode */) {
1120 // `${COMMENT_TYPE}.${hostId}.${nodeId}.${depth}.${index}`
1121 childIdSplt = node.nodeValue.split('.');
1122 if (childIdSplt[1] === hostId || childIdSplt[1] === '0') {
1123 // comment node for either the host id or a 0 host id
1124 childNodeType = childIdSplt[0];
1125 childVNode = {
1126 $flags$: 0,
1127 $hostId$: childIdSplt[1],
1128 $nodeId$: childIdSplt[2],
1129 $depth$: childIdSplt[3],
1130 $index$: childIdSplt[4],
1131 $elm$: node,
1132 $attrs$: null,
1133 $children$: null,
1134 $key$: null,
1135 $name$: null,
1136 $tag$: null,
1137 $text$: null,
1138 };
1139 if (childNodeType === TEXT_NODE_ID) {
1140 childVNode.$elm$ = node.nextSibling;
1141 if (childVNode.$elm$ && childVNode.$elm$.nodeType === 3 /* TextNode */) {
1142 childVNode.$text$ = childVNode.$elm$.textContent;
1143 childRenderNodes.push(childVNode);
1144 // remove the text comment since it's no longer needed
1145 node.remove();
1146 if (!parentVNode.$children$) {
1147 parentVNode.$children$ = [];
1148 }
1149 parentVNode.$children$[childVNode.$index$] = childVNode;
1150 if (shadowRootNodes && childVNode.$depth$ === '0') {
1151 shadowRootNodes[childVNode.$index$] = childVNode.$elm$;
1152 }
1153 }
1154 }
1155 else if (childVNode.$hostId$ === hostId) {
1156 // this comment node is specifcally for this host id
1157 if (childNodeType === SLOT_NODE_ID) {
1158 // `${SLOT_NODE_ID}.${hostId}.${nodeId}.${depth}.${index}.${slotName}`;
1159 childVNode.$tag$ = 'slot';
1160 if (childIdSplt[5]) {
1161 node['s-sn'] = childVNode.$name$ = childIdSplt[5];
1162 }
1163 else {
1164 node['s-sn'] = '';
1165 }
1166 node['s-sr'] = true;
1167 slotNodes.push(childVNode);
1168 if (!parentVNode.$children$) {
1169 parentVNode.$children$ = [];
1170 }
1171 parentVNode.$children$[childVNode.$index$] = childVNode;
1172 }
1173 else if (childNodeType === CONTENT_REF_ID) {
1174 // `${CONTENT_REF_ID}.${hostId}`;
1175 {
1176 hostElm['s-cr'] = node;
1177 node['s-cn'] = true;
1178 }
1179 }
1180 }
1181 }
1182 }
1183 else if (parentVNode && parentVNode.$tag$ === 'style') {
1184 const vnode = newVNode(null, node.textContent);
1185 vnode.$elm$ = node;
1186 vnode.$index$ = '0';
1187 parentVNode.$children$ = [vnode];
1188 }
1189};
1190const initializeDocumentHydrate = (node, orgLocNodes) => {
1191 if (node.nodeType === 1 /* ElementNode */) {
1192 let i = 0;
1193 for (; i < node.childNodes.length; i++) {
1194 initializeDocumentHydrate(node.childNodes[i], orgLocNodes);
1195 }
1196 if (node.shadowRoot) {
1197 for (i = 0; i < node.shadowRoot.childNodes.length; i++) {
1198 initializeDocumentHydrate(node.shadowRoot.childNodes[i], orgLocNodes);
1199 }
1200 }
1201 }
1202 else if (node.nodeType === 8 /* CommentNode */) {
1203 const childIdSplt = node.nodeValue.split('.');
1204 if (childIdSplt[0] === ORG_LOCATION_ID) {
1205 orgLocNodes.set(childIdSplt[1] + '.' + childIdSplt[2], node);
1206 node.nodeValue = '';
1207 // useful to know if the original location is
1208 // the root light-dom of a shadow dom component
1209 node['s-en'] = childIdSplt[3];
1210 }
1211 }
1212};
1213const parsePropertyValue = (propValue, propType) => {
1214 // ensure this value is of the correct prop type
1215 if (propValue != null && !isComplexType(propValue)) {
1216 if (propType & 4 /* Boolean */) {
1217 // per the HTML spec, any string value means it is a boolean true value
1218 // but we'll cheat here and say that the string "false" is the boolean false
1219 return propValue === 'false' ? false : propValue === '' || !!propValue;
1220 }
1221 if (propType & 2 /* Number */) {
1222 // force it to be a number
1223 return parseFloat(propValue);
1224 }
1225 if (propType & 1 /* String */) {
1226 // could have been passed as a number or boolean
1227 // but we still want it as a string
1228 return String(propValue);
1229 }
1230 // redundant return here for better minification
1231 return propValue;
1232 }
1233 // not sure exactly what type we want
1234 // so no need to change to a different type
1235 return propValue;
1236};
1237const getValue = (ref, propName) => getHostRef(ref).$instanceValues$.get(propName);
1238const setValue = (ref, propName, newVal, cmpMeta) => {
1239 // check our new property value against our internal value
1240 const hostRef = getHostRef(ref);
1241 const oldVal = hostRef.$instanceValues$.get(propName);
1242 const flags = hostRef.$flags$;
1243 const instance = hostRef.$lazyInstance$ ;
1244 newVal = parsePropertyValue(newVal, cmpMeta.$members$[propName][0]);
1245 if ((!(flags & 8 /* isConstructingInstance */) || oldVal === undefined) && newVal !== oldVal) {
1246 // gadzooks! the property's value has changed!!
1247 // set our new value!
1248 hostRef.$instanceValues$.set(propName, newVal);
1249 if (instance) {
1250 if ((flags & (2 /* hasRendered */ | 16 /* isQueuedForUpdate */)) === 2 /* hasRendered */) {
1251 // looks like this value actually changed, so we've got work to do!
1252 // but only if we've already rendered, otherwise just chill out
1253 // queue that we need to do an update, but don't worry about queuing
1254 // up millions cuz this function ensures it only runs once
1255 scheduleUpdate(hostRef, false);
1256 }
1257 }
1258 }
1259};
1260const proxyComponent = (Cstr, cmpMeta, flags) => {
1261 if (cmpMeta.$members$) {
1262 // It's better to have a const than two Object.entries()
1263 const members = Object.entries(cmpMeta.$members$);
1264 const prototype = Cstr.prototype;
1265 members.map(([memberName, [memberFlags]]) => {
1266 if ((memberFlags & 31 /* Prop */ ||
1267 ((flags & 2 /* proxyState */) && memberFlags & 32 /* State */))) {
1268 // proxyComponent - prop
1269 Object.defineProperty(prototype, memberName, {
1270 get() {
1271 // proxyComponent, get value
1272 return getValue(this, memberName);
1273 },
1274 set(newValue) {
1275 // proxyComponent, set value
1276 setValue(this, memberName, newValue, cmpMeta);
1277 },
1278 configurable: true,
1279 enumerable: true,
1280 });
1281 }
1282 });
1283 if ((flags & 1 /* isElementConstructor */)) {
1284 const attrNameToPropName = new Map();
1285 prototype.attributeChangedCallback = function (attrName, _oldValue, newValue) {
1286 plt.jmp(() => {
1287 const propName = attrNameToPropName.get(attrName);
1288 // In a web component lifecycle the attributeChangedCallback runs prior to connectedCallback
1289 // in the case where an attribute was set inline.
1290 // ```html
1291 // <my-component some-attribute="some-value"></my-component>
1292 // ```
1293 //
1294 // There is an edge case where a developer sets the attribute inline on a custom element and then
1295 // programmatically changes it before it has been upgraded as shown below:
1296 //
1297 // ```html
1298 // <!-- this component has _not_ been upgraded yet -->
1299 // <my-component id="test" some-attribute="some-value"></my-component>
1300 // <script>
1301 // // grab non-upgraded component
1302 // el = document.querySelector("#test");
1303 // el.someAttribute = "another-value";
1304 // // upgrade component
1305 // customElements.define('my-component', MyComponent);
1306 // </script>
1307 // ```
1308 // In this case if we do not unshadow here and use the value of the shadowing property, attributeChangedCallback
1309 // will be called with `newValue = "some-value"` and will set the shadowed property (this.someAttribute = "another-value")
1310 // to the value that was set inline i.e. "some-value" from above example. When
1311 // the connectedCallback attempts to unshadow it will use "some-value" as the initial value rather than "another-value"
1312 //
1313 // The case where the attribute was NOT set inline but was not set programmatically shall be handled/unshadowed
1314 // by connectedCallback as this attributeChangedCallback will not fire.
1315 //
1316 // https://developers.google.com/web/fundamentals/web-components/best-practices#lazy-properties
1317 //
1318 // TODO(STENCIL-16) we should think about whether or not we actually want to be reflecting the attributes to
1319 // properties here given that this goes against best practices outlined here
1320 // https://developers.google.com/web/fundamentals/web-components/best-practices#avoid-reentrancy
1321 if (this.hasOwnProperty(propName)) {
1322 newValue = this[propName];
1323 delete this[propName];
1324 }
1325 else if (prototype.hasOwnProperty(propName) &&
1326 typeof this[propName] === 'number' &&
1327 this[propName] == newValue) {
1328 // if the propName exists on the prototype of `Cstr`, this update may be a result of Stencil using native
1329 // APIs to reflect props as attributes. Calls to `setAttribute(someElement, propName)` will result in
1330 // `propName` to be converted to a `DOMString`, which may not be what we want for other primitive props.
1331 return;
1332 }
1333 this[propName] = newValue === null && typeof this[propName] === 'boolean' ? false : newValue;
1334 });
1335 };
1336 // create an array of attributes to observe
1337 // and also create a map of html attribute name to js property name
1338 Cstr.observedAttributes = members
1339 .filter(([_, m]) => m[0] & 15 /* HasAttribute */) // filter to only keep props that should match attributes
1340 .map(([propName, m]) => {
1341 const attrName = m[1] || propName;
1342 attrNameToPropName.set(attrName, propName);
1343 if (m[0] & 512 /* ReflectAttr */) {
1344 cmpMeta.$attrsToReflect$.push([propName, attrName]);
1345 }
1346 return attrName;
1347 });
1348 }
1349 }
1350 return Cstr;
1351};
1352const initializeComponent = async (elm, hostRef, cmpMeta, hmrVersionId, Cstr) => {
1353 // initializeComponent
1354 if ((hostRef.$flags$ & 32 /* hasInitializedComponent */) === 0) {
1355 {
1356 // we haven't initialized this element yet
1357 hostRef.$flags$ |= 32 /* hasInitializedComponent */;
1358 // lazy loaded components
1359 // request the component's implementation to be
1360 // wired up with the host element
1361 Cstr = loadModule(cmpMeta);
1362 if (Cstr.then) {
1363 // Await creates a micro-task avoid if possible
1364 const endLoad = uniqueTime();
1365 Cstr = await Cstr;
1366 endLoad();
1367 }
1368 if (!Cstr.isProxied) {
1369 proxyComponent(Cstr, cmpMeta, 2 /* proxyState */);
1370 Cstr.isProxied = true;
1371 }
1372 const endNewInstance = createTime('createInstance', cmpMeta.$tagName$);
1373 // ok, time to construct the instance
1374 // but let's keep track of when we start and stop
1375 // so that the getters/setters don't incorrectly step on data
1376 {
1377 hostRef.$flags$ |= 8 /* isConstructingInstance */;
1378 }
1379 // construct the lazy-loaded component implementation
1380 // passing the hostRef is very important during
1381 // construction in order to directly wire together the
1382 // host element and the lazy-loaded instance
1383 try {
1384 new Cstr(hostRef);
1385 }
1386 catch (e) {
1387 consoleError(e);
1388 }
1389 {
1390 hostRef.$flags$ &= ~8 /* isConstructingInstance */;
1391 }
1392 endNewInstance();
1393 }
1394 if (Cstr.style) {
1395 // this component has styles but we haven't registered them yet
1396 let style = Cstr.style;
1397 const scopeId = getScopeId(cmpMeta);
1398 if (!styles.has(scopeId)) {
1399 const endRegisterStyles = createTime('registerStyles', cmpMeta.$tagName$);
1400 registerStyle(scopeId, style, !!(cmpMeta.$flags$ & 1 /* shadowDomEncapsulation */));
1401 endRegisterStyles();
1402 }
1403 }
1404 }
1405 // we've successfully created a lazy instance
1406 const ancestorComponent = hostRef.$ancestorComponent$;
1407 const schedule = () => scheduleUpdate(hostRef, true);
1408 if (ancestorComponent && ancestorComponent['s-rc']) {
1409 // this is the initial load and this component it has an ancestor component
1410 // but the ancestor component has NOT fired its will update lifecycle yet
1411 // so let's just cool our jets and wait for the ancestor to continue first
1412 // this will get fired off when the ancestor component
1413 // finally gets around to rendering its lazy self
1414 // fire off the initial update
1415 ancestorComponent['s-rc'].push(schedule);
1416 }
1417 else {
1418 schedule();
1419 }
1420};
1421const connectedCallback = (elm) => {
1422 if ((plt.$flags$ & 1 /* isTmpDisconnected */) === 0) {
1423 const hostRef = getHostRef(elm);
1424 const cmpMeta = hostRef.$cmpMeta$;
1425 const endConnected = createTime('connectedCallback', cmpMeta.$tagName$);
1426 if (!(hostRef.$flags$ & 1 /* hasConnected */)) {
1427 // first time this component has connected
1428 hostRef.$flags$ |= 1 /* hasConnected */;
1429 let hostId;
1430 {
1431 hostId = elm.getAttribute(HYDRATE_ID);
1432 if (hostId) {
1433 initializeClientHydrate(elm, cmpMeta.$tagName$, hostId, hostRef);
1434 }
1435 }
1436 if (!hostId) {
1437 // initUpdate
1438 // if the slot polyfill is required we'll need to put some nodes
1439 // in here to act as original content anchors as we move nodes around
1440 // host element has been connected to the DOM
1441 if ((cmpMeta.$flags$ & (4 /* hasSlotRelocation */ | 8 /* needsShadowDomShim */))) {
1442 setContentReference(elm);
1443 }
1444 }
1445 {
1446 // find the first ancestor component (if there is one) and register
1447 // this component as one of the actively loading child components for its ancestor
1448 let ancestorComponent = elm;
1449 while ((ancestorComponent = ancestorComponent.parentNode || ancestorComponent.host)) {
1450 // climb up the ancestors looking for the first
1451 // component that hasn't finished its lifecycle update yet
1452 if ((ancestorComponent.nodeType === 1 /* ElementNode */ &&
1453 ancestorComponent.hasAttribute('s-id') &&
1454 ancestorComponent['s-p']) ||
1455 ancestorComponent['s-p']) {
1456 // we found this components first ancestor component
1457 // keep a reference to this component's ancestor component
1458 attachToAncestor(hostRef, (hostRef.$ancestorComponent$ = ancestorComponent));
1459 break;
1460 }
1461 }
1462 }
1463 // Lazy properties
1464 // https://developers.google.com/web/fundamentals/web-components/best-practices#lazy-properties
1465 if (cmpMeta.$members$) {
1466 Object.entries(cmpMeta.$members$).map(([memberName, [memberFlags]]) => {
1467 if (memberFlags & 31 /* Prop */ && elm.hasOwnProperty(memberName)) {
1468 const value = elm[memberName];
1469 delete elm[memberName];
1470 elm[memberName] = value;
1471 }
1472 });
1473 }
1474 {
1475 initializeComponent(elm, hostRef, cmpMeta);
1476 }
1477 }
1478 endConnected();
1479 }
1480};
1481const setContentReference = (elm) => {
1482 // only required when we're NOT using native shadow dom (slot)
1483 // or this browser doesn't support native shadow dom
1484 // and this host element was NOT created with SSR
1485 // let's pick out the inner content for slot projection
1486 // create a node to represent where the original
1487 // content was first placed, which is useful later on
1488 const contentRefElm = (elm['s-cr'] = doc.createComment(''));
1489 contentRefElm['s-cn'] = true;
1490 elm.insertBefore(contentRefElm, elm.firstChild);
1491};
1492const disconnectedCallback = (elm) => {
1493 if ((plt.$flags$ & 1 /* isTmpDisconnected */) === 0) {
1494 getHostRef(elm);
1495 }
1496};
1497const bootstrapLazy = (lazyBundles, options = {}) => {
1498 const endBootstrap = createTime();
1499 const cmpTags = [];
1500 const exclude = options.exclude || [];
1501 const customElements = win.customElements;
1502 const head = doc.head;
1503 const metaCharset = /*@__PURE__*/ head.querySelector('meta[charset]');
1504 const visibilityStyle = /*@__PURE__*/ doc.createElement('style');
1505 const deferredConnectedCallbacks = [];
1506 let appLoadFallback;
1507 let isBootstrapping = true;
1508 Object.assign(plt, options);
1509 plt.$resourcesUrl$ = new URL(options.resourcesUrl || './', doc.baseURI).href;
1510 {
1511 // If the app is already hydrated there is not point to disable the
1512 // async queue. This will improve the first input delay
1513 plt.$flags$ |= 2 /* appLoaded */;
1514 }
1515 lazyBundles.map((lazyBundle) => {
1516 lazyBundle[1].map((compactMeta) => {
1517 const cmpMeta = {
1518 $flags$: compactMeta[0],
1519 $tagName$: compactMeta[1],
1520 $members$: compactMeta[2],
1521 $listeners$: compactMeta[3],
1522 };
1523 {
1524 cmpMeta.$members$ = compactMeta[2];
1525 }
1526 {
1527 cmpMeta.$attrsToReflect$ = [];
1528 }
1529 const tagName = cmpMeta.$tagName$;
1530 const HostElement = class extends HTMLElement {
1531 // StencilLazyHost
1532 constructor(self) {
1533 // @ts-ignore
1534 super(self);
1535 self = this;
1536 registerHost(self, cmpMeta);
1537 }
1538 connectedCallback() {
1539 if (appLoadFallback) {
1540 clearTimeout(appLoadFallback);
1541 appLoadFallback = null;
1542 }
1543 if (isBootstrapping) {
1544 // connectedCallback will be processed once all components have been registered
1545 deferredConnectedCallbacks.push(this);
1546 }
1547 else {
1548 plt.jmp(() => connectedCallback(this));
1549 }
1550 }
1551 disconnectedCallback() {
1552 plt.jmp(() => disconnectedCallback(this));
1553 }
1554 componentOnReady() {
1555 return getHostRef(this).$onReadyPromise$;
1556 }
1557 };
1558 cmpMeta.$lazyBundleId$ = lazyBundle[0];
1559 if (!exclude.includes(tagName) && !customElements.get(tagName)) {
1560 cmpTags.push(tagName);
1561 customElements.define(tagName, proxyComponent(HostElement, cmpMeta, 1 /* isElementConstructor */));
1562 }
1563 });
1564 });
1565 {
1566 visibilityStyle.innerHTML = cmpTags + HYDRATED_CSS;
1567 visibilityStyle.setAttribute('data-styles', '');
1568 head.insertBefore(visibilityStyle, metaCharset ? metaCharset.nextSibling : head.firstChild);
1569 }
1570 // Process deferred connectedCallbacks now all components have been registered
1571 isBootstrapping = false;
1572 if (deferredConnectedCallbacks.length) {
1573 deferredConnectedCallbacks.map((host) => host.connectedCallback());
1574 }
1575 else {
1576 {
1577 plt.jmp(() => (appLoadFallback = setTimeout(appDidLoad, 30)));
1578 }
1579 }
1580 // Fallback appLoad event
1581 endBootstrap();
1582};
1583const hostRefs = new WeakMap();
1584const getHostRef = (ref) => hostRefs.get(ref);
1585const registerInstance = (lazyInstance, hostRef) => hostRefs.set((hostRef.$lazyInstance$ = lazyInstance), hostRef);
1586const registerHost = (elm, cmpMeta) => {
1587 const hostRef = {
1588 $flags$: 0,
1589 $hostElement$: elm,
1590 $cmpMeta$: cmpMeta,
1591 $instanceValues$: new Map(),
1592 };
1593 {
1594 hostRef.$onReadyPromise$ = new Promise((r) => (hostRef.$onReadyResolve$ = r));
1595 elm['s-p'] = [];
1596 elm['s-rc'] = [];
1597 }
1598 return hostRefs.set(elm, hostRef);
1599};
1600const isMemberInElement = (elm, memberName) => memberName in elm;
1601const consoleError = (e, el) => (0, console.error)(e, el);
1602const cmpModules = /*@__PURE__*/ new Map();
1603const loadModule = (cmpMeta, hostRef, hmrVersionId) => {
1604 // loadModuleImport
1605 const exportName = cmpMeta.$tagName$.replace(/-/g, '_');
1606 const bundleId = cmpMeta.$lazyBundleId$;
1607 const module = cmpModules.get(bundleId) ;
1608 if (module) {
1609 return module[exportName];
1610 }
1611 return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(
1612 /* webpackInclude: /\.entry\.js$/ */
1613 /* webpackExclude: /\.system\.entry\.js$/ */
1614 /* webpackMode: "lazy" */
1615 `./${bundleId}.entry.js${''}`)); }).then((importedModule) => {
1616 {
1617 cmpModules.set(bundleId, importedModule);
1618 }
1619 return importedModule[exportName];
1620 }, consoleError);
1621};
1622const styles = new Map();
1623const queueDomReads = [];
1624const queueDomWrites = [];
1625const queueTask = (queue, write) => (cb) => {
1626 queue.push(cb);
1627 if (!queuePending) {
1628 queuePending = true;
1629 if (write && plt.$flags$ & 4 /* queueSync */) {
1630 nextTick(flush);
1631 }
1632 else {
1633 plt.raf(flush);
1634 }
1635 }
1636};
1637const consume = (queue) => {
1638 for (let i = 0; i < queue.length; i++) {
1639 try {
1640 queue[i](performance.now());
1641 }
1642 catch (e) {
1643 consoleError(e);
1644 }
1645 }
1646 queue.length = 0;
1647};
1648const flush = () => {
1649 // always force a bunch of medium callbacks to run, but still have
1650 // a throttle on how many can run in a certain time
1651 // DOM READS!!!
1652 consume(queueDomReads);
1653 // DOM WRITES!!!
1654 {
1655 consume(queueDomWrites);
1656 if ((queuePending = queueDomReads.length > 0)) {
1657 // still more to do yet, but we've run out of time
1658 // let's let this thing cool off and try again in the next tick
1659 plt.raf(flush);
1660 }
1661 }
1662};
1663const nextTick = /*@__PURE__*/ (cb) => promiseResolve().then(cb);
1664const writeTask = /*@__PURE__*/ queueTask(queueDomWrites, true);
1665
1666exports.Host = Host;
1667exports.bootstrapLazy = bootstrapLazy;
1668exports.h = h;
1669exports.promiseResolve = promiseResolve;
1670exports.registerInstance = registerInstance;