@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
@@ -21,6 +21,7 @@ function _interopNamespace(e) {
21
21
  }
22
22
 
23
23
  const NAMESPACE = 'jump-design-system';
24
+ 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 };
24
25
 
25
26
  /**
26
27
  * Virtual DOM patching algorithm based on Snabbdom by
@@ -52,6 +53,13 @@ const uniqueTime = (key, measureText) => {
52
53
  }
53
54
  };
54
55
  const HYDRATED_CSS = '{visibility:hidden}.hydrated{visibility:inherit}';
56
+ /**
57
+ * Constant for styles to be globally applied to `slot-fb` elements for pseudo-slot behavior.
58
+ *
59
+ * Two cascading rules must be used instead of a `:not()` selector due to Stencil browser
60
+ * support as of Stencil v4.
61
+ */
62
+ const SLOT_FB_CSS = 'slot-fb{display:contents}slot-fb[hidden]{display:none}';
55
63
  /**
56
64
  * Default style mode id
57
65
  */
@@ -96,6 +104,7 @@ function queryNonceMetaTagContent(doc) {
96
104
  // export function h(nodeName: string | d.FunctionalComponent, vnodeData: d.PropsType, ...children: d.ChildType[]): d.VNode;
97
105
  const h = (nodeName, vnodeData, ...children) => {
98
106
  let child = null;
107
+ let key = null;
99
108
  let slotName = null;
100
109
  let simple = false;
101
110
  let lastSimple = false;
@@ -124,9 +133,13 @@ const h = (nodeName, vnodeData, ...children) => {
124
133
  };
125
134
  walk(children);
126
135
  if (vnodeData) {
136
+ if (vnodeData.key) {
137
+ key = vnodeData.key;
138
+ }
127
139
  if (vnodeData.name) {
128
140
  slotName = vnodeData.name;
129
141
  }
142
+ // normalize class / className attributes
130
143
  {
131
144
  const classData = vnodeData.className || vnodeData.class;
132
145
  if (classData) {
@@ -144,6 +157,9 @@ const h = (nodeName, vnodeData, ...children) => {
144
157
  if (vNodeChildren.length > 0) {
145
158
  vnode.$children$ = vNodeChildren;
146
159
  }
160
+ {
161
+ vnode.$key$ = key;
162
+ }
147
163
  {
148
164
  vnode.$name$ = slotName;
149
165
  }
@@ -168,6 +184,9 @@ const newVNode = (tag, text) => {
168
184
  {
169
185
  vnode.$attrs$ = null;
170
186
  }
187
+ {
188
+ vnode.$key$ = null;
189
+ }
171
190
  {
172
191
  vnode.$name$ = null;
173
192
  }
@@ -283,6 +302,10 @@ const addStyle = (styleContainerNode, cmpMeta, mode) => {
283
302
  }
284
303
  styleContainerNode.insertBefore(styleElm, styleContainerNode.querySelector('link'));
285
304
  }
305
+ // Add styles for `slot-fb` elements if we're using slots outside the Shadow DOM
306
+ if (cmpMeta.$flags$ & 4 /* CMP_FLAGS.hasSlotRelocation */) {
307
+ styleElm.innerHTML += SLOT_FB_CSS;
308
+ }
286
309
  if (appliedStyles) {
287
310
  appliedStyles.add(scopeId);
288
311
  }
@@ -310,6 +333,21 @@ const getScopeId = (cmp, mode) => 'sc-' + (cmp.$tagName$);
310
333
  *
311
334
  * Modified for Stencil's compiler and vdom
312
335
  */
336
+ /**
337
+ * When running a VDom render set properties present on a VDom node onto the
338
+ * corresponding HTML element.
339
+ *
340
+ * Note that this function has special functionality for the `class`,
341
+ * `style`, `key`, and `ref` attributes, as well as event handlers (like
342
+ * `onClick`, etc). All others are just passed through as-is.
343
+ *
344
+ * @param elm the HTMLElement onto which attributes should be set
345
+ * @param memberName the name of the attribute to set
346
+ * @param oldValue the old value for the attribute
347
+ * @param newValue the new value for the attribute
348
+ * @param isSvg whether we're in an svg context or not
349
+ * @param flags bitflags for Vdom variables
350
+ */
313
351
  const setAccessor = (elm, memberName, oldValue, newValue, isSvg, flags) => {
314
352
  if (oldValue !== newValue) {
315
353
  let isProp = isMemberInElement(elm, memberName);
@@ -321,6 +359,8 @@ const setAccessor = (elm, memberName, oldValue, newValue, isSvg, flags) => {
321
359
  classList.remove(...oldClasses.filter((c) => c && !newClasses.includes(c)));
322
360
  classList.add(...newClasses.filter((c) => c && !oldClasses.includes(c)));
323
361
  }
362
+ else if (memberName === 'key')
363
+ ;
324
364
  else {
325
365
  // Set property if it exists and it's not a SVG
326
366
  const isComplex = isComplexType(newValue);
@@ -340,7 +380,11 @@ const setAccessor = (elm, memberName, oldValue, newValue, isSvg, flags) => {
340
380
  elm[memberName] = newValue;
341
381
  }
342
382
  }
343
- catch (e) { }
383
+ catch (e) {
384
+ /**
385
+ * in case someone tries to set a read-only property, e.g. "namespaceURI", we just ignore it
386
+ */
387
+ }
344
388
  }
345
389
  if (newValue == null || newValue === false) {
346
390
  if (newValue !== false || elm.getAttribute(memberName) === '') {
@@ -359,6 +403,11 @@ const setAccessor = (elm, memberName, oldValue, newValue, isSvg, flags) => {
359
403
  }
360
404
  };
361
405
  const parseClassListRegex = /\s/;
406
+ /**
407
+ * Parsed a string of classnames into an array
408
+ * @param value className string, e.g. "foo bar baz"
409
+ * @returns list of classes, e.g. ["foo", "bar", "baz"]
410
+ */
362
411
  const parseClassList = (value) => (!value ? [] : value.split(parseClassListRegex));
363
412
  const updateElement = (oldVnode, newVnode, isSvgMode, memberName) => {
364
413
  // if the element passed in is a shadow root, which is a document fragment
@@ -440,8 +489,10 @@ const createElm = (oldParentVNode, newParentVNode, childIndex, parentElm) => {
440
489
  }
441
490
  }
442
491
  }
492
+ // This needs to always happen so we can hide nodes that are projected
493
+ // to another component but don't end up in a slot
494
+ elm['s-hn'] = hostTagName;
443
495
  {
444
- elm['s-hn'] = hostTagName;
445
496
  if (newVNode.$flags$ & (2 /* VNODE_FLAGS.isSlotFallback */ | 1 /* VNODE_FLAGS.isSlotReference */)) {
446
497
  // remember the content reference comment
447
498
  elm['s-sr'] = true;
@@ -452,9 +503,11 @@ const createElm = (oldParentVNode, newParentVNode, childIndex, parentElm) => {
452
503
  // check if we've got an old vnode for this slot
453
504
  oldVNode = oldParentVNode && oldParentVNode.$children$ && oldParentVNode.$children$[childIndex];
454
505
  if (oldVNode && oldVNode.$tag$ === newVNode.$tag$ && oldParentVNode.$elm$) {
455
- // we've got an old slot vnode and the wrapper is being replaced
456
- // so let's move the old slot content back to it's original location
457
- putBackInOriginalLocation(oldParentVNode.$elm$, false);
506
+ {
507
+ // we've got an old slot vnode and the wrapper is being replaced
508
+ // so let's move the old slot content back to its original location
509
+ putBackInOriginalLocation(oldParentVNode.$elm$, false);
510
+ }
458
511
  }
459
512
  }
460
513
  }
@@ -466,16 +519,15 @@ const putBackInOriginalLocation = (parentElm, recursive) => {
466
519
  for (let i = oldSlotChildNodes.length - 1; i >= 0; i--) {
467
520
  const childNode = oldSlotChildNodes[i];
468
521
  if (childNode['s-hn'] !== hostTagName && childNode['s-ol']) {
469
- // // this child node in the old element is from another component
470
- // // remove this node from the old slot's parent
471
- // childNode.remove();
472
522
  // and relocate it back to it's original location
473
523
  parentReferenceNode(childNode).insertBefore(childNode, referenceNode(childNode));
474
524
  // remove the old original location comment entirely
475
525
  // later on the patch function will know what to do
476
- // and move this to the correct spot in need be
526
+ // and move this to the correct spot if need be
477
527
  childNode['s-ol'].remove();
478
528
  childNode['s-ol'] = undefined;
529
+ // Reset so we can correctly move the node around again.
530
+ childNode['s-sh'] = undefined;
479
531
  checkSlotRelocate = true;
480
532
  }
481
533
  if (recursive) {
@@ -616,10 +668,13 @@ const removeVnodes = (vnodes, startIdx, endIdx) => {
616
668
  * @param oldCh the old children of the parent node
617
669
  * @param newVNode the new VNode which will replace the parent
618
670
  * @param newCh the new children of the parent node
671
+ * @param isInitialRender whether or not this is the first render of the vdom
619
672
  */
620
- const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
673
+ const updateChildren = (parentElm, oldCh, newVNode, newCh, isInitialRender = false) => {
621
674
  let oldStartIdx = 0;
622
675
  let newStartIdx = 0;
676
+ let idxInOld = 0;
677
+ let i = 0;
623
678
  let oldEndIdx = oldCh.length - 1;
624
679
  let oldStartVnode = oldCh[0];
625
680
  let oldEndVnode = oldCh[oldEndIdx];
@@ -627,6 +682,7 @@ const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
627
682
  let newStartVnode = newCh[0];
628
683
  let newEndVnode = newCh[newEndIdx];
629
684
  let node;
685
+ let elmToMove;
630
686
  while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
631
687
  if (oldStartVnode == null) {
632
688
  // VNode might have been moved left
@@ -641,24 +697,24 @@ const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
641
697
  else if (newEndVnode == null) {
642
698
  newEndVnode = newCh[--newEndIdx];
643
699
  }
644
- else if (isSameVnode(oldStartVnode, newStartVnode)) {
700
+ else if (isSameVnode(oldStartVnode, newStartVnode, isInitialRender)) {
645
701
  // if the start nodes are the same then we should patch the new VNode
646
702
  // onto the old one, and increment our `newStartIdx` and `oldStartIdx`
647
703
  // indices to reflect that. We don't need to move any DOM Nodes around
648
704
  // since things are matched up in order.
649
- patch(oldStartVnode, newStartVnode);
705
+ patch(oldStartVnode, newStartVnode, isInitialRender);
650
706
  oldStartVnode = oldCh[++oldStartIdx];
651
707
  newStartVnode = newCh[++newStartIdx];
652
708
  }
653
- else if (isSameVnode(oldEndVnode, newEndVnode)) {
709
+ else if (isSameVnode(oldEndVnode, newEndVnode, isInitialRender)) {
654
710
  // likewise, if the end nodes are the same we patch new onto old and
655
711
  // decrement our end indices, and also likewise in this case we don't
656
712
  // need to move any DOM Nodes.
657
- patch(oldEndVnode, newEndVnode);
713
+ patch(oldEndVnode, newEndVnode, isInitialRender);
658
714
  oldEndVnode = oldCh[--oldEndIdx];
659
715
  newEndVnode = newCh[--newEndIdx];
660
716
  }
661
- else if (isSameVnode(oldStartVnode, newEndVnode)) {
717
+ else if (isSameVnode(oldStartVnode, newEndVnode, isInitialRender)) {
662
718
  // case: "Vnode moved right"
663
719
  //
664
720
  // We've found that the last node in our window on the new children is
@@ -676,7 +732,7 @@ const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
676
732
  if ((oldStartVnode.$tag$ === 'slot' || newEndVnode.$tag$ === 'slot')) {
677
733
  putBackInOriginalLocation(oldStartVnode.$elm$.parentNode, false);
678
734
  }
679
- patch(oldStartVnode, newEndVnode);
735
+ patch(oldStartVnode, newEndVnode, isInitialRender);
680
736
  // We need to move the element for `oldStartVnode` into a position which
681
737
  // will be appropriate for `newEndVnode`. For this we can use
682
738
  // `.insertBefore` and `oldEndVnode.$elm$.nextSibling`. If there is a
@@ -698,7 +754,7 @@ const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
698
754
  oldStartVnode = oldCh[++oldStartIdx];
699
755
  newEndVnode = newCh[--newEndIdx];
700
756
  }
701
- else if (isSameVnode(oldEndVnode, newStartVnode)) {
757
+ else if (isSameVnode(oldEndVnode, newStartVnode, isInitialRender)) {
702
758
  // case: "Vnode moved left"
703
759
  //
704
760
  // We've found that the first node in our window on the new children is
@@ -717,7 +773,7 @@ const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
717
773
  if ((oldStartVnode.$tag$ === 'slot' || newEndVnode.$tag$ === 'slot')) {
718
774
  putBackInOriginalLocation(oldEndVnode.$elm$.parentNode, false);
719
775
  }
720
- patch(oldEndVnode, newStartVnode);
776
+ patch(oldEndVnode, newStartVnode, isInitialRender);
721
777
  // We've already checked above if `oldStartVnode` and `newStartVnode` are
722
778
  // the same node, so since we're here we know that they are not. Thus we
723
779
  // can move the element for `oldEndVnode` _before_ the element for
@@ -728,7 +784,41 @@ const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
728
784
  newStartVnode = newCh[++newStartIdx];
729
785
  }
730
786
  else {
787
+ // Here we do some checks to match up old and new nodes based on the
788
+ // `$key$` attribute, which is set by putting a `key="my-key"` attribute
789
+ // in the JSX for a DOM element in the implementation of a Stencil
790
+ // component.
791
+ //
792
+ // First we check to see if there are any nodes in the array of old
793
+ // children which have the same key as the first node in the new
794
+ // children.
795
+ idxInOld = -1;
731
796
  {
797
+ for (i = oldStartIdx; i <= oldEndIdx; ++i) {
798
+ if (oldCh[i] && oldCh[i].$key$ !== null && oldCh[i].$key$ === newStartVnode.$key$) {
799
+ idxInOld = i;
800
+ break;
801
+ }
802
+ }
803
+ }
804
+ if (idxInOld >= 0) {
805
+ // We found a node in the old children which matches up with the first
806
+ // node in the new children! So let's deal with that
807
+ elmToMove = oldCh[idxInOld];
808
+ if (elmToMove.$tag$ !== newStartVnode.$tag$) {
809
+ // the tag doesn't match so we'll need a new DOM element
810
+ node = createElm(oldCh && oldCh[newStartIdx], newVNode, idxInOld);
811
+ }
812
+ else {
813
+ patch(elmToMove, newStartVnode, isInitialRender);
814
+ // invalidate the matching old node so that we won't try to update it
815
+ // again later on
816
+ oldCh[idxInOld] = undefined;
817
+ node = elmToMove.$elm$;
818
+ }
819
+ newStartVnode = newCh[++newStartIdx];
820
+ }
821
+ else {
732
822
  // We either didn't find an element in the old children that matches
733
823
  // the key of the first new child OR the build is not using `key`
734
824
  // attributes at all. In either case we need to create a new element
@@ -771,15 +861,24 @@ const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
771
861
  *
772
862
  * @param leftVNode the first VNode to check
773
863
  * @param rightVNode the second VNode to check
864
+ * @param isInitialRender whether or not this is the first render of the vdom
774
865
  * @returns whether they're equal or not
775
866
  */
776
- const isSameVnode = (leftVNode, rightVNode) => {
867
+ const isSameVnode = (leftVNode, rightVNode, isInitialRender = false) => {
777
868
  // compare if two vnode to see if they're "technically" the same
778
869
  // need to have the same element tag, and same key to be the same
779
870
  if (leftVNode.$tag$ === rightVNode.$tag$) {
780
871
  if (leftVNode.$tag$ === 'slot') {
781
872
  return leftVNode.$name$ === rightVNode.$name$;
782
873
  }
874
+ // this will be set if JSX tags in the build have `key` attrs set on them
875
+ // we only want to check this if we're not on the first render since on
876
+ // first render `leftVNode.$key$` will always be `null`, so we can be led
877
+ // astray and, for instance, accidentally delete a DOM node that we want to
878
+ // keep around.
879
+ if (!isInitialRender) {
880
+ return leftVNode.$key$ === rightVNode.$key$;
881
+ }
783
882
  return true;
784
883
  }
785
884
  return false;
@@ -799,8 +898,9 @@ const parentReferenceNode = (node) => (node['s-ol'] ? node['s-ol'] : node).paren
799
898
  *
800
899
  * @param oldVNode an old VNode whose DOM element and children we want to update
801
900
  * @param newVNode a new VNode representing an updated version of the old one
901
+ * @param isInitialRender whether or not this is the first render of the vdom
802
902
  */
803
- const patch = (oldVNode, newVNode) => {
903
+ const patch = (oldVNode, newVNode, isInitialRender = false) => {
804
904
  const elm = (newVNode.$elm$ = oldVNode.$elm$);
805
905
  const oldChildren = oldVNode.$children$;
806
906
  const newChildren = newVNode.$children$;
@@ -809,8 +909,7 @@ const patch = (oldVNode, newVNode) => {
809
909
  let defaultHolder;
810
910
  if (text === null) {
811
911
  {
812
- if (tag === 'slot')
813
- ;
912
+ if (tag === 'slot' && !useNativeShadowDom) ;
814
913
  else {
815
914
  // either this is the first render of an element OR it's an update
816
915
  // AND we already know it's possible it could have changed
@@ -821,7 +920,7 @@ const patch = (oldVNode, newVNode) => {
821
920
  if (oldChildren !== null && newChildren !== null) {
822
921
  // looks like there's child vnodes for both the old and new vnodes
823
922
  // so we need to call `updateChildren` to reconcile them
824
- updateChildren(elm, oldChildren, newVNode, newChildren);
923
+ updateChildren(elm, oldChildren, newVNode, newChildren, isInitialRender);
825
924
  }
826
925
  else if (newChildren !== null) {
827
926
  // no old child vnodes, but there are new child vnodes to add
@@ -847,42 +946,53 @@ const patch = (oldVNode, newVNode) => {
847
946
  elm.data = text;
848
947
  }
849
948
  };
949
+ /**
950
+ * Adjust the `.hidden` property as-needed on any nodes in a DOM subtree which
951
+ * are slot fallbacks nodes.
952
+ *
953
+ * A slot fallback node should be visible by default. Then, it should be
954
+ * conditionally hidden if:
955
+ *
956
+ * - it has a sibling with a `slot` property set to its slot name or if
957
+ * - it is a default fallback slot node, in which case we hide if it has any
958
+ * content
959
+ *
960
+ * @param elm the element of interest
961
+ */
850
962
  const updateFallbackSlotVisibility = (elm) => {
851
- // tslint:disable-next-line: prefer-const
852
963
  const childNodes = elm.childNodes;
853
- let childNode;
854
- let i;
855
- let ilen;
856
- let j;
857
- let slotNameAttr;
858
- let nodeType;
859
- for (i = 0, ilen = childNodes.length; i < ilen; i++) {
860
- childNode = childNodes[i];
964
+ for (const childNode of childNodes) {
861
965
  if (childNode.nodeType === 1 /* NODE_TYPE.ElementNode */) {
862
966
  if (childNode['s-sr']) {
863
967
  // this is a slot fallback node
864
968
  // get the slot name for this slot reference node
865
- slotNameAttr = childNode['s-sn'];
969
+ const slotName = childNode['s-sn'];
866
970
  // by default always show a fallback slot node
867
971
  // then hide it if there are other slots in the light dom
868
972
  childNode.hidden = false;
869
- for (j = 0; j < ilen; j++) {
870
- nodeType = childNodes[j].nodeType;
871
- if (childNodes[j]['s-hn'] !== childNode['s-hn'] || slotNameAttr !== '') {
872
- // this sibling node is from a different component OR is a named fallback slot node
873
- if (nodeType === 1 /* NODE_TYPE.ElementNode */ && slotNameAttr === childNodes[j].getAttribute('slot')) {
874
- childNode.hidden = true;
875
- break;
973
+ // we need to check all of its sibling nodes in order to see if
974
+ // `childNode` should be hidden
975
+ for (const siblingNode of childNodes) {
976
+ // Don't check the node against itself
977
+ if (siblingNode !== childNode) {
978
+ if (siblingNode['s-hn'] !== childNode['s-hn'] || slotName !== '') {
979
+ // this sibling node is from a different component OR is a named
980
+ // fallback slot node
981
+ if (siblingNode.nodeType === 1 /* NODE_TYPE.ElementNode */ &&
982
+ (slotName === siblingNode.getAttribute('slot') || slotName === siblingNode['s-sn'])) {
983
+ childNode.hidden = true;
984
+ break;
985
+ }
876
986
  }
877
- }
878
- else {
879
- // this is a default fallback slot node
880
- // any element or text node (with content)
881
- // should hide the default fallback slot node
882
- if (nodeType === 1 /* NODE_TYPE.ElementNode */ ||
883
- (nodeType === 3 /* NODE_TYPE.TextNode */ && childNodes[j].textContent.trim() !== '')) {
884
- childNode.hidden = true;
885
- break;
987
+ else {
988
+ // this is a default fallback slot node
989
+ // any element or text node (with content)
990
+ // should hide the default fallback slot node
991
+ if (siblingNode.nodeType === 1 /* NODE_TYPE.ElementNode */ ||
992
+ (siblingNode.nodeType === 3 /* NODE_TYPE.TextNode */ && siblingNode.textContent.trim() !== '')) {
993
+ childNode.hidden = true;
994
+ break;
995
+ }
886
996
  }
887
997
  }
888
998
  }
@@ -892,45 +1002,67 @@ const updateFallbackSlotVisibility = (elm) => {
892
1002
  }
893
1003
  }
894
1004
  };
1005
+ /**
1006
+ * Component-global information about nodes which are either currently being
1007
+ * relocated or will be shortly.
1008
+ */
895
1009
  const relocateNodes = [];
896
- const relocateSlotContent = (elm) => {
1010
+ /**
1011
+ * Mark the contents of a slot for relocation via adding references to them to
1012
+ * the {@link relocateNodes} data structure. The actual work of relocating them
1013
+ * will then be handled in {@link renderVdom}.
1014
+ *
1015
+ * @param elm a render node whose child nodes need to be relocated
1016
+ */
1017
+ const markSlotContentForRelocation = (elm) => {
897
1018
  // tslint:disable-next-line: prefer-const
898
- let childNode;
899
1019
  let node;
900
1020
  let hostContentNodes;
901
- let slotNameAttr;
902
- let relocateNodeData;
903
1021
  let j;
904
- let i = 0;
905
- const childNodes = elm.childNodes;
906
- const ilen = childNodes.length;
907
- for (; i < ilen; i++) {
908
- childNode = childNodes[i];
1022
+ for (const childNode of elm.childNodes) {
1023
+ // we need to find child nodes which are slot references so we can then try
1024
+ // to match them up with nodes that need to be relocated
909
1025
  if (childNode['s-sr'] && (node = childNode['s-cr']) && node.parentNode) {
910
- // first got the content reference comment node
911
- // then we got it's parent, which is where all the host content is in now
1026
+ // first get the content reference comment node ('s-cr'), then we get
1027
+ // its parent, which is where all the host content is now
912
1028
  hostContentNodes = node.parentNode.childNodes;
913
- slotNameAttr = childNode['s-sn'];
1029
+ const slotName = childNode['s-sn'];
1030
+ // iterate through all the nodes under the location where the host was
1031
+ // originally rendered
914
1032
  for (j = hostContentNodes.length - 1; j >= 0; j--) {
915
1033
  node = hostContentNodes[j];
916
- if (!node['s-cn'] && !node['s-nr'] && node['s-hn'] !== childNode['s-hn']) {
917
- // let's do some relocating to its new home
918
- // but never relocate a content reference node
919
- // that is suppose to always represent the original content location
920
- if (isNodeLocatedInSlot(node, slotNameAttr)) {
1034
+ // check that the node is not a content reference node or a node
1035
+ // reference and then check that the host name does not match that of
1036
+ // childNode.
1037
+ // In addition, check that the slot either has not already been relocated, or
1038
+ // that its current location's host is not childNode's host. This is essentially
1039
+ // a check so that we don't try to relocate (and then hide) a node that is already
1040
+ // where it should be.
1041
+ if (!node['s-cn'] &&
1042
+ !node['s-nr'] &&
1043
+ node['s-hn'] !== childNode['s-hn'] &&
1044
+ (!BUILD.experimentalSlotFixes )) {
1045
+ // if `node` is located in the slot that `childNode` refers to (via the
1046
+ // `'s-sn'` property) then we need to relocate it from it's current spot
1047
+ // (under the host element parent) to the right slot location
1048
+ if (isNodeLocatedInSlot(node, slotName)) {
921
1049
  // it's possible we've already decided to relocate this node
922
- relocateNodeData = relocateNodes.find((r) => r.$nodeToRelocate$ === node);
1050
+ let relocateNodeData = relocateNodes.find((r) => r.$nodeToRelocate$ === node);
923
1051
  // made some changes to slots
924
1052
  // let's make sure we also double check
925
1053
  // fallbacks are correctly hidden or shown
926
1054
  checkSlotFallbackVisibility = true;
927
- node['s-sn'] = node['s-sn'] || slotNameAttr;
1055
+ // ensure that the slot-name attr is correct
1056
+ node['s-sn'] = node['s-sn'] || slotName;
928
1057
  if (relocateNodeData) {
929
- // previously we never found a slot home for this node
930
- // but turns out we did, so let's remember it now
1058
+ relocateNodeData.$nodeToRelocate$['s-sh'] = childNode['s-hn'];
1059
+ // we marked this node for relocation previously but didn't find
1060
+ // out the slot reference node to which it needs to be relocated
1061
+ // so write it down now!
931
1062
  relocateNodeData.$slotRefNode$ = childNode;
932
1063
  }
933
1064
  else {
1065
+ node['s-sh'] = childNode['s-hn'];
934
1066
  // add to our list of nodes to relocate
935
1067
  relocateNodes.push({
936
1068
  $slotRefNode$: childNode,
@@ -949,8 +1081,10 @@ const relocateSlotContent = (elm) => {
949
1081
  }
950
1082
  }
951
1083
  else if (!relocateNodes.some((r) => r.$nodeToRelocate$ === node)) {
952
- // so far this element does not have a slot home, not setting slotRefNode on purpose
953
- // if we never find a home for this element then we'll need to hide it
1084
+ // the node is not found within the slot (`childNode`) that we're
1085
+ // currently looking at, so we stick it into `relocateNodes` to
1086
+ // handle later. If we never find a home for this element then
1087
+ // we'll need to hide it
954
1088
  relocateNodes.push({
955
1089
  $nodeToRelocate$: node,
956
1090
  });
@@ -958,25 +1092,36 @@ const relocateSlotContent = (elm) => {
958
1092
  }
959
1093
  }
960
1094
  }
1095
+ // if we're dealing with any type of element (capable of itself being a
1096
+ // slot reference or containing one) then we recur
961
1097
  if (childNode.nodeType === 1 /* NODE_TYPE.ElementNode */) {
962
- relocateSlotContent(childNode);
1098
+ markSlotContentForRelocation(childNode);
963
1099
  }
964
1100
  }
965
1101
  };
966
- const isNodeLocatedInSlot = (nodeToRelocate, slotNameAttr) => {
1102
+ /**
1103
+ * Check whether a node is located in a given named slot.
1104
+ *
1105
+ * @param nodeToRelocate the node of interest
1106
+ * @param slotName the slot name to check
1107
+ * @returns whether the node is located in the slot or not
1108
+ */
1109
+ const isNodeLocatedInSlot = (nodeToRelocate, slotName) => {
967
1110
  if (nodeToRelocate.nodeType === 1 /* NODE_TYPE.ElementNode */) {
968
- if (nodeToRelocate.getAttribute('slot') === null && slotNameAttr === '') {
1111
+ if (nodeToRelocate.getAttribute('slot') === null && slotName === '') {
1112
+ // if the node doesn't have a slot attribute, and the slot we're checking
1113
+ // is not a named slot, then we assume the node should be within the slot
969
1114
  return true;
970
1115
  }
971
- if (nodeToRelocate.getAttribute('slot') === slotNameAttr) {
1116
+ if (nodeToRelocate.getAttribute('slot') === slotName) {
972
1117
  return true;
973
1118
  }
974
1119
  return false;
975
1120
  }
976
- if (nodeToRelocate['s-sn'] === slotNameAttr) {
1121
+ if (nodeToRelocate['s-sn'] === slotName) {
977
1122
  return true;
978
1123
  }
979
- return slotNameAttr === '';
1124
+ return slotName === '';
980
1125
  };
981
1126
  /**
982
1127
  * The main entry point for Stencil's virtual DOM-based rendering engine
@@ -989,71 +1134,104 @@ const isNodeLocatedInSlot = (nodeToRelocate, slotNameAttr) => {
989
1134
  * @param hostRef data needed to root and render the virtual DOM tree, such as
990
1135
  * the DOM node into which it should be rendered.
991
1136
  * @param renderFnResults the virtual DOM nodes to be rendered
1137
+ * @param isInitialLoad whether or not this is the first call after page load
992
1138
  */
993
- const renderVdom = (hostRef, renderFnResults) => {
1139
+ const renderVdom = (hostRef, renderFnResults, isInitialLoad = false) => {
1140
+ var _a, _b, _c, _d;
994
1141
  const hostElm = hostRef.$hostElement$;
995
1142
  const cmpMeta = hostRef.$cmpMeta$;
996
1143
  const oldVNode = hostRef.$vnode$ || newVNode(null, null);
1144
+ // if `renderFnResults` is a Host node then we can use it directly. If not,
1145
+ // we need to call `h` again to wrap the children of our component in a
1146
+ // 'dummy' Host node (well, an empty vnode) since `renderVdom` assumes
1147
+ // implicitly that the top-level vdom node is 1) an only child and 2)
1148
+ // contains attrs that need to be set on the host element.
997
1149
  const rootVnode = isHost(renderFnResults) ? renderFnResults : h(null, null, renderFnResults);
998
1150
  hostTagName = hostElm.tagName;
999
1151
  if (cmpMeta.$attrsToReflect$) {
1000
1152
  rootVnode.$attrs$ = rootVnode.$attrs$ || {};
1001
1153
  cmpMeta.$attrsToReflect$.map(([propName, attribute]) => (rootVnode.$attrs$[attribute] = hostElm[propName]));
1002
1154
  }
1155
+ // On the first render and *only* on the first render we want to check for
1156
+ // any attributes set on the host element which are also set on the vdom
1157
+ // node. If we find them, we override the value on the VDom node attrs with
1158
+ // the value from the host element, which allows developers building apps
1159
+ // with Stencil components to override e.g. the `role` attribute on a
1160
+ // component even if it's already set on the `Host`.
1161
+ if (isInitialLoad && rootVnode.$attrs$) {
1162
+ for (const key of Object.keys(rootVnode.$attrs$)) {
1163
+ // We have a special implementation in `setAccessor` for `style` and
1164
+ // `class` which reconciles values coming from the VDom with values
1165
+ // already present on the DOM element, so we don't want to override those
1166
+ // attributes on the VDom tree with values from the host element if they
1167
+ // are present.
1168
+ //
1169
+ // Likewise, `ref` and `key` are special internal values for the Stencil
1170
+ // runtime and we don't want to override those either.
1171
+ if (hostElm.hasAttribute(key) && !['key', 'ref', 'style', 'class'].includes(key)) {
1172
+ rootVnode.$attrs$[key] = hostElm[key];
1173
+ }
1174
+ }
1175
+ }
1003
1176
  rootVnode.$tag$ = null;
1004
1177
  rootVnode.$flags$ |= 4 /* VNODE_FLAGS.isHost */;
1005
1178
  hostRef.$vnode$ = rootVnode;
1006
1179
  rootVnode.$elm$ = oldVNode.$elm$ = (hostElm);
1180
+ useNativeShadowDom = (cmpMeta.$flags$ & 1 /* CMP_FLAGS.shadowDomEncapsulation */) !== 0;
1007
1181
  {
1008
1182
  contentRef = hostElm['s-cr'];
1009
- useNativeShadowDom = (cmpMeta.$flags$ & 1 /* CMP_FLAGS.shadowDomEncapsulation */) !== 0;
1010
1183
  // always reset
1011
1184
  checkSlotFallbackVisibility = false;
1012
1185
  }
1013
1186
  // synchronous patch
1014
- patch(oldVNode, rootVnode);
1187
+ patch(oldVNode, rootVnode, isInitialLoad);
1015
1188
  {
1016
1189
  // while we're moving nodes around existing nodes, temporarily disable
1017
1190
  // the disconnectCallback from working
1018
1191
  plt.$flags$ |= 1 /* PLATFORM_FLAGS.isTmpDisconnected */;
1019
1192
  if (checkSlotRelocate) {
1020
- relocateSlotContent(rootVnode.$elm$);
1021
- let relocateData;
1022
- let nodeToRelocate;
1023
- let orgLocationNode;
1024
- let parentNodeRef;
1025
- let insertBeforeNode;
1026
- let refNode;
1027
- let i = 0;
1028
- for (; i < relocateNodes.length; i++) {
1029
- relocateData = relocateNodes[i];
1030
- nodeToRelocate = relocateData.$nodeToRelocate$;
1193
+ markSlotContentForRelocation(rootVnode.$elm$);
1194
+ for (const relocateData of relocateNodes) {
1195
+ const nodeToRelocate = relocateData.$nodeToRelocate$;
1031
1196
  if (!nodeToRelocate['s-ol']) {
1032
1197
  // add a reference node marking this node's original location
1033
1198
  // keep a reference to this node for later lookups
1034
- orgLocationNode =
1035
- doc.createTextNode('');
1199
+ const orgLocationNode = doc.createTextNode('');
1036
1200
  orgLocationNode['s-nr'] = nodeToRelocate;
1037
1201
  nodeToRelocate.parentNode.insertBefore((nodeToRelocate['s-ol'] = orgLocationNode), nodeToRelocate);
1038
1202
  }
1039
1203
  }
1040
- for (i = 0; i < relocateNodes.length; i++) {
1041
- relocateData = relocateNodes[i];
1042
- nodeToRelocate = relocateData.$nodeToRelocate$;
1043
- if (relocateData.$slotRefNode$) {
1044
- // by default we're just going to insert it directly
1045
- // after the slot reference node
1046
- parentNodeRef = relocateData.$slotRefNode$.parentNode;
1047
- insertBeforeNode = relocateData.$slotRefNode$.nextSibling;
1048
- orgLocationNode = nodeToRelocate['s-ol'];
1049
- while ((orgLocationNode = orgLocationNode.previousSibling)) {
1050
- refNode = orgLocationNode['s-nr'];
1051
- if (refNode && refNode['s-sn'] === nodeToRelocate['s-sn'] && parentNodeRef === refNode.parentNode) {
1052
- refNode = refNode.nextSibling;
1053
- if (!refNode || !refNode['s-nr']) {
1054
- insertBeforeNode = refNode;
1055
- break;
1204
+ for (const relocateData of relocateNodes) {
1205
+ const nodeToRelocate = relocateData.$nodeToRelocate$;
1206
+ const slotRefNode = relocateData.$slotRefNode$;
1207
+ if (slotRefNode) {
1208
+ const parentNodeRef = slotRefNode.parentNode;
1209
+ // When determining where to insert content, the most simple case would be
1210
+ // to relocate the node immediately following the slot reference node. We do this
1211
+ // by getting a reference to the node immediately following the slot reference node
1212
+ // since we will use `insertBefore` to manipulate the DOM.
1213
+ //
1214
+ // If there is no node immediately following the slot reference node, then we will just
1215
+ // end up appending the node as the last child of the parent.
1216
+ let insertBeforeNode = slotRefNode.nextSibling;
1217
+ // If the node we're currently planning on inserting the new node before is an element,
1218
+ // we need to do some additional checks to make sure we're inserting the node in the correct order.
1219
+ // The use case here would be that we have multiple nodes being relocated to the same slot. So, we want
1220
+ // to make sure they get inserted into their new how in the same order they were declared in their original location.
1221
+ //
1222
+ // TODO(STENCIL-914): Remove `experimentalSlotFixes` check
1223
+ {
1224
+ let orgLocationNode = (_a = nodeToRelocate['s-ol']) === null || _a === void 0 ? void 0 : _a.previousSibling;
1225
+ while (orgLocationNode) {
1226
+ let refNode = (_b = orgLocationNode['s-nr']) !== null && _b !== void 0 ? _b : null;
1227
+ if (refNode && refNode['s-sn'] === nodeToRelocate['s-sn'] && parentNodeRef === refNode.parentNode) {
1228
+ refNode = refNode.nextSibling;
1229
+ if (!refNode || !refNode['s-nr']) {
1230
+ insertBeforeNode = refNode;
1231
+ break;
1232
+ }
1056
1233
  }
1234
+ orgLocationNode = orgLocationNode.previousSibling;
1057
1235
  }
1058
1236
  }
1059
1237
  if ((!insertBeforeNode && parentNodeRef !== nodeToRelocate.parentNode) ||
@@ -1063,17 +1241,32 @@ const renderVdom = (hostRef, renderFnResults) => {
1063
1241
  // has a different next sibling or parent relocated
1064
1242
  if (nodeToRelocate !== insertBeforeNode) {
1065
1243
  if (!nodeToRelocate['s-hn'] && nodeToRelocate['s-ol']) {
1066
- // probably a component in the index.html that doesn't have it's hostname set
1244
+ // probably a component in the index.html that doesn't have its hostname set
1067
1245
  nodeToRelocate['s-hn'] = nodeToRelocate['s-ol'].parentNode.nodeName;
1068
1246
  }
1069
- // add it back to the dom but in its new home
1247
+ // Add it back to the dom but in its new home
1248
+ // If we get to this point and `insertBeforeNode` is `null`, that means
1249
+ // we're just going to append the node as the last child of the parent. Passing
1250
+ // `null` as the second arg here will trigger that behavior.
1070
1251
  parentNodeRef.insertBefore(nodeToRelocate, insertBeforeNode);
1252
+ // Reset the `hidden` value back to what it was defined as originally
1253
+ // This solves a problem where a `slot` is dynamically rendered and `hidden` may have
1254
+ // been set on content originally, but now it has a slot to go to so it should have
1255
+ // the value it was defined as having in the DOM, not what we overrode it to.
1256
+ if (nodeToRelocate.nodeType === 1 /* NODE_TYPE.ElementNode */) {
1257
+ nodeToRelocate.hidden = (_c = nodeToRelocate['s-ih']) !== null && _c !== void 0 ? _c : false;
1258
+ }
1071
1259
  }
1072
1260
  }
1073
1261
  }
1074
1262
  else {
1075
1263
  // this node doesn't have a slot home to go to, so let's hide it
1076
1264
  if (nodeToRelocate.nodeType === 1 /* NODE_TYPE.ElementNode */) {
1265
+ // Store the initial value of `hidden` so we can reset it later when
1266
+ // moving nodes around.
1267
+ if (isInitialLoad) {
1268
+ nodeToRelocate['s-ih'] = (_d = nodeToRelocate.hidden) !== null && _d !== void 0 ? _d : false;
1269
+ }
1077
1270
  nodeToRelocate.hidden = true;
1078
1271
  }
1079
1272
  }
@@ -1088,6 +1281,8 @@ const renderVdom = (hostRef, renderFnResults) => {
1088
1281
  // always reset
1089
1282
  relocateNodes.length = 0;
1090
1283
  }
1284
+ // Clear the content ref so we don't create a memory leak
1285
+ contentRef = undefined;
1091
1286
  };
1092
1287
  const attachToAncestor = (hostRef, ancestorComponent) => {
1093
1288
  if (ancestorComponent && !hostRef.$onRenderResolve$ && ancestorComponent['s-p']) {
@@ -1167,6 +1362,16 @@ const enqueue = (maybePromise, fn) => isPromisey(maybePromise) ? maybePromise.th
1167
1362
  */
1168
1363
  const isPromisey = (maybePromise) => maybePromise instanceof Promise ||
1169
1364
  (maybePromise && maybePromise.then && typeof maybePromise.then === 'function');
1365
+ /**
1366
+ * Update a component given reference to its host elements and so on.
1367
+ *
1368
+ * @param hostRef an object containing references to the element's host node,
1369
+ * VDom nodes, and other metadata
1370
+ * @param instance a reference to the underlying host element where it will be
1371
+ * rendered
1372
+ * @param isInitialLoad whether or not this function is being called as part of
1373
+ * the first render cycle
1374
+ */
1170
1375
  const updateComponent = async (hostRef, instance, isInitialLoad) => {
1171
1376
  var _a;
1172
1377
  const elm = hostRef.$hostElement$;
@@ -1178,7 +1383,7 @@ const updateComponent = async (hostRef, instance, isInitialLoad) => {
1178
1383
  }
1179
1384
  const endRender = createTime('render', hostRef.$cmpMeta$.$tagName$);
1180
1385
  {
1181
- callRender(hostRef, instance);
1386
+ callRender(hostRef, instance, elm, isInitialLoad);
1182
1387
  }
1183
1388
  if (rc) {
1184
1389
  // ok, so turns out there are some child host elements
@@ -1202,8 +1407,24 @@ const updateComponent = async (hostRef, instance, isInitialLoad) => {
1202
1407
  }
1203
1408
  }
1204
1409
  };
1205
- const callRender = (hostRef, instance, elm) => {
1410
+ /**
1411
+ * Handle making the call to the VDom renderer with the proper context given
1412
+ * various build variables
1413
+ *
1414
+ * @param hostRef an object containing references to the element's host node,
1415
+ * VDom nodes, and other metadata
1416
+ * @param instance a reference to the underlying host element where it will be
1417
+ * rendered
1418
+ * @param elm the Host element for the component
1419
+ * @param isInitialLoad whether or not this function is being called as part of
1420
+ * @returns an empty promise
1421
+ */
1422
+ const callRender = (hostRef, instance, elm, isInitialLoad) => {
1206
1423
  try {
1424
+ /**
1425
+ * minification optimization: `allRenderFn` is `true` if all components have a `render`
1426
+ * method, so we can call the method immediately. If not, check before calling it.
1427
+ */
1207
1428
  instance = instance.render() ;
1208
1429
  {
1209
1430
  hostRef.$flags$ &= ~16 /* HOST_FLAGS.isQueuedForUpdate */;
@@ -1217,7 +1438,7 @@ const callRender = (hostRef, instance, elm) => {
1217
1438
  // or we need to update the css class/attrs on the host element
1218
1439
  // DOM WRITE!
1219
1440
  {
1220
- renderVdom(hostRef, instance);
1441
+ renderVdom(hostRef, instance, isInitialLoad);
1221
1442
  }
1222
1443
  }
1223
1444
  }
@@ -1277,6 +1498,16 @@ const appDidLoad = (who) => {
1277
1498
  }
1278
1499
  nextTick(() => emitEvent(win, 'appload', { detail: { namespace: NAMESPACE } }));
1279
1500
  };
1501
+ /**
1502
+ * Allows to safely call a method, e.g. `componentDidLoad`, on an instance,
1503
+ * e.g. custom element node. If a build figures out that e.g. no component
1504
+ * has a `componentDidLoad` method, the instance method gets removed from the
1505
+ * output bundle and this function returns `undefined`.
1506
+ * @param instance any object that may or may not contain methods
1507
+ * @param method method name
1508
+ * @param arg single arbitrary argument
1509
+ * @returns result of method call if it exists, otherwise `undefined`
1510
+ */
1280
1511
  const safeCall = (instance, method, arg) => {
1281
1512
  if (instance && instance[method]) {
1282
1513
  try {
@@ -1327,10 +1558,11 @@ const setValue = (ref, propName, newVal, cmpMeta) => {
1327
1558
  * @returns a reference to the same constructor passed in (but now mutated)
1328
1559
  */
1329
1560
  const proxyComponent = (Cstr, cmpMeta, flags) => {
1561
+ var _a;
1562
+ const prototype = Cstr.prototype;
1330
1563
  if (cmpMeta.$members$) {
1331
1564
  // It's better to have a const than two Object.entries()
1332
1565
  const members = Object.entries(cmpMeta.$members$);
1333
- const prototype = Cstr.prototype;
1334
1566
  members.map(([memberName, [memberFlags]]) => {
1335
1567
  if ((memberFlags & 31 /* MEMBER_FLAGS.Prop */ ||
1336
1568
  ((flags & 2 /* PROXY_FLAGS.proxyState */) && memberFlags & 32 /* MEMBER_FLAGS.State */))) {
@@ -1351,8 +1583,9 @@ const proxyComponent = (Cstr, cmpMeta, flags) => {
1351
1583
  });
1352
1584
  if ((flags & 1 /* PROXY_FLAGS.isElementConstructor */)) {
1353
1585
  const attrNameToPropName = new Map();
1354
- prototype.attributeChangedCallback = function (attrName, _oldValue, newValue) {
1586
+ prototype.attributeChangedCallback = function (attrName, oldValue, newValue) {
1355
1587
  plt.jmp(() => {
1588
+ var _a;
1356
1589
  const propName = attrNameToPropName.get(attrName);
1357
1590
  // In a web component lifecycle the attributeChangedCallback runs prior to connectedCallback
1358
1591
  // in the case where an attribute was set inline.
@@ -1374,12 +1607,12 @@ const proxyComponent = (Cstr, cmpMeta, flags) => {
1374
1607
  // customElements.define('my-component', MyComponent);
1375
1608
  // </script>
1376
1609
  // ```
1377
- // In this case if we do not unshadow here and use the value of the shadowing property, attributeChangedCallback
1610
+ // In this case if we do not un-shadow here and use the value of the shadowing property, attributeChangedCallback
1378
1611
  // will be called with `newValue = "some-value"` and will set the shadowed property (this.someAttribute = "another-value")
1379
1612
  // to the value that was set inline i.e. "some-value" from above example. When
1380
- // the connectedCallback attempts to unshadow it will use "some-value" as the initial value rather than "another-value"
1613
+ // the connectedCallback attempts to un-shadow it will use "some-value" as the initial value rather than "another-value"
1381
1614
  //
1382
- // The case where the attribute was NOT set inline but was not set programmatically shall be handled/unshadowed
1615
+ // The case where the attribute was NOT set inline but was not set programmatically shall be handled/un-shadowed
1383
1616
  // by connectedCallback as this attributeChangedCallback will not fire.
1384
1617
  //
1385
1618
  // https://developers.google.com/web/fundamentals/web-components/best-practices#lazy-properties
@@ -1399,26 +1632,67 @@ const proxyComponent = (Cstr, cmpMeta, flags) => {
1399
1632
  // `propName` to be converted to a `DOMString`, which may not be what we want for other primitive props.
1400
1633
  return;
1401
1634
  }
1635
+ else if (propName == null) {
1636
+ // At this point we should know this is not a "member", so we can treat it like watching an attribute
1637
+ // on a vanilla web component
1638
+ const hostRef = getHostRef(this);
1639
+ const flags = hostRef === null || hostRef === void 0 ? void 0 : hostRef.$flags$;
1640
+ // We only want to trigger the callback(s) if:
1641
+ // 1. The instance is ready
1642
+ // 2. The watchers are ready
1643
+ // 3. The value has changed
1644
+ if (flags &&
1645
+ !(flags & 8 /* HOST_FLAGS.isConstructingInstance */) &&
1646
+ flags & 128 /* HOST_FLAGS.isWatchReady */ &&
1647
+ newValue !== oldValue) {
1648
+ const instance = hostRef.$lazyInstance$ ;
1649
+ const entry = (_a = cmpMeta.$watchers$) === null || _a === void 0 ? void 0 : _a[attrName];
1650
+ entry === null || entry === void 0 ? void 0 : entry.forEach((callbackName) => {
1651
+ if (instance[callbackName] != null) {
1652
+ instance[callbackName].call(instance, newValue, oldValue, attrName);
1653
+ }
1654
+ });
1655
+ }
1656
+ return;
1657
+ }
1402
1658
  this[propName] = newValue === null && typeof this[propName] === 'boolean' ? false : newValue;
1403
1659
  });
1404
1660
  };
1405
- // create an array of attributes to observe
1406
- // and also create a map of html attribute name to js property name
1407
- Cstr.observedAttributes = members
1408
- .filter(([_, m]) => m[0] & 15 /* MEMBER_FLAGS.HasAttribute */) // filter to only keep props that should match attributes
1409
- .map(([propName, m]) => {
1410
- const attrName = m[1] || propName;
1411
- attrNameToPropName.set(attrName, propName);
1412
- if (m[0] & 512 /* MEMBER_FLAGS.ReflectAttr */) {
1413
- cmpMeta.$attrsToReflect$.push([propName, attrName]);
1414
- }
1415
- return attrName;
1416
- });
1661
+ // Create an array of attributes to observe
1662
+ // This list in comprised of all strings used within a `@Watch()` decorator
1663
+ // on a component as well as any Stencil-specific "members" (`@Prop()`s and `@State()`s).
1664
+ // As such, there is no way to guarantee type-safety here that a user hasn't entered
1665
+ // an invalid attribute.
1666
+ Cstr.observedAttributes = Array.from(new Set([
1667
+ ...Object.keys((_a = cmpMeta.$watchers$) !== null && _a !== void 0 ? _a : {}),
1668
+ ...members
1669
+ .filter(([_, m]) => m[0] & 15 /* MEMBER_FLAGS.HasAttribute */)
1670
+ .map(([propName, m]) => {
1671
+ var _a;
1672
+ const attrName = m[1] || propName;
1673
+ attrNameToPropName.set(attrName, propName);
1674
+ if (m[0] & 512 /* MEMBER_FLAGS.ReflectAttr */) {
1675
+ (_a = cmpMeta.$attrsToReflect$) === null || _a === void 0 ? void 0 : _a.push([propName, attrName]);
1676
+ }
1677
+ return attrName;
1678
+ }),
1679
+ ]));
1417
1680
  }
1418
1681
  }
1419
1682
  return Cstr;
1420
1683
  };
1421
- const initializeComponent = async (elm, hostRef, cmpMeta, hmrVersionId, Cstr) => {
1684
+ /**
1685
+ * Initialize a Stencil component given a reference to its host element, its
1686
+ * runtime bookkeeping data structure, runtime metadata about the component,
1687
+ * and (optionally) an HMR version ID.
1688
+ *
1689
+ * @param elm a host element
1690
+ * @param hostRef the element's runtime bookkeeping object
1691
+ * @param cmpMeta runtime metadata for the Stencil component
1692
+ * @param hmrVersionId an (optional) HMR version ID
1693
+ */
1694
+ const initializeComponent = async (elm, hostRef, cmpMeta, hmrVersionId) => {
1695
+ let Cstr;
1422
1696
  // initializeComponent
1423
1697
  if ((hostRef.$flags$ & 32 /* HOST_FLAGS.hasInitializedComponent */) === 0) {
1424
1698
  // Let the runtime know that the component has been initialized
@@ -1487,6 +1761,8 @@ const initializeComponent = async (elm, hostRef, cmpMeta, hmrVersionId, Cstr) =>
1487
1761
  schedule();
1488
1762
  }
1489
1763
  };
1764
+ const fireConnectedCallback = (instance) => {
1765
+ };
1490
1766
  const connectedCallback = (elm) => {
1491
1767
  if ((plt.$flags$ & 1 /* PLATFORM_FLAGS.isTmpDisconnected */) === 0) {
1492
1768
  const hostRef = getHostRef(elm);
@@ -1535,6 +1811,13 @@ const connectedCallback = (elm) => {
1535
1811
  initializeComponent(elm, hostRef, cmpMeta);
1536
1812
  }
1537
1813
  }
1814
+ else {
1815
+ // fire off connectedCallback() on component instance
1816
+ if (hostRef === null || hostRef === void 0 ? void 0 : hostRef.$lazyInstance$) ;
1817
+ else if (hostRef === null || hostRef === void 0 ? void 0 : hostRef.$onReadyPromise$) {
1818
+ hostRef.$onReadyPromise$.then(() => fireConnectedCallback());
1819
+ }
1820
+ }
1538
1821
  endConnected();
1539
1822
  }
1540
1823
  };
@@ -1549,9 +1832,15 @@ const setContentReference = (elm) => {
1549
1832
  contentRefElm['s-cn'] = true;
1550
1833
  elm.insertBefore(contentRefElm, elm.firstChild);
1551
1834
  };
1552
- const disconnectedCallback = (elm) => {
1835
+ const disconnectInstance = (instance) => {
1836
+ };
1837
+ const disconnectedCallback = async (elm) => {
1553
1838
  if ((plt.$flags$ & 1 /* PLATFORM_FLAGS.isTmpDisconnected */) === 0) {
1554
- getHostRef(elm);
1839
+ const hostRef = getHostRef(elm);
1840
+ if (hostRef === null || hostRef === void 0 ? void 0 : hostRef.$lazyInstance$) ;
1841
+ else if (hostRef === null || hostRef === void 0 ? void 0 : hostRef.$onReadyPromise$) {
1842
+ hostRef.$onReadyPromise$.then(() => disconnectInstance());
1843
+ }
1555
1844
  }
1556
1845
  };
1557
1846
  const bootstrapLazy = (lazyBundles, options = {}) => {
@@ -1562,12 +1851,13 @@ const bootstrapLazy = (lazyBundles, options = {}) => {
1562
1851
  const customElements = win.customElements;
1563
1852
  const head = doc.head;
1564
1853
  const metaCharset = /*@__PURE__*/ head.querySelector('meta[charset]');
1565
- const visibilityStyle = /*@__PURE__*/ doc.createElement('style');
1854
+ const dataStyles = /*@__PURE__*/ doc.createElement('style');
1566
1855
  const deferredConnectedCallbacks = [];
1567
1856
  let appLoadFallback;
1568
1857
  let isBootstrapping = true;
1569
1858
  Object.assign(plt, options);
1570
1859
  plt.$resourcesUrl$ = new URL(options.resourcesUrl || './', doc.baseURI).href;
1860
+ let hasSlotRelocation = false;
1571
1861
  lazyBundles.map((lazyBundle) => {
1572
1862
  lazyBundle[1].map((compactMeta) => {
1573
1863
  const cmpMeta = {
@@ -1576,6 +1866,11 @@ const bootstrapLazy = (lazyBundles, options = {}) => {
1576
1866
  $members$: compactMeta[2],
1577
1867
  $listeners$: compactMeta[3],
1578
1868
  };
1869
+ // Check if we are using slots outside the shadow DOM in this component.
1870
+ // We'll use this information later to add styles for `slot-fb` elements
1871
+ if (cmpMeta.$flags$ & 4 /* CMP_FLAGS.hasSlotRelocation */) {
1872
+ hasSlotRelocation = true;
1873
+ }
1579
1874
  {
1580
1875
  cmpMeta.$members$ = compactMeta[2];
1581
1876
  }
@@ -1618,15 +1913,29 @@ const bootstrapLazy = (lazyBundles, options = {}) => {
1618
1913
  }
1619
1914
  });
1620
1915
  });
1621
- {
1622
- visibilityStyle.innerHTML = cmpTags + HYDRATED_CSS;
1623
- visibilityStyle.setAttribute('data-styles', '');
1624
- // Apply CSP nonce to the style tag if it exists
1625
- const nonce = (_a = plt.$nonce$) !== null && _a !== void 0 ? _a : queryNonceMetaTagContent(doc);
1626
- if (nonce != null) {
1627
- visibilityStyle.setAttribute('nonce', nonce);
1916
+ // Only bother generating CSS if we have components
1917
+ // TODO(STENCIL-1118): Add test cases for CSS content based on conditionals
1918
+ if (cmpTags.length > 0) {
1919
+ // Add styles for `slot-fb` elements if any of our components are using slots outside the Shadow DOM
1920
+ if (hasSlotRelocation) {
1921
+ dataStyles.textContent += SLOT_FB_CSS;
1922
+ }
1923
+ // Add hydration styles
1924
+ {
1925
+ dataStyles.textContent += cmpTags + HYDRATED_CSS;
1926
+ }
1927
+ // If we have styles, add them to the DOM
1928
+ if (dataStyles.innerHTML.length) {
1929
+ dataStyles.setAttribute('data-styles', '');
1930
+ // Apply CSP nonce to the style tag if it exists
1931
+ const nonce = (_a = plt.$nonce$) !== null && _a !== void 0 ? _a : queryNonceMetaTagContent(doc);
1932
+ if (nonce != null) {
1933
+ dataStyles.setAttribute('nonce', nonce);
1934
+ }
1935
+ // Insert the styles into the document head
1936
+ // NOTE: this _needs_ to happen last so we can ensure the nonce (and other attributes) are applied
1937
+ head.insertBefore(dataStyles, metaCharset ? metaCharset.nextSibling : head.firstChild);
1628
1938
  }
1629
- head.insertBefore(visibilityStyle, metaCharset ? metaCharset.nextSibling : head.firstChild);
1630
1939
  }
1631
1940
  // Process deferred connectedCallbacks now all components have been registered
1632
1941
  isBootstrapping = false;
@@ -1648,22 +1957,60 @@ const bootstrapLazy = (lazyBundles, options = {}) => {
1648
1957
  * @returns void
1649
1958
  */
1650
1959
  const setNonce = (nonce) => (plt.$nonce$ = nonce);
1651
- const hostRefs = /*@__PURE__*/ new WeakMap();
1960
+ /**
1961
+ * A WeakMap mapping runtime component references to their corresponding host reference
1962
+ * instances.
1963
+ *
1964
+ * **Note**: If we're in an HMR context we need to store a reference to this
1965
+ * value on `window` in order to maintain the mapping of {@link d.RuntimeRef}
1966
+ * to {@link d.HostRef} across HMR updates.
1967
+ *
1968
+ * This is necessary because when HMR updates for a component are processed by
1969
+ * the browser-side dev server client the JS bundle for that component is
1970
+ * re-fetched. Since the module containing {@link hostRefs} is included in
1971
+ * that bundle, if we do not store a reference to it the new iteration of the
1972
+ * component will not have access to the previous hostRef map, leading to a
1973
+ * bug where the new version of the component cannot properly initialize.
1974
+ */
1975
+ const hostRefs = new WeakMap();
1976
+ /**
1977
+ * Given a {@link d.RuntimeRef} retrieve the corresponding {@link d.HostRef}
1978
+ *
1979
+ * @param ref the runtime ref of interest
1980
+ * @returns the Host reference (if found) or undefined
1981
+ */
1652
1982
  const getHostRef = (ref) => hostRefs.get(ref);
1983
+ /**
1984
+ * Register a lazy instance with the {@link hostRefs} object so it's
1985
+ * corresponding {@link d.HostRef} can be retrieved later.
1986
+ *
1987
+ * @param lazyInstance the lazy instance of interest
1988
+ * @param hostRef that instances `HostRef` object
1989
+ * @returns a reference to the host ref WeakMap
1990
+ */
1653
1991
  const registerInstance = (lazyInstance, hostRef) => hostRefs.set((hostRef.$lazyInstance$ = lazyInstance), hostRef);
1654
- const registerHost = (elm, cmpMeta) => {
1992
+ /**
1993
+ * Register a host element for a Stencil component, setting up various metadata
1994
+ * and callbacks based on {@link BUILD} flags as well as the component's runtime
1995
+ * metadata.
1996
+ *
1997
+ * @param hostElement the host element to register
1998
+ * @param cmpMeta runtime metadata for that component
1999
+ * @returns a reference to the host ref WeakMap
2000
+ */
2001
+ const registerHost = (hostElement, cmpMeta) => {
1655
2002
  const hostRef = {
1656
2003
  $flags$: 0,
1657
- $hostElement$: elm,
2004
+ $hostElement$: hostElement,
1658
2005
  $cmpMeta$: cmpMeta,
1659
2006
  $instanceValues$: new Map(),
1660
2007
  };
1661
2008
  {
1662
2009
  hostRef.$onReadyPromise$ = new Promise((r) => (hostRef.$onReadyResolve$ = r));
1663
- elm['s-p'] = [];
1664
- elm['s-rc'] = [];
2010
+ hostElement['s-p'] = [];
2011
+ hostElement['s-rc'] = [];
1665
2012
  }
1666
- return hostRefs.set(elm, hostRef);
2013
+ return hostRefs.set(hostElement, hostRef);
1667
2014
  };
1668
2015
  const isMemberInElement = (elm, memberName) => memberName in elm;
1669
2016
  const consoleError = (e, el) => (0, console.error)(e, el);
@@ -1751,7 +2098,7 @@ const flush = () => {
1751
2098
  }
1752
2099
  }
1753
2100
  };
1754
- const nextTick = /*@__PURE__*/ (cb) => promiseResolve().then(cb);
2101
+ const nextTick = (cb) => promiseResolve().then(cb);
1755
2102
  const writeTask = /*@__PURE__*/ queueTask(queueDomWrites, true);
1756
2103
 
1757
2104
  exports.Host = Host;
@@ -1761,4 +2108,4 @@ exports.promiseResolve = promiseResolve;
1761
2108
  exports.registerInstance = registerInstance;
1762
2109
  exports.setNonce = setNonce;
1763
2110
 
1764
- //# sourceMappingURL=index-c572276a.js.map
2111
+ //# sourceMappingURL=index-46644e39.js.map