@jumpgroup/jump-design-system 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/dist/cjs/app-globals-3a1e7e63.js +7 -0
  2. package/dist/cjs/app-globals-3a1e7e63.js.map +1 -0
  3. package/dist/cjs/{index-c572276a.js → index-46644e39.js} +499 -152
  4. package/dist/cjs/index-46644e39.js.map +1 -0
  5. package/dist/cjs/jump-button.cjs.entry.js +24 -16
  6. package/dist/cjs/jump-button.cjs.entry.js.map +1 -1
  7. package/dist/cjs/jump-design-system.cjs.js +6 -4
  8. package/dist/cjs/jump-design-system.cjs.js.map +1 -1
  9. package/dist/cjs/jump-icon.cjs.entry.js +19 -30
  10. package/dist/cjs/jump-icon.cjs.entry.js.map +1 -1
  11. package/dist/cjs/jump-pagination.cjs.entry.js +22 -21
  12. package/dist/cjs/jump-pagination.cjs.entry.js.map +1 -1
  13. package/dist/cjs/loader.cjs.js +6 -4
  14. package/dist/cjs/loader.cjs.js.map +1 -1
  15. package/dist/collection/collection-manifest.json +2 -2
  16. package/dist/collection/components/app-icon/jump-icon.js +59 -59
  17. package/dist/collection/components/app-icon/jump-icon.js.map +1 -1
  18. package/dist/collection/components/app-icon/jump-icon.stories.js +16 -16
  19. package/dist/collection/components/app-icon/jump-icon.stories.js.map +1 -1
  20. package/dist/collection/components/app-icon/test/jump-icon.e2e.js +6 -6
  21. package/dist/collection/components/app-icon/test/jump-icon.e2e.js.map +1 -1
  22. package/dist/collection/components/app-icon/test/jump-icon.spec.js +7 -7
  23. package/dist/collection/components/app-icon/test/jump-icon.spec.js.map +1 -1
  24. package/dist/collection/components/jump-button/jump-button.css +47 -21
  25. package/dist/collection/components/jump-button/jump-button.js +285 -153
  26. package/dist/collection/components/jump-button/jump-button.js.map +1 -1
  27. package/dist/collection/components/jump-button/jump-button.stories.js +371 -206
  28. package/dist/collection/components/jump-button/jump-button.stories.js.map +1 -1
  29. package/dist/collection/components/jump-button/test/jump-button.e2e.js +6 -6
  30. package/dist/collection/components/jump-button/test/jump-button.e2e.js.map +1 -1
  31. package/dist/collection/components/jump-button/test/jump-button.spec.js +7 -7
  32. package/dist/collection/components/jump-button/test/jump-button.spec.js.map +1 -1
  33. package/dist/collection/components/jump-pagination/jump-pagination.js +175 -175
  34. package/dist/collection/components/jump-pagination/jump-pagination.js.map +1 -1
  35. package/dist/collection/components/jump-pagination/jump-pagination.stories.js +91 -92
  36. package/dist/collection/components/jump-pagination/jump-pagination.stories.js.map +1 -1
  37. package/dist/collection/components/jump-pagination/test/jump-pagination.e2e.js +6 -6
  38. package/dist/collection/components/jump-pagination/test/jump-pagination.e2e.js.map +1 -1
  39. package/dist/collection/components/jump-pagination/test/jump-pagination.spec.js +7 -7
  40. package/dist/collection/components/jump-pagination/test/jump-pagination.spec.js.map +1 -1
  41. package/dist/collection/utils/utils.js +1 -1
  42. package/dist/collection/utils/utils.js.map +1 -1
  43. package/dist/collection/utils/utils.spec.js +12 -12
  44. package/dist/collection/utils/utils.spec.js.map +1 -1
  45. package/dist/components/index.d.ts +6 -0
  46. package/dist/components/index.js +1 -1
  47. package/dist/components/jump-button.d.ts +2 -2
  48. package/dist/components/jump-button.js +50 -35
  49. package/dist/components/jump-button.js.map +1 -1
  50. package/dist/components/jump-icon.d.ts +2 -2
  51. package/dist/components/jump-icon2.js +33 -44
  52. package/dist/components/jump-icon2.js.map +1 -1
  53. package/dist/components/jump-pagination.d.ts +2 -2
  54. package/dist/components/jump-pagination.js +47 -46
  55. package/dist/components/jump-pagination.js.map +1 -1
  56. package/dist/esm/app-globals-0f993ce5.js +5 -0
  57. package/dist/esm/app-globals-0f993ce5.js.map +1 -0
  58. package/dist/esm/{index-ad69454c.js → index-b0176170.js} +499 -152
  59. package/dist/esm/index-b0176170.js.map +1 -0
  60. package/dist/esm/jump-button.entry.js +24 -16
  61. package/dist/esm/jump-button.entry.js.map +1 -1
  62. package/dist/esm/jump-design-system.js +7 -5
  63. package/dist/esm/jump-design-system.js.map +1 -1
  64. package/dist/esm/jump-icon.entry.js +19 -30
  65. package/dist/esm/jump-icon.entry.js.map +1 -1
  66. package/dist/esm/jump-pagination.entry.js +22 -21
  67. package/dist/esm/jump-pagination.entry.js.map +1 -1
  68. package/dist/esm/loader.js +7 -5
  69. package/dist/esm/loader.js.map +1 -1
  70. package/dist/jump-design-system/jump-design-system.esm.js +1 -1
  71. package/dist/jump-design-system/jump-design-system.esm.js.map +1 -1
  72. package/dist/jump-design-system/p-0d2b55a8.entry.js +2 -0
  73. package/dist/jump-design-system/p-0d2b55a8.entry.js.map +1 -0
  74. package/dist/jump-design-system/p-1bb7f2a5.entry.js +2 -0
  75. package/dist/jump-design-system/p-1bb7f2a5.entry.js.map +1 -0
  76. package/dist/jump-design-system/{p-15ecd712.entry.js → p-3cbc3a68.entry.js} +3 -3
  77. package/dist/jump-design-system/p-3cbc3a68.entry.js.map +1 -0
  78. package/dist/jump-design-system/p-68bce598.js +3 -0
  79. package/dist/jump-design-system/p-68bce598.js.map +1 -0
  80. package/dist/jump-design-system/p-e1255160.js +2 -0
  81. package/dist/jump-design-system/p-e1255160.js.map +1 -0
  82. package/dist/jump-design-system-elements.json +57 -1
  83. package/dist/types/components/app-icon/jump-icon.d.ts +10 -10
  84. package/dist/types/components/app-icon/jump-icon.stories.d.ts +14 -14
  85. package/dist/types/components/jump-button/jump-button.d.ts +57 -29
  86. package/dist/types/components/jump-button/jump-button.stories.d.ts +152 -86
  87. package/dist/types/components/jump-pagination/jump-pagination.d.ts +24 -24
  88. package/dist/types/components/jump-pagination/jump-pagination.stories.d.ts +63 -63
  89. package/dist/types/components.d.ts +60 -4
  90. package/dist/types/stencil-public-runtime.d.ts +46 -5
  91. package/loader/index.d.ts +1 -1
  92. package/package.json +2 -2
  93. package/readme.md +13 -8
  94. package/dist/cjs/index-c572276a.js.map +0 -1
  95. package/dist/esm/index-ad69454c.js.map +0 -1
  96. package/dist/jump-design-system/p-15ecd712.entry.js.map +0 -1
  97. package/dist/jump-design-system/p-42799645.entry.js +0 -2
  98. package/dist/jump-design-system/p-42799645.entry.js.map +0 -1
  99. package/dist/jump-design-system/p-44f459bb.js +0 -3
  100. package/dist/jump-design-system/p-44f459bb.js.map +0 -1
  101. package/dist/jump-design-system/p-6ba563bd.entry.js +0 -2
  102. package/dist/jump-design-system/p-6ba563bd.entry.js.map +0 -1
@@ -1,4 +1,5 @@
1
1
  const NAMESPACE = 'jump-design-system';
2
+ const BUILD = /* jump-design-system */ { allRenderFn: true, appendChildSlotFix: false, asyncLoading: true, asyncQueue: false, attachStyles: true, cloneNodeFix: false, cmpDidLoad: true, cmpDidRender: false, cmpDidUnload: false, cmpDidUpdate: false, cmpShouldUpdate: false, cmpWillLoad: false, cmpWillRender: false, cmpWillUpdate: false, connectedCallback: false, constructableCSS: true, cssAnnotations: true, devTools: false, disconnectedCallback: false, element: false, event: false, experimentalScopedSlotChanges: false, experimentalSlotFixes: false, formAssociated: false, hasRenderFn: true, hostListener: false, hostListenerTarget: false, hostListenerTargetBody: false, hostListenerTargetDocument: false, hostListenerTargetParent: false, hostListenerTargetWindow: false, hotModuleReplacement: false, hydrateClientSide: false, hydrateServerSide: false, hydratedAttribute: false, hydratedClass: true, initializeNextTick: false, invisiblePrehydration: true, isDebug: false, isDev: false, isTesting: false, lazyLoad: true, lifecycle: true, lifecycleDOMEvents: false, member: true, method: false, mode: false, observeAttribute: true, profile: false, prop: true, propBoolean: true, propMutable: false, propNumber: true, propString: true, reflect: true, scoped: false, scopedSlotTextContentFix: false, scriptDataOpts: false, shadowDelegatesFocus: false, shadowDom: false, slot: true, slotChildNodesFix: false, slotRelocation: true, state: false, style: true, svg: false, taskQueue: true, transformTagName: false, updatable: true, vdomAttribute: true, vdomClass: true, vdomFunctional: false, vdomKey: true, vdomListener: false, vdomPropOrAttr: true, vdomRef: false, vdomRender: true, vdomStyle: false, vdomText: true, vdomXlink: false, watchCallback: false };
2
3
 
3
4
  /**
4
5
  * Virtual DOM patching algorithm based on Snabbdom by
@@ -30,6 +31,13 @@ const uniqueTime = (key, measureText) => {
30
31
  }
31
32
  };
32
33
  const HYDRATED_CSS = '{visibility:hidden}.hydrated{visibility:inherit}';
34
+ /**
35
+ * Constant for styles to be globally applied to `slot-fb` elements for pseudo-slot behavior.
36
+ *
37
+ * Two cascading rules must be used instead of a `:not()` selector due to Stencil browser
38
+ * support as of Stencil v4.
39
+ */
40
+ const SLOT_FB_CSS = 'slot-fb{display:contents}slot-fb[hidden]{display:none}';
33
41
  /**
34
42
  * Default style mode id
35
43
  */
@@ -74,6 +82,7 @@ function queryNonceMetaTagContent(doc) {
74
82
  // export function h(nodeName: string | d.FunctionalComponent, vnodeData: d.PropsType, ...children: d.ChildType[]): d.VNode;
75
83
  const h = (nodeName, vnodeData, ...children) => {
76
84
  let child = null;
85
+ let key = null;
77
86
  let slotName = null;
78
87
  let simple = false;
79
88
  let lastSimple = false;
@@ -102,9 +111,13 @@ const h = (nodeName, vnodeData, ...children) => {
102
111
  };
103
112
  walk(children);
104
113
  if (vnodeData) {
114
+ if (vnodeData.key) {
115
+ key = vnodeData.key;
116
+ }
105
117
  if (vnodeData.name) {
106
118
  slotName = vnodeData.name;
107
119
  }
120
+ // normalize class / className attributes
108
121
  {
109
122
  const classData = vnodeData.className || vnodeData.class;
110
123
  if (classData) {
@@ -122,6 +135,9 @@ const h = (nodeName, vnodeData, ...children) => {
122
135
  if (vNodeChildren.length > 0) {
123
136
  vnode.$children$ = vNodeChildren;
124
137
  }
138
+ {
139
+ vnode.$key$ = key;
140
+ }
125
141
  {
126
142
  vnode.$name$ = slotName;
127
143
  }
@@ -146,6 +162,9 @@ const newVNode = (tag, text) => {
146
162
  {
147
163
  vnode.$attrs$ = null;
148
164
  }
165
+ {
166
+ vnode.$key$ = null;
167
+ }
149
168
  {
150
169
  vnode.$name$ = null;
151
170
  }
@@ -261,6 +280,10 @@ const addStyle = (styleContainerNode, cmpMeta, mode) => {
261
280
  }
262
281
  styleContainerNode.insertBefore(styleElm, styleContainerNode.querySelector('link'));
263
282
  }
283
+ // Add styles for `slot-fb` elements if we're using slots outside the Shadow DOM
284
+ if (cmpMeta.$flags$ & 4 /* CMP_FLAGS.hasSlotRelocation */) {
285
+ styleElm.innerHTML += SLOT_FB_CSS;
286
+ }
264
287
  if (appliedStyles) {
265
288
  appliedStyles.add(scopeId);
266
289
  }
@@ -288,6 +311,21 @@ const getScopeId = (cmp, mode) => 'sc-' + (cmp.$tagName$);
288
311
  *
289
312
  * Modified for Stencil's compiler and vdom
290
313
  */
314
+ /**
315
+ * When running a VDom render set properties present on a VDom node onto the
316
+ * corresponding HTML element.
317
+ *
318
+ * Note that this function has special functionality for the `class`,
319
+ * `style`, `key`, and `ref` attributes, as well as event handlers (like
320
+ * `onClick`, etc). All others are just passed through as-is.
321
+ *
322
+ * @param elm the HTMLElement onto which attributes should be set
323
+ * @param memberName the name of the attribute to set
324
+ * @param oldValue the old value for the attribute
325
+ * @param newValue the new value for the attribute
326
+ * @param isSvg whether we're in an svg context or not
327
+ * @param flags bitflags for Vdom variables
328
+ */
291
329
  const setAccessor = (elm, memberName, oldValue, newValue, isSvg, flags) => {
292
330
  if (oldValue !== newValue) {
293
331
  let isProp = isMemberInElement(elm, memberName);
@@ -299,6 +337,8 @@ const setAccessor = (elm, memberName, oldValue, newValue, isSvg, flags) => {
299
337
  classList.remove(...oldClasses.filter((c) => c && !newClasses.includes(c)));
300
338
  classList.add(...newClasses.filter((c) => c && !oldClasses.includes(c)));
301
339
  }
340
+ else if (memberName === 'key')
341
+ ;
302
342
  else {
303
343
  // Set property if it exists and it's not a SVG
304
344
  const isComplex = isComplexType(newValue);
@@ -318,7 +358,11 @@ const setAccessor = (elm, memberName, oldValue, newValue, isSvg, flags) => {
318
358
  elm[memberName] = newValue;
319
359
  }
320
360
  }
321
- catch (e) { }
361
+ catch (e) {
362
+ /**
363
+ * in case someone tries to set a read-only property, e.g. "namespaceURI", we just ignore it
364
+ */
365
+ }
322
366
  }
323
367
  if (newValue == null || newValue === false) {
324
368
  if (newValue !== false || elm.getAttribute(memberName) === '') {
@@ -337,6 +381,11 @@ const setAccessor = (elm, memberName, oldValue, newValue, isSvg, flags) => {
337
381
  }
338
382
  };
339
383
  const parseClassListRegex = /\s/;
384
+ /**
385
+ * Parsed a string of classnames into an array
386
+ * @param value className string, e.g. "foo bar baz"
387
+ * @returns list of classes, e.g. ["foo", "bar", "baz"]
388
+ */
340
389
  const parseClassList = (value) => (!value ? [] : value.split(parseClassListRegex));
341
390
  const updateElement = (oldVnode, newVnode, isSvgMode, memberName) => {
342
391
  // if the element passed in is a shadow root, which is a document fragment
@@ -418,8 +467,10 @@ const createElm = (oldParentVNode, newParentVNode, childIndex, parentElm) => {
418
467
  }
419
468
  }
420
469
  }
470
+ // This needs to always happen so we can hide nodes that are projected
471
+ // to another component but don't end up in a slot
472
+ elm['s-hn'] = hostTagName;
421
473
  {
422
- elm['s-hn'] = hostTagName;
423
474
  if (newVNode.$flags$ & (2 /* VNODE_FLAGS.isSlotFallback */ | 1 /* VNODE_FLAGS.isSlotReference */)) {
424
475
  // remember the content reference comment
425
476
  elm['s-sr'] = true;
@@ -430,9 +481,11 @@ const createElm = (oldParentVNode, newParentVNode, childIndex, parentElm) => {
430
481
  // check if we've got an old vnode for this slot
431
482
  oldVNode = oldParentVNode && oldParentVNode.$children$ && oldParentVNode.$children$[childIndex];
432
483
  if (oldVNode && oldVNode.$tag$ === newVNode.$tag$ && oldParentVNode.$elm$) {
433
- // we've got an old slot vnode and the wrapper is being replaced
434
- // so let's move the old slot content back to it's original location
435
- putBackInOriginalLocation(oldParentVNode.$elm$, false);
484
+ {
485
+ // we've got an old slot vnode and the wrapper is being replaced
486
+ // so let's move the old slot content back to its original location
487
+ putBackInOriginalLocation(oldParentVNode.$elm$, false);
488
+ }
436
489
  }
437
490
  }
438
491
  }
@@ -444,16 +497,15 @@ const putBackInOriginalLocation = (parentElm, recursive) => {
444
497
  for (let i = oldSlotChildNodes.length - 1; i >= 0; i--) {
445
498
  const childNode = oldSlotChildNodes[i];
446
499
  if (childNode['s-hn'] !== hostTagName && childNode['s-ol']) {
447
- // // this child node in the old element is from another component
448
- // // remove this node from the old slot's parent
449
- // childNode.remove();
450
500
  // and relocate it back to it's original location
451
501
  parentReferenceNode(childNode).insertBefore(childNode, referenceNode(childNode));
452
502
  // remove the old original location comment entirely
453
503
  // later on the patch function will know what to do
454
- // and move this to the correct spot in need be
504
+ // and move this to the correct spot if need be
455
505
  childNode['s-ol'].remove();
456
506
  childNode['s-ol'] = undefined;
507
+ // Reset so we can correctly move the node around again.
508
+ childNode['s-sh'] = undefined;
457
509
  checkSlotRelocate = true;
458
510
  }
459
511
  if (recursive) {
@@ -594,10 +646,13 @@ const removeVnodes = (vnodes, startIdx, endIdx) => {
594
646
  * @param oldCh the old children of the parent node
595
647
  * @param newVNode the new VNode which will replace the parent
596
648
  * @param newCh the new children of the parent node
649
+ * @param isInitialRender whether or not this is the first render of the vdom
597
650
  */
598
- const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
651
+ const updateChildren = (parentElm, oldCh, newVNode, newCh, isInitialRender = false) => {
599
652
  let oldStartIdx = 0;
600
653
  let newStartIdx = 0;
654
+ let idxInOld = 0;
655
+ let i = 0;
601
656
  let oldEndIdx = oldCh.length - 1;
602
657
  let oldStartVnode = oldCh[0];
603
658
  let oldEndVnode = oldCh[oldEndIdx];
@@ -605,6 +660,7 @@ const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
605
660
  let newStartVnode = newCh[0];
606
661
  let newEndVnode = newCh[newEndIdx];
607
662
  let node;
663
+ let elmToMove;
608
664
  while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
609
665
  if (oldStartVnode == null) {
610
666
  // VNode might have been moved left
@@ -619,24 +675,24 @@ const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
619
675
  else if (newEndVnode == null) {
620
676
  newEndVnode = newCh[--newEndIdx];
621
677
  }
622
- else if (isSameVnode(oldStartVnode, newStartVnode)) {
678
+ else if (isSameVnode(oldStartVnode, newStartVnode, isInitialRender)) {
623
679
  // if the start nodes are the same then we should patch the new VNode
624
680
  // onto the old one, and increment our `newStartIdx` and `oldStartIdx`
625
681
  // indices to reflect that. We don't need to move any DOM Nodes around
626
682
  // since things are matched up in order.
627
- patch(oldStartVnode, newStartVnode);
683
+ patch(oldStartVnode, newStartVnode, isInitialRender);
628
684
  oldStartVnode = oldCh[++oldStartIdx];
629
685
  newStartVnode = newCh[++newStartIdx];
630
686
  }
631
- else if (isSameVnode(oldEndVnode, newEndVnode)) {
687
+ else if (isSameVnode(oldEndVnode, newEndVnode, isInitialRender)) {
632
688
  // likewise, if the end nodes are the same we patch new onto old and
633
689
  // decrement our end indices, and also likewise in this case we don't
634
690
  // need to move any DOM Nodes.
635
- patch(oldEndVnode, newEndVnode);
691
+ patch(oldEndVnode, newEndVnode, isInitialRender);
636
692
  oldEndVnode = oldCh[--oldEndIdx];
637
693
  newEndVnode = newCh[--newEndIdx];
638
694
  }
639
- else if (isSameVnode(oldStartVnode, newEndVnode)) {
695
+ else if (isSameVnode(oldStartVnode, newEndVnode, isInitialRender)) {
640
696
  // case: "Vnode moved right"
641
697
  //
642
698
  // We've found that the last node in our window on the new children is
@@ -654,7 +710,7 @@ const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
654
710
  if ((oldStartVnode.$tag$ === 'slot' || newEndVnode.$tag$ === 'slot')) {
655
711
  putBackInOriginalLocation(oldStartVnode.$elm$.parentNode, false);
656
712
  }
657
- patch(oldStartVnode, newEndVnode);
713
+ patch(oldStartVnode, newEndVnode, isInitialRender);
658
714
  // We need to move the element for `oldStartVnode` into a position which
659
715
  // will be appropriate for `newEndVnode`. For this we can use
660
716
  // `.insertBefore` and `oldEndVnode.$elm$.nextSibling`. If there is a
@@ -676,7 +732,7 @@ const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
676
732
  oldStartVnode = oldCh[++oldStartIdx];
677
733
  newEndVnode = newCh[--newEndIdx];
678
734
  }
679
- else if (isSameVnode(oldEndVnode, newStartVnode)) {
735
+ else if (isSameVnode(oldEndVnode, newStartVnode, isInitialRender)) {
680
736
  // case: "Vnode moved left"
681
737
  //
682
738
  // We've found that the first node in our window on the new children is
@@ -695,7 +751,7 @@ const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
695
751
  if ((oldStartVnode.$tag$ === 'slot' || newEndVnode.$tag$ === 'slot')) {
696
752
  putBackInOriginalLocation(oldEndVnode.$elm$.parentNode, false);
697
753
  }
698
- patch(oldEndVnode, newStartVnode);
754
+ patch(oldEndVnode, newStartVnode, isInitialRender);
699
755
  // We've already checked above if `oldStartVnode` and `newStartVnode` are
700
756
  // the same node, so since we're here we know that they are not. Thus we
701
757
  // can move the element for `oldEndVnode` _before_ the element for
@@ -706,7 +762,41 @@ const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
706
762
  newStartVnode = newCh[++newStartIdx];
707
763
  }
708
764
  else {
765
+ // Here we do some checks to match up old and new nodes based on the
766
+ // `$key$` attribute, which is set by putting a `key="my-key"` attribute
767
+ // in the JSX for a DOM element in the implementation of a Stencil
768
+ // component.
769
+ //
770
+ // First we check to see if there are any nodes in the array of old
771
+ // children which have the same key as the first node in the new
772
+ // children.
773
+ idxInOld = -1;
709
774
  {
775
+ for (i = oldStartIdx; i <= oldEndIdx; ++i) {
776
+ if (oldCh[i] && oldCh[i].$key$ !== null && oldCh[i].$key$ === newStartVnode.$key$) {
777
+ idxInOld = i;
778
+ break;
779
+ }
780
+ }
781
+ }
782
+ if (idxInOld >= 0) {
783
+ // We found a node in the old children which matches up with the first
784
+ // node in the new children! So let's deal with that
785
+ elmToMove = oldCh[idxInOld];
786
+ if (elmToMove.$tag$ !== newStartVnode.$tag$) {
787
+ // the tag doesn't match so we'll need a new DOM element
788
+ node = createElm(oldCh && oldCh[newStartIdx], newVNode, idxInOld);
789
+ }
790
+ else {
791
+ patch(elmToMove, newStartVnode, isInitialRender);
792
+ // invalidate the matching old node so that we won't try to update it
793
+ // again later on
794
+ oldCh[idxInOld] = undefined;
795
+ node = elmToMove.$elm$;
796
+ }
797
+ newStartVnode = newCh[++newStartIdx];
798
+ }
799
+ else {
710
800
  // We either didn't find an element in the old children that matches
711
801
  // the key of the first new child OR the build is not using `key`
712
802
  // attributes at all. In either case we need to create a new element
@@ -749,15 +839,24 @@ const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
749
839
  *
750
840
  * @param leftVNode the first VNode to check
751
841
  * @param rightVNode the second VNode to check
842
+ * @param isInitialRender whether or not this is the first render of the vdom
752
843
  * @returns whether they're equal or not
753
844
  */
754
- const isSameVnode = (leftVNode, rightVNode) => {
845
+ const isSameVnode = (leftVNode, rightVNode, isInitialRender = false) => {
755
846
  // compare if two vnode to see if they're "technically" the same
756
847
  // need to have the same element tag, and same key to be the same
757
848
  if (leftVNode.$tag$ === rightVNode.$tag$) {
758
849
  if (leftVNode.$tag$ === 'slot') {
759
850
  return leftVNode.$name$ === rightVNode.$name$;
760
851
  }
852
+ // this will be set if JSX tags in the build have `key` attrs set on them
853
+ // we only want to check this if we're not on the first render since on
854
+ // first render `leftVNode.$key$` will always be `null`, so we can be led
855
+ // astray and, for instance, accidentally delete a DOM node that we want to
856
+ // keep around.
857
+ if (!isInitialRender) {
858
+ return leftVNode.$key$ === rightVNode.$key$;
859
+ }
761
860
  return true;
762
861
  }
763
862
  return false;
@@ -777,8 +876,9 @@ const parentReferenceNode = (node) => (node['s-ol'] ? node['s-ol'] : node).paren
777
876
  *
778
877
  * @param oldVNode an old VNode whose DOM element and children we want to update
779
878
  * @param newVNode a new VNode representing an updated version of the old one
879
+ * @param isInitialRender whether or not this is the first render of the vdom
780
880
  */
781
- const patch = (oldVNode, newVNode) => {
881
+ const patch = (oldVNode, newVNode, isInitialRender = false) => {
782
882
  const elm = (newVNode.$elm$ = oldVNode.$elm$);
783
883
  const oldChildren = oldVNode.$children$;
784
884
  const newChildren = newVNode.$children$;
@@ -787,8 +887,7 @@ const patch = (oldVNode, newVNode) => {
787
887
  let defaultHolder;
788
888
  if (text === null) {
789
889
  {
790
- if (tag === 'slot')
791
- ;
890
+ if (tag === 'slot' && !useNativeShadowDom) ;
792
891
  else {
793
892
  // either this is the first render of an element OR it's an update
794
893
  // AND we already know it's possible it could have changed
@@ -799,7 +898,7 @@ const patch = (oldVNode, newVNode) => {
799
898
  if (oldChildren !== null && newChildren !== null) {
800
899
  // looks like there's child vnodes for both the old and new vnodes
801
900
  // so we need to call `updateChildren` to reconcile them
802
- updateChildren(elm, oldChildren, newVNode, newChildren);
901
+ updateChildren(elm, oldChildren, newVNode, newChildren, isInitialRender);
803
902
  }
804
903
  else if (newChildren !== null) {
805
904
  // no old child vnodes, but there are new child vnodes to add
@@ -825,42 +924,53 @@ const patch = (oldVNode, newVNode) => {
825
924
  elm.data = text;
826
925
  }
827
926
  };
927
+ /**
928
+ * Adjust the `.hidden` property as-needed on any nodes in a DOM subtree which
929
+ * are slot fallbacks nodes.
930
+ *
931
+ * A slot fallback node should be visible by default. Then, it should be
932
+ * conditionally hidden if:
933
+ *
934
+ * - it has a sibling with a `slot` property set to its slot name or if
935
+ * - it is a default fallback slot node, in which case we hide if it has any
936
+ * content
937
+ *
938
+ * @param elm the element of interest
939
+ */
828
940
  const updateFallbackSlotVisibility = (elm) => {
829
- // tslint:disable-next-line: prefer-const
830
941
  const childNodes = elm.childNodes;
831
- let childNode;
832
- let i;
833
- let ilen;
834
- let j;
835
- let slotNameAttr;
836
- let nodeType;
837
- for (i = 0, ilen = childNodes.length; i < ilen; i++) {
838
- childNode = childNodes[i];
942
+ for (const childNode of childNodes) {
839
943
  if (childNode.nodeType === 1 /* NODE_TYPE.ElementNode */) {
840
944
  if (childNode['s-sr']) {
841
945
  // this is a slot fallback node
842
946
  // get the slot name for this slot reference node
843
- slotNameAttr = childNode['s-sn'];
947
+ const slotName = childNode['s-sn'];
844
948
  // by default always show a fallback slot node
845
949
  // then hide it if there are other slots in the light dom
846
950
  childNode.hidden = false;
847
- for (j = 0; j < ilen; j++) {
848
- nodeType = childNodes[j].nodeType;
849
- if (childNodes[j]['s-hn'] !== childNode['s-hn'] || slotNameAttr !== '') {
850
- // this sibling node is from a different component OR is a named fallback slot node
851
- if (nodeType === 1 /* NODE_TYPE.ElementNode */ && slotNameAttr === childNodes[j].getAttribute('slot')) {
852
- childNode.hidden = true;
853
- break;
951
+ // we need to check all of its sibling nodes in order to see if
952
+ // `childNode` should be hidden
953
+ for (const siblingNode of childNodes) {
954
+ // Don't check the node against itself
955
+ if (siblingNode !== childNode) {
956
+ if (siblingNode['s-hn'] !== childNode['s-hn'] || slotName !== '') {
957
+ // this sibling node is from a different component OR is a named
958
+ // fallback slot node
959
+ if (siblingNode.nodeType === 1 /* NODE_TYPE.ElementNode */ &&
960
+ (slotName === siblingNode.getAttribute('slot') || slotName === siblingNode['s-sn'])) {
961
+ childNode.hidden = true;
962
+ break;
963
+ }
854
964
  }
855
- }
856
- else {
857
- // this is a default fallback slot node
858
- // any element or text node (with content)
859
- // should hide the default fallback slot node
860
- if (nodeType === 1 /* NODE_TYPE.ElementNode */ ||
861
- (nodeType === 3 /* NODE_TYPE.TextNode */ && childNodes[j].textContent.trim() !== '')) {
862
- childNode.hidden = true;
863
- break;
965
+ else {
966
+ // this is a default fallback slot node
967
+ // any element or text node (with content)
968
+ // should hide the default fallback slot node
969
+ if (siblingNode.nodeType === 1 /* NODE_TYPE.ElementNode */ ||
970
+ (siblingNode.nodeType === 3 /* NODE_TYPE.TextNode */ && siblingNode.textContent.trim() !== '')) {
971
+ childNode.hidden = true;
972
+ break;
973
+ }
864
974
  }
865
975
  }
866
976
  }
@@ -870,45 +980,67 @@ const updateFallbackSlotVisibility = (elm) => {
870
980
  }
871
981
  }
872
982
  };
983
+ /**
984
+ * Component-global information about nodes which are either currently being
985
+ * relocated or will be shortly.
986
+ */
873
987
  const relocateNodes = [];
874
- const relocateSlotContent = (elm) => {
988
+ /**
989
+ * Mark the contents of a slot for relocation via adding references to them to
990
+ * the {@link relocateNodes} data structure. The actual work of relocating them
991
+ * will then be handled in {@link renderVdom}.
992
+ *
993
+ * @param elm a render node whose child nodes need to be relocated
994
+ */
995
+ const markSlotContentForRelocation = (elm) => {
875
996
  // tslint:disable-next-line: prefer-const
876
- let childNode;
877
997
  let node;
878
998
  let hostContentNodes;
879
- let slotNameAttr;
880
- let relocateNodeData;
881
999
  let j;
882
- let i = 0;
883
- const childNodes = elm.childNodes;
884
- const ilen = childNodes.length;
885
- for (; i < ilen; i++) {
886
- childNode = childNodes[i];
1000
+ for (const childNode of elm.childNodes) {
1001
+ // we need to find child nodes which are slot references so we can then try
1002
+ // to match them up with nodes that need to be relocated
887
1003
  if (childNode['s-sr'] && (node = childNode['s-cr']) && node.parentNode) {
888
- // first got the content reference comment node
889
- // then we got it's parent, which is where all the host content is in now
1004
+ // first get the content reference comment node ('s-cr'), then we get
1005
+ // its parent, which is where all the host content is now
890
1006
  hostContentNodes = node.parentNode.childNodes;
891
- slotNameAttr = childNode['s-sn'];
1007
+ const slotName = childNode['s-sn'];
1008
+ // iterate through all the nodes under the location where the host was
1009
+ // originally rendered
892
1010
  for (j = hostContentNodes.length - 1; j >= 0; j--) {
893
1011
  node = hostContentNodes[j];
894
- if (!node['s-cn'] && !node['s-nr'] && node['s-hn'] !== childNode['s-hn']) {
895
- // let's do some relocating to its new home
896
- // but never relocate a content reference node
897
- // that is suppose to always represent the original content location
898
- if (isNodeLocatedInSlot(node, slotNameAttr)) {
1012
+ // check that the node is not a content reference node or a node
1013
+ // reference and then check that the host name does not match that of
1014
+ // childNode.
1015
+ // In addition, check that the slot either has not already been relocated, or
1016
+ // that its current location's host is not childNode's host. This is essentially
1017
+ // a check so that we don't try to relocate (and then hide) a node that is already
1018
+ // where it should be.
1019
+ if (!node['s-cn'] &&
1020
+ !node['s-nr'] &&
1021
+ node['s-hn'] !== childNode['s-hn'] &&
1022
+ (!BUILD.experimentalSlotFixes )) {
1023
+ // if `node` is located in the slot that `childNode` refers to (via the
1024
+ // `'s-sn'` property) then we need to relocate it from it's current spot
1025
+ // (under the host element parent) to the right slot location
1026
+ if (isNodeLocatedInSlot(node, slotName)) {
899
1027
  // it's possible we've already decided to relocate this node
900
- relocateNodeData = relocateNodes.find((r) => r.$nodeToRelocate$ === node);
1028
+ let relocateNodeData = relocateNodes.find((r) => r.$nodeToRelocate$ === node);
901
1029
  // made some changes to slots
902
1030
  // let's make sure we also double check
903
1031
  // fallbacks are correctly hidden or shown
904
1032
  checkSlotFallbackVisibility = true;
905
- node['s-sn'] = node['s-sn'] || slotNameAttr;
1033
+ // ensure that the slot-name attr is correct
1034
+ node['s-sn'] = node['s-sn'] || slotName;
906
1035
  if (relocateNodeData) {
907
- // previously we never found a slot home for this node
908
- // but turns out we did, so let's remember it now
1036
+ relocateNodeData.$nodeToRelocate$['s-sh'] = childNode['s-hn'];
1037
+ // we marked this node for relocation previously but didn't find
1038
+ // out the slot reference node to which it needs to be relocated
1039
+ // so write it down now!
909
1040
  relocateNodeData.$slotRefNode$ = childNode;
910
1041
  }
911
1042
  else {
1043
+ node['s-sh'] = childNode['s-hn'];
912
1044
  // add to our list of nodes to relocate
913
1045
  relocateNodes.push({
914
1046
  $slotRefNode$: childNode,
@@ -927,8 +1059,10 @@ const relocateSlotContent = (elm) => {
927
1059
  }
928
1060
  }
929
1061
  else if (!relocateNodes.some((r) => r.$nodeToRelocate$ === node)) {
930
- // so far this element does not have a slot home, not setting slotRefNode on purpose
931
- // if we never find a home for this element then we'll need to hide it
1062
+ // the node is not found within the slot (`childNode`) that we're
1063
+ // currently looking at, so we stick it into `relocateNodes` to
1064
+ // handle later. If we never find a home for this element then
1065
+ // we'll need to hide it
932
1066
  relocateNodes.push({
933
1067
  $nodeToRelocate$: node,
934
1068
  });
@@ -936,25 +1070,36 @@ const relocateSlotContent = (elm) => {
936
1070
  }
937
1071
  }
938
1072
  }
1073
+ // if we're dealing with any type of element (capable of itself being a
1074
+ // slot reference or containing one) then we recur
939
1075
  if (childNode.nodeType === 1 /* NODE_TYPE.ElementNode */) {
940
- relocateSlotContent(childNode);
1076
+ markSlotContentForRelocation(childNode);
941
1077
  }
942
1078
  }
943
1079
  };
944
- const isNodeLocatedInSlot = (nodeToRelocate, slotNameAttr) => {
1080
+ /**
1081
+ * Check whether a node is located in a given named slot.
1082
+ *
1083
+ * @param nodeToRelocate the node of interest
1084
+ * @param slotName the slot name to check
1085
+ * @returns whether the node is located in the slot or not
1086
+ */
1087
+ const isNodeLocatedInSlot = (nodeToRelocate, slotName) => {
945
1088
  if (nodeToRelocate.nodeType === 1 /* NODE_TYPE.ElementNode */) {
946
- if (nodeToRelocate.getAttribute('slot') === null && slotNameAttr === '') {
1089
+ if (nodeToRelocate.getAttribute('slot') === null && slotName === '') {
1090
+ // if the node doesn't have a slot attribute, and the slot we're checking
1091
+ // is not a named slot, then we assume the node should be within the slot
947
1092
  return true;
948
1093
  }
949
- if (nodeToRelocate.getAttribute('slot') === slotNameAttr) {
1094
+ if (nodeToRelocate.getAttribute('slot') === slotName) {
950
1095
  return true;
951
1096
  }
952
1097
  return false;
953
1098
  }
954
- if (nodeToRelocate['s-sn'] === slotNameAttr) {
1099
+ if (nodeToRelocate['s-sn'] === slotName) {
955
1100
  return true;
956
1101
  }
957
- return slotNameAttr === '';
1102
+ return slotName === '';
958
1103
  };
959
1104
  /**
960
1105
  * The main entry point for Stencil's virtual DOM-based rendering engine
@@ -967,71 +1112,104 @@ const isNodeLocatedInSlot = (nodeToRelocate, slotNameAttr) => {
967
1112
  * @param hostRef data needed to root and render the virtual DOM tree, such as
968
1113
  * the DOM node into which it should be rendered.
969
1114
  * @param renderFnResults the virtual DOM nodes to be rendered
1115
+ * @param isInitialLoad whether or not this is the first call after page load
970
1116
  */
971
- const renderVdom = (hostRef, renderFnResults) => {
1117
+ const renderVdom = (hostRef, renderFnResults, isInitialLoad = false) => {
1118
+ var _a, _b, _c, _d;
972
1119
  const hostElm = hostRef.$hostElement$;
973
1120
  const cmpMeta = hostRef.$cmpMeta$;
974
1121
  const oldVNode = hostRef.$vnode$ || newVNode(null, null);
1122
+ // if `renderFnResults` is a Host node then we can use it directly. If not,
1123
+ // we need to call `h` again to wrap the children of our component in a
1124
+ // 'dummy' Host node (well, an empty vnode) since `renderVdom` assumes
1125
+ // implicitly that the top-level vdom node is 1) an only child and 2)
1126
+ // contains attrs that need to be set on the host element.
975
1127
  const rootVnode = isHost(renderFnResults) ? renderFnResults : h(null, null, renderFnResults);
976
1128
  hostTagName = hostElm.tagName;
977
1129
  if (cmpMeta.$attrsToReflect$) {
978
1130
  rootVnode.$attrs$ = rootVnode.$attrs$ || {};
979
1131
  cmpMeta.$attrsToReflect$.map(([propName, attribute]) => (rootVnode.$attrs$[attribute] = hostElm[propName]));
980
1132
  }
1133
+ // On the first render and *only* on the first render we want to check for
1134
+ // any attributes set on the host element which are also set on the vdom
1135
+ // node. If we find them, we override the value on the VDom node attrs with
1136
+ // the value from the host element, which allows developers building apps
1137
+ // with Stencil components to override e.g. the `role` attribute on a
1138
+ // component even if it's already set on the `Host`.
1139
+ if (isInitialLoad && rootVnode.$attrs$) {
1140
+ for (const key of Object.keys(rootVnode.$attrs$)) {
1141
+ // We have a special implementation in `setAccessor` for `style` and
1142
+ // `class` which reconciles values coming from the VDom with values
1143
+ // already present on the DOM element, so we don't want to override those
1144
+ // attributes on the VDom tree with values from the host element if they
1145
+ // are present.
1146
+ //
1147
+ // Likewise, `ref` and `key` are special internal values for the Stencil
1148
+ // runtime and we don't want to override those either.
1149
+ if (hostElm.hasAttribute(key) && !['key', 'ref', 'style', 'class'].includes(key)) {
1150
+ rootVnode.$attrs$[key] = hostElm[key];
1151
+ }
1152
+ }
1153
+ }
981
1154
  rootVnode.$tag$ = null;
982
1155
  rootVnode.$flags$ |= 4 /* VNODE_FLAGS.isHost */;
983
1156
  hostRef.$vnode$ = rootVnode;
984
1157
  rootVnode.$elm$ = oldVNode.$elm$ = (hostElm);
1158
+ useNativeShadowDom = (cmpMeta.$flags$ & 1 /* CMP_FLAGS.shadowDomEncapsulation */) !== 0;
985
1159
  {
986
1160
  contentRef = hostElm['s-cr'];
987
- useNativeShadowDom = (cmpMeta.$flags$ & 1 /* CMP_FLAGS.shadowDomEncapsulation */) !== 0;
988
1161
  // always reset
989
1162
  checkSlotFallbackVisibility = false;
990
1163
  }
991
1164
  // synchronous patch
992
- patch(oldVNode, rootVnode);
1165
+ patch(oldVNode, rootVnode, isInitialLoad);
993
1166
  {
994
1167
  // while we're moving nodes around existing nodes, temporarily disable
995
1168
  // the disconnectCallback from working
996
1169
  plt.$flags$ |= 1 /* PLATFORM_FLAGS.isTmpDisconnected */;
997
1170
  if (checkSlotRelocate) {
998
- relocateSlotContent(rootVnode.$elm$);
999
- let relocateData;
1000
- let nodeToRelocate;
1001
- let orgLocationNode;
1002
- let parentNodeRef;
1003
- let insertBeforeNode;
1004
- let refNode;
1005
- let i = 0;
1006
- for (; i < relocateNodes.length; i++) {
1007
- relocateData = relocateNodes[i];
1008
- nodeToRelocate = relocateData.$nodeToRelocate$;
1171
+ markSlotContentForRelocation(rootVnode.$elm$);
1172
+ for (const relocateData of relocateNodes) {
1173
+ const nodeToRelocate = relocateData.$nodeToRelocate$;
1009
1174
  if (!nodeToRelocate['s-ol']) {
1010
1175
  // add a reference node marking this node's original location
1011
1176
  // keep a reference to this node for later lookups
1012
- orgLocationNode =
1013
- doc.createTextNode('');
1177
+ const orgLocationNode = doc.createTextNode('');
1014
1178
  orgLocationNode['s-nr'] = nodeToRelocate;
1015
1179
  nodeToRelocate.parentNode.insertBefore((nodeToRelocate['s-ol'] = orgLocationNode), nodeToRelocate);
1016
1180
  }
1017
1181
  }
1018
- for (i = 0; i < relocateNodes.length; i++) {
1019
- relocateData = relocateNodes[i];
1020
- nodeToRelocate = relocateData.$nodeToRelocate$;
1021
- if (relocateData.$slotRefNode$) {
1022
- // by default we're just going to insert it directly
1023
- // after the slot reference node
1024
- parentNodeRef = relocateData.$slotRefNode$.parentNode;
1025
- insertBeforeNode = relocateData.$slotRefNode$.nextSibling;
1026
- orgLocationNode = nodeToRelocate['s-ol'];
1027
- while ((orgLocationNode = orgLocationNode.previousSibling)) {
1028
- refNode = orgLocationNode['s-nr'];
1029
- if (refNode && refNode['s-sn'] === nodeToRelocate['s-sn'] && parentNodeRef === refNode.parentNode) {
1030
- refNode = refNode.nextSibling;
1031
- if (!refNode || !refNode['s-nr']) {
1032
- insertBeforeNode = refNode;
1033
- break;
1182
+ for (const relocateData of relocateNodes) {
1183
+ const nodeToRelocate = relocateData.$nodeToRelocate$;
1184
+ const slotRefNode = relocateData.$slotRefNode$;
1185
+ if (slotRefNode) {
1186
+ const parentNodeRef = slotRefNode.parentNode;
1187
+ // When determining where to insert content, the most simple case would be
1188
+ // to relocate the node immediately following the slot reference node. We do this
1189
+ // by getting a reference to the node immediately following the slot reference node
1190
+ // since we will use `insertBefore` to manipulate the DOM.
1191
+ //
1192
+ // If there is no node immediately following the slot reference node, then we will just
1193
+ // end up appending the node as the last child of the parent.
1194
+ let insertBeforeNode = slotRefNode.nextSibling;
1195
+ // If the node we're currently planning on inserting the new node before is an element,
1196
+ // we need to do some additional checks to make sure we're inserting the node in the correct order.
1197
+ // The use case here would be that we have multiple nodes being relocated to the same slot. So, we want
1198
+ // to make sure they get inserted into their new how in the same order they were declared in their original location.
1199
+ //
1200
+ // TODO(STENCIL-914): Remove `experimentalSlotFixes` check
1201
+ {
1202
+ let orgLocationNode = (_a = nodeToRelocate['s-ol']) === null || _a === void 0 ? void 0 : _a.previousSibling;
1203
+ while (orgLocationNode) {
1204
+ let refNode = (_b = orgLocationNode['s-nr']) !== null && _b !== void 0 ? _b : null;
1205
+ if (refNode && refNode['s-sn'] === nodeToRelocate['s-sn'] && parentNodeRef === refNode.parentNode) {
1206
+ refNode = refNode.nextSibling;
1207
+ if (!refNode || !refNode['s-nr']) {
1208
+ insertBeforeNode = refNode;
1209
+ break;
1210
+ }
1034
1211
  }
1212
+ orgLocationNode = orgLocationNode.previousSibling;
1035
1213
  }
1036
1214
  }
1037
1215
  if ((!insertBeforeNode && parentNodeRef !== nodeToRelocate.parentNode) ||
@@ -1041,17 +1219,32 @@ const renderVdom = (hostRef, renderFnResults) => {
1041
1219
  // has a different next sibling or parent relocated
1042
1220
  if (nodeToRelocate !== insertBeforeNode) {
1043
1221
  if (!nodeToRelocate['s-hn'] && nodeToRelocate['s-ol']) {
1044
- // probably a component in the index.html that doesn't have it's hostname set
1222
+ // probably a component in the index.html that doesn't have its hostname set
1045
1223
  nodeToRelocate['s-hn'] = nodeToRelocate['s-ol'].parentNode.nodeName;
1046
1224
  }
1047
- // add it back to the dom but in its new home
1225
+ // Add it back to the dom but in its new home
1226
+ // If we get to this point and `insertBeforeNode` is `null`, that means
1227
+ // we're just going to append the node as the last child of the parent. Passing
1228
+ // `null` as the second arg here will trigger that behavior.
1048
1229
  parentNodeRef.insertBefore(nodeToRelocate, insertBeforeNode);
1230
+ // Reset the `hidden` value back to what it was defined as originally
1231
+ // This solves a problem where a `slot` is dynamically rendered and `hidden` may have
1232
+ // been set on content originally, but now it has a slot to go to so it should have
1233
+ // the value it was defined as having in the DOM, not what we overrode it to.
1234
+ if (nodeToRelocate.nodeType === 1 /* NODE_TYPE.ElementNode */) {
1235
+ nodeToRelocate.hidden = (_c = nodeToRelocate['s-ih']) !== null && _c !== void 0 ? _c : false;
1236
+ }
1049
1237
  }
1050
1238
  }
1051
1239
  }
1052
1240
  else {
1053
1241
  // this node doesn't have a slot home to go to, so let's hide it
1054
1242
  if (nodeToRelocate.nodeType === 1 /* NODE_TYPE.ElementNode */) {
1243
+ // Store the initial value of `hidden` so we can reset it later when
1244
+ // moving nodes around.
1245
+ if (isInitialLoad) {
1246
+ nodeToRelocate['s-ih'] = (_d = nodeToRelocate.hidden) !== null && _d !== void 0 ? _d : false;
1247
+ }
1055
1248
  nodeToRelocate.hidden = true;
1056
1249
  }
1057
1250
  }
@@ -1066,6 +1259,8 @@ const renderVdom = (hostRef, renderFnResults) => {
1066
1259
  // always reset
1067
1260
  relocateNodes.length = 0;
1068
1261
  }
1262
+ // Clear the content ref so we don't create a memory leak
1263
+ contentRef = undefined;
1069
1264
  };
1070
1265
  const attachToAncestor = (hostRef, ancestorComponent) => {
1071
1266
  if (ancestorComponent && !hostRef.$onRenderResolve$ && ancestorComponent['s-p']) {
@@ -1145,6 +1340,16 @@ const enqueue = (maybePromise, fn) => isPromisey(maybePromise) ? maybePromise.th
1145
1340
  */
1146
1341
  const isPromisey = (maybePromise) => maybePromise instanceof Promise ||
1147
1342
  (maybePromise && maybePromise.then && typeof maybePromise.then === 'function');
1343
+ /**
1344
+ * Update a component given reference to its host elements and so on.
1345
+ *
1346
+ * @param hostRef an object containing references to the element's host node,
1347
+ * VDom nodes, and other metadata
1348
+ * @param instance a reference to the underlying host element where it will be
1349
+ * rendered
1350
+ * @param isInitialLoad whether or not this function is being called as part of
1351
+ * the first render cycle
1352
+ */
1148
1353
  const updateComponent = async (hostRef, instance, isInitialLoad) => {
1149
1354
  var _a;
1150
1355
  const elm = hostRef.$hostElement$;
@@ -1156,7 +1361,7 @@ const updateComponent = async (hostRef, instance, isInitialLoad) => {
1156
1361
  }
1157
1362
  const endRender = createTime('render', hostRef.$cmpMeta$.$tagName$);
1158
1363
  {
1159
- callRender(hostRef, instance);
1364
+ callRender(hostRef, instance, elm, isInitialLoad);
1160
1365
  }
1161
1366
  if (rc) {
1162
1367
  // ok, so turns out there are some child host elements
@@ -1180,8 +1385,24 @@ const updateComponent = async (hostRef, instance, isInitialLoad) => {
1180
1385
  }
1181
1386
  }
1182
1387
  };
1183
- const callRender = (hostRef, instance, elm) => {
1388
+ /**
1389
+ * Handle making the call to the VDom renderer with the proper context given
1390
+ * various build variables
1391
+ *
1392
+ * @param hostRef an object containing references to the element's host node,
1393
+ * VDom nodes, and other metadata
1394
+ * @param instance a reference to the underlying host element where it will be
1395
+ * rendered
1396
+ * @param elm the Host element for the component
1397
+ * @param isInitialLoad whether or not this function is being called as part of
1398
+ * @returns an empty promise
1399
+ */
1400
+ const callRender = (hostRef, instance, elm, isInitialLoad) => {
1184
1401
  try {
1402
+ /**
1403
+ * minification optimization: `allRenderFn` is `true` if all components have a `render`
1404
+ * method, so we can call the method immediately. If not, check before calling it.
1405
+ */
1185
1406
  instance = instance.render() ;
1186
1407
  {
1187
1408
  hostRef.$flags$ &= ~16 /* HOST_FLAGS.isQueuedForUpdate */;
@@ -1195,7 +1416,7 @@ const callRender = (hostRef, instance, elm) => {
1195
1416
  // or we need to update the css class/attrs on the host element
1196
1417
  // DOM WRITE!
1197
1418
  {
1198
- renderVdom(hostRef, instance);
1419
+ renderVdom(hostRef, instance, isInitialLoad);
1199
1420
  }
1200
1421
  }
1201
1422
  }
@@ -1255,6 +1476,16 @@ const appDidLoad = (who) => {
1255
1476
  }
1256
1477
  nextTick(() => emitEvent(win, 'appload', { detail: { namespace: NAMESPACE } }));
1257
1478
  };
1479
+ /**
1480
+ * Allows to safely call a method, e.g. `componentDidLoad`, on an instance,
1481
+ * e.g. custom element node. If a build figures out that e.g. no component
1482
+ * has a `componentDidLoad` method, the instance method gets removed from the
1483
+ * output bundle and this function returns `undefined`.
1484
+ * @param instance any object that may or may not contain methods
1485
+ * @param method method name
1486
+ * @param arg single arbitrary argument
1487
+ * @returns result of method call if it exists, otherwise `undefined`
1488
+ */
1258
1489
  const safeCall = (instance, method, arg) => {
1259
1490
  if (instance && instance[method]) {
1260
1491
  try {
@@ -1305,10 +1536,11 @@ const setValue = (ref, propName, newVal, cmpMeta) => {
1305
1536
  * @returns a reference to the same constructor passed in (but now mutated)
1306
1537
  */
1307
1538
  const proxyComponent = (Cstr, cmpMeta, flags) => {
1539
+ var _a;
1540
+ const prototype = Cstr.prototype;
1308
1541
  if (cmpMeta.$members$) {
1309
1542
  // It's better to have a const than two Object.entries()
1310
1543
  const members = Object.entries(cmpMeta.$members$);
1311
- const prototype = Cstr.prototype;
1312
1544
  members.map(([memberName, [memberFlags]]) => {
1313
1545
  if ((memberFlags & 31 /* MEMBER_FLAGS.Prop */ ||
1314
1546
  ((flags & 2 /* PROXY_FLAGS.proxyState */) && memberFlags & 32 /* MEMBER_FLAGS.State */))) {
@@ -1329,8 +1561,9 @@ const proxyComponent = (Cstr, cmpMeta, flags) => {
1329
1561
  });
1330
1562
  if ((flags & 1 /* PROXY_FLAGS.isElementConstructor */)) {
1331
1563
  const attrNameToPropName = new Map();
1332
- prototype.attributeChangedCallback = function (attrName, _oldValue, newValue) {
1564
+ prototype.attributeChangedCallback = function (attrName, oldValue, newValue) {
1333
1565
  plt.jmp(() => {
1566
+ var _a;
1334
1567
  const propName = attrNameToPropName.get(attrName);
1335
1568
  // In a web component lifecycle the attributeChangedCallback runs prior to connectedCallback
1336
1569
  // in the case where an attribute was set inline.
@@ -1352,12 +1585,12 @@ const proxyComponent = (Cstr, cmpMeta, flags) => {
1352
1585
  // customElements.define('my-component', MyComponent);
1353
1586
  // </script>
1354
1587
  // ```
1355
- // In this case if we do not unshadow here and use the value of the shadowing property, attributeChangedCallback
1588
+ // In this case if we do not un-shadow here and use the value of the shadowing property, attributeChangedCallback
1356
1589
  // will be called with `newValue = "some-value"` and will set the shadowed property (this.someAttribute = "another-value")
1357
1590
  // to the value that was set inline i.e. "some-value" from above example. When
1358
- // the connectedCallback attempts to unshadow it will use "some-value" as the initial value rather than "another-value"
1591
+ // the connectedCallback attempts to un-shadow it will use "some-value" as the initial value rather than "another-value"
1359
1592
  //
1360
- // The case where the attribute was NOT set inline but was not set programmatically shall be handled/unshadowed
1593
+ // The case where the attribute was NOT set inline but was not set programmatically shall be handled/un-shadowed
1361
1594
  // by connectedCallback as this attributeChangedCallback will not fire.
1362
1595
  //
1363
1596
  // https://developers.google.com/web/fundamentals/web-components/best-practices#lazy-properties
@@ -1377,26 +1610,67 @@ const proxyComponent = (Cstr, cmpMeta, flags) => {
1377
1610
  // `propName` to be converted to a `DOMString`, which may not be what we want for other primitive props.
1378
1611
  return;
1379
1612
  }
1613
+ else if (propName == null) {
1614
+ // At this point we should know this is not a "member", so we can treat it like watching an attribute
1615
+ // on a vanilla web component
1616
+ const hostRef = getHostRef(this);
1617
+ const flags = hostRef === null || hostRef === void 0 ? void 0 : hostRef.$flags$;
1618
+ // We only want to trigger the callback(s) if:
1619
+ // 1. The instance is ready
1620
+ // 2. The watchers are ready
1621
+ // 3. The value has changed
1622
+ if (flags &&
1623
+ !(flags & 8 /* HOST_FLAGS.isConstructingInstance */) &&
1624
+ flags & 128 /* HOST_FLAGS.isWatchReady */ &&
1625
+ newValue !== oldValue) {
1626
+ const instance = hostRef.$lazyInstance$ ;
1627
+ const entry = (_a = cmpMeta.$watchers$) === null || _a === void 0 ? void 0 : _a[attrName];
1628
+ entry === null || entry === void 0 ? void 0 : entry.forEach((callbackName) => {
1629
+ if (instance[callbackName] != null) {
1630
+ instance[callbackName].call(instance, newValue, oldValue, attrName);
1631
+ }
1632
+ });
1633
+ }
1634
+ return;
1635
+ }
1380
1636
  this[propName] = newValue === null && typeof this[propName] === 'boolean' ? false : newValue;
1381
1637
  });
1382
1638
  };
1383
- // create an array of attributes to observe
1384
- // and also create a map of html attribute name to js property name
1385
- Cstr.observedAttributes = members
1386
- .filter(([_, m]) => m[0] & 15 /* MEMBER_FLAGS.HasAttribute */) // filter to only keep props that should match attributes
1387
- .map(([propName, m]) => {
1388
- const attrName = m[1] || propName;
1389
- attrNameToPropName.set(attrName, propName);
1390
- if (m[0] & 512 /* MEMBER_FLAGS.ReflectAttr */) {
1391
- cmpMeta.$attrsToReflect$.push([propName, attrName]);
1392
- }
1393
- return attrName;
1394
- });
1639
+ // Create an array of attributes to observe
1640
+ // This list in comprised of all strings used within a `@Watch()` decorator
1641
+ // on a component as well as any Stencil-specific "members" (`@Prop()`s and `@State()`s).
1642
+ // As such, there is no way to guarantee type-safety here that a user hasn't entered
1643
+ // an invalid attribute.
1644
+ Cstr.observedAttributes = Array.from(new Set([
1645
+ ...Object.keys((_a = cmpMeta.$watchers$) !== null && _a !== void 0 ? _a : {}),
1646
+ ...members
1647
+ .filter(([_, m]) => m[0] & 15 /* MEMBER_FLAGS.HasAttribute */)
1648
+ .map(([propName, m]) => {
1649
+ var _a;
1650
+ const attrName = m[1] || propName;
1651
+ attrNameToPropName.set(attrName, propName);
1652
+ if (m[0] & 512 /* MEMBER_FLAGS.ReflectAttr */) {
1653
+ (_a = cmpMeta.$attrsToReflect$) === null || _a === void 0 ? void 0 : _a.push([propName, attrName]);
1654
+ }
1655
+ return attrName;
1656
+ }),
1657
+ ]));
1395
1658
  }
1396
1659
  }
1397
1660
  return Cstr;
1398
1661
  };
1399
- const initializeComponent = async (elm, hostRef, cmpMeta, hmrVersionId, Cstr) => {
1662
+ /**
1663
+ * Initialize a Stencil component given a reference to its host element, its
1664
+ * runtime bookkeeping data structure, runtime metadata about the component,
1665
+ * and (optionally) an HMR version ID.
1666
+ *
1667
+ * @param elm a host element
1668
+ * @param hostRef the element's runtime bookkeeping object
1669
+ * @param cmpMeta runtime metadata for the Stencil component
1670
+ * @param hmrVersionId an (optional) HMR version ID
1671
+ */
1672
+ const initializeComponent = async (elm, hostRef, cmpMeta, hmrVersionId) => {
1673
+ let Cstr;
1400
1674
  // initializeComponent
1401
1675
  if ((hostRef.$flags$ & 32 /* HOST_FLAGS.hasInitializedComponent */) === 0) {
1402
1676
  // Let the runtime know that the component has been initialized
@@ -1465,6 +1739,8 @@ const initializeComponent = async (elm, hostRef, cmpMeta, hmrVersionId, Cstr) =>
1465
1739
  schedule();
1466
1740
  }
1467
1741
  };
1742
+ const fireConnectedCallback = (instance) => {
1743
+ };
1468
1744
  const connectedCallback = (elm) => {
1469
1745
  if ((plt.$flags$ & 1 /* PLATFORM_FLAGS.isTmpDisconnected */) === 0) {
1470
1746
  const hostRef = getHostRef(elm);
@@ -1513,6 +1789,13 @@ const connectedCallback = (elm) => {
1513
1789
  initializeComponent(elm, hostRef, cmpMeta);
1514
1790
  }
1515
1791
  }
1792
+ else {
1793
+ // fire off connectedCallback() on component instance
1794
+ if (hostRef === null || hostRef === void 0 ? void 0 : hostRef.$lazyInstance$) ;
1795
+ else if (hostRef === null || hostRef === void 0 ? void 0 : hostRef.$onReadyPromise$) {
1796
+ hostRef.$onReadyPromise$.then(() => fireConnectedCallback());
1797
+ }
1798
+ }
1516
1799
  endConnected();
1517
1800
  }
1518
1801
  };
@@ -1527,9 +1810,15 @@ const setContentReference = (elm) => {
1527
1810
  contentRefElm['s-cn'] = true;
1528
1811
  elm.insertBefore(contentRefElm, elm.firstChild);
1529
1812
  };
1530
- const disconnectedCallback = (elm) => {
1813
+ const disconnectInstance = (instance) => {
1814
+ };
1815
+ const disconnectedCallback = async (elm) => {
1531
1816
  if ((plt.$flags$ & 1 /* PLATFORM_FLAGS.isTmpDisconnected */) === 0) {
1532
- getHostRef(elm);
1817
+ const hostRef = getHostRef(elm);
1818
+ if (hostRef === null || hostRef === void 0 ? void 0 : hostRef.$lazyInstance$) ;
1819
+ else if (hostRef === null || hostRef === void 0 ? void 0 : hostRef.$onReadyPromise$) {
1820
+ hostRef.$onReadyPromise$.then(() => disconnectInstance());
1821
+ }
1533
1822
  }
1534
1823
  };
1535
1824
  const bootstrapLazy = (lazyBundles, options = {}) => {
@@ -1540,12 +1829,13 @@ const bootstrapLazy = (lazyBundles, options = {}) => {
1540
1829
  const customElements = win.customElements;
1541
1830
  const head = doc.head;
1542
1831
  const metaCharset = /*@__PURE__*/ head.querySelector('meta[charset]');
1543
- const visibilityStyle = /*@__PURE__*/ doc.createElement('style');
1832
+ const dataStyles = /*@__PURE__*/ doc.createElement('style');
1544
1833
  const deferredConnectedCallbacks = [];
1545
1834
  let appLoadFallback;
1546
1835
  let isBootstrapping = true;
1547
1836
  Object.assign(plt, options);
1548
1837
  plt.$resourcesUrl$ = new URL(options.resourcesUrl || './', doc.baseURI).href;
1838
+ let hasSlotRelocation = false;
1549
1839
  lazyBundles.map((lazyBundle) => {
1550
1840
  lazyBundle[1].map((compactMeta) => {
1551
1841
  const cmpMeta = {
@@ -1554,6 +1844,11 @@ const bootstrapLazy = (lazyBundles, options = {}) => {
1554
1844
  $members$: compactMeta[2],
1555
1845
  $listeners$: compactMeta[3],
1556
1846
  };
1847
+ // Check if we are using slots outside the shadow DOM in this component.
1848
+ // We'll use this information later to add styles for `slot-fb` elements
1849
+ if (cmpMeta.$flags$ & 4 /* CMP_FLAGS.hasSlotRelocation */) {
1850
+ hasSlotRelocation = true;
1851
+ }
1557
1852
  {
1558
1853
  cmpMeta.$members$ = compactMeta[2];
1559
1854
  }
@@ -1596,15 +1891,29 @@ const bootstrapLazy = (lazyBundles, options = {}) => {
1596
1891
  }
1597
1892
  });
1598
1893
  });
1599
- {
1600
- visibilityStyle.innerHTML = cmpTags + HYDRATED_CSS;
1601
- visibilityStyle.setAttribute('data-styles', '');
1602
- // Apply CSP nonce to the style tag if it exists
1603
- const nonce = (_a = plt.$nonce$) !== null && _a !== void 0 ? _a : queryNonceMetaTagContent(doc);
1604
- if (nonce != null) {
1605
- visibilityStyle.setAttribute('nonce', nonce);
1894
+ // Only bother generating CSS if we have components
1895
+ // TODO(STENCIL-1118): Add test cases for CSS content based on conditionals
1896
+ if (cmpTags.length > 0) {
1897
+ // Add styles for `slot-fb` elements if any of our components are using slots outside the Shadow DOM
1898
+ if (hasSlotRelocation) {
1899
+ dataStyles.textContent += SLOT_FB_CSS;
1900
+ }
1901
+ // Add hydration styles
1902
+ {
1903
+ dataStyles.textContent += cmpTags + HYDRATED_CSS;
1904
+ }
1905
+ // If we have styles, add them to the DOM
1906
+ if (dataStyles.innerHTML.length) {
1907
+ dataStyles.setAttribute('data-styles', '');
1908
+ // Apply CSP nonce to the style tag if it exists
1909
+ const nonce = (_a = plt.$nonce$) !== null && _a !== void 0 ? _a : queryNonceMetaTagContent(doc);
1910
+ if (nonce != null) {
1911
+ dataStyles.setAttribute('nonce', nonce);
1912
+ }
1913
+ // Insert the styles into the document head
1914
+ // NOTE: this _needs_ to happen last so we can ensure the nonce (and other attributes) are applied
1915
+ head.insertBefore(dataStyles, metaCharset ? metaCharset.nextSibling : head.firstChild);
1606
1916
  }
1607
- head.insertBefore(visibilityStyle, metaCharset ? metaCharset.nextSibling : head.firstChild);
1608
1917
  }
1609
1918
  // Process deferred connectedCallbacks now all components have been registered
1610
1919
  isBootstrapping = false;
@@ -1626,22 +1935,60 @@ const bootstrapLazy = (lazyBundles, options = {}) => {
1626
1935
  * @returns void
1627
1936
  */
1628
1937
  const setNonce = (nonce) => (plt.$nonce$ = nonce);
1629
- const hostRefs = /*@__PURE__*/ new WeakMap();
1938
+ /**
1939
+ * A WeakMap mapping runtime component references to their corresponding host reference
1940
+ * instances.
1941
+ *
1942
+ * **Note**: If we're in an HMR context we need to store a reference to this
1943
+ * value on `window` in order to maintain the mapping of {@link d.RuntimeRef}
1944
+ * to {@link d.HostRef} across HMR updates.
1945
+ *
1946
+ * This is necessary because when HMR updates for a component are processed by
1947
+ * the browser-side dev server client the JS bundle for that component is
1948
+ * re-fetched. Since the module containing {@link hostRefs} is included in
1949
+ * that bundle, if we do not store a reference to it the new iteration of the
1950
+ * component will not have access to the previous hostRef map, leading to a
1951
+ * bug where the new version of the component cannot properly initialize.
1952
+ */
1953
+ const hostRefs = new WeakMap();
1954
+ /**
1955
+ * Given a {@link d.RuntimeRef} retrieve the corresponding {@link d.HostRef}
1956
+ *
1957
+ * @param ref the runtime ref of interest
1958
+ * @returns the Host reference (if found) or undefined
1959
+ */
1630
1960
  const getHostRef = (ref) => hostRefs.get(ref);
1961
+ /**
1962
+ * Register a lazy instance with the {@link hostRefs} object so it's
1963
+ * corresponding {@link d.HostRef} can be retrieved later.
1964
+ *
1965
+ * @param lazyInstance the lazy instance of interest
1966
+ * @param hostRef that instances `HostRef` object
1967
+ * @returns a reference to the host ref WeakMap
1968
+ */
1631
1969
  const registerInstance = (lazyInstance, hostRef) => hostRefs.set((hostRef.$lazyInstance$ = lazyInstance), hostRef);
1632
- const registerHost = (elm, cmpMeta) => {
1970
+ /**
1971
+ * Register a host element for a Stencil component, setting up various metadata
1972
+ * and callbacks based on {@link BUILD} flags as well as the component's runtime
1973
+ * metadata.
1974
+ *
1975
+ * @param hostElement the host element to register
1976
+ * @param cmpMeta runtime metadata for that component
1977
+ * @returns a reference to the host ref WeakMap
1978
+ */
1979
+ const registerHost = (hostElement, cmpMeta) => {
1633
1980
  const hostRef = {
1634
1981
  $flags$: 0,
1635
- $hostElement$: elm,
1982
+ $hostElement$: hostElement,
1636
1983
  $cmpMeta$: cmpMeta,
1637
1984
  $instanceValues$: new Map(),
1638
1985
  };
1639
1986
  {
1640
1987
  hostRef.$onReadyPromise$ = new Promise((r) => (hostRef.$onReadyResolve$ = r));
1641
- elm['s-p'] = [];
1642
- elm['s-rc'] = [];
1988
+ hostElement['s-p'] = [];
1989
+ hostElement['s-rc'] = [];
1643
1990
  }
1644
- return hostRefs.set(elm, hostRef);
1991
+ return hostRefs.set(hostElement, hostRef);
1645
1992
  };
1646
1993
  const isMemberInElement = (elm, memberName) => memberName in elm;
1647
1994
  const consoleError = (e, el) => (0, console.error)(e, el);
@@ -1729,9 +2076,9 @@ const flush = () => {
1729
2076
  }
1730
2077
  }
1731
2078
  };
1732
- const nextTick = /*@__PURE__*/ (cb) => promiseResolve().then(cb);
2079
+ const nextTick = (cb) => promiseResolve().then(cb);
1733
2080
  const writeTask = /*@__PURE__*/ queueTask(queueDomWrites, true);
1734
2081
 
1735
2082
  export { Host as H, bootstrapLazy as b, h, promiseResolve as p, registerInstance as r, setNonce as s };
1736
2083
 
1737
- //# sourceMappingURL=index-ad69454c.js.map
2084
+ //# sourceMappingURL=index-b0176170.js.map