@lwc/engine-core 2.3.7 → 2.5.2-canary1

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.
@@ -1,5 +1,5 @@
1
1
  /* proxy-compat-disable */
2
- import { seal, create, isFunction as isFunction$1, ArrayPush as ArrayPush$1, isUndefined as isUndefined$1, ArrayIndexOf, ArraySplice, StringToLowerCase, ArrayJoin, isNull, assign, assert, keys, StringCharCodeAt, isString, StringSlice, freeze, defineProperties, forEach, getOwnPropertyNames as getOwnPropertyNames$1, getPrototypeOf as getPrototypeOf$1, setPrototypeOf, getPropertyDescriptor, isObject, AriaPropNameToAttrNameMap, defineProperty, KEY__SYNTHETIC_MODE, toString as toString$1, isFalse, isTrue, getOwnPropertyDescriptor as getOwnPropertyDescriptor$1, htmlPropertyToAttribute, ArraySlice, hasOwnProperty as hasOwnProperty$1, noop, isArray as isArray$1, isNumber, StringReplace, KEY__SHADOW_RESOLVER, ArrayUnshift, isFrozen } from '@lwc/shared';
2
+ import { seal, create, isFunction as isFunction$1, ArrayPush as ArrayPush$1, isUndefined as isUndefined$1, ArrayIndexOf, ArraySplice, StringToLowerCase, ArrayJoin, isNull, assign, assert, keys, StringCharCodeAt, isString, StringSlice, freeze, defineProperties, forEach, getOwnPropertyNames as getOwnPropertyNames$1, getPrototypeOf as getPrototypeOf$1, setPrototypeOf, getPropertyDescriptor, isObject, AriaPropNameToAttrNameMap, defineProperty, KEY__SYNTHETIC_MODE, toString as toString$1, isFalse, isTrue, getOwnPropertyDescriptor as getOwnPropertyDescriptor$1, htmlPropertyToAttribute, ArraySlice, hasOwnProperty as hasOwnProperty$1, ArrayFilter, noop, isArray as isArray$1, isNumber, StringReplace, KEY__SHADOW_RESOLVER, KEY__SCOPED_CSS, ArrayUnshift, isFrozen } from '@lwc/shared';
3
3
  import { runtimeFlags } from '@lwc/features';
4
4
  export { setFeatureFlag, setFeatureFlagForTest } from '@lwc/features';
5
5
 
@@ -2309,12 +2309,6 @@ const LightningElement = function () {
2309
2309
  associateVM(component, vm);
2310
2310
  associateVM(elm, vm);
2311
2311
 
2312
- if (!runtimeFlags.ENABLE_LIGHT_DOM_COMPONENTS) {
2313
- assert.isTrue(def.renderMode !== 0
2314
- /* Light */
2315
- , `${def.name || 'Anonymous class'} is an invalid LWC component. Light DOM components are not available in this environment.`);
2316
- }
2317
-
2318
2312
  if (vm.renderMode === 1
2319
2313
  /* Shadow */
2320
2314
  ) {
@@ -2946,18 +2940,33 @@ function createObservedFieldPropertyDescriptor(key) {
2946
2940
 
2947
2941
  function getClassDescriptorType(descriptor) {
2948
2942
  if (isFunction$1(descriptor.value)) {
2949
- return 'method';
2943
+ return "method"
2944
+ /* Method */
2945
+ ;
2950
2946
  } else if (isFunction$1(descriptor.set) || isFunction$1(descriptor.get)) {
2951
- return 'accessor';
2947
+ return "accessor"
2948
+ /* Accessor */
2949
+ ;
2952
2950
  } else {
2953
- return 'field';
2951
+ return "field"
2952
+ /* Field */
2953
+ ;
2954
2954
  }
2955
2955
  }
2956
2956
 
2957
2957
  function validateObservedField(Ctor, fieldName, descriptor) {
2958
2958
  if (!isUndefined$1(descriptor)) {
2959
2959
  const type = getClassDescriptorType(descriptor);
2960
- assert.fail(`Invalid observed ${fieldName} field. Found a duplicate ${type} with the same name.`);
2960
+ const message = `Invalid observed ${fieldName} field. Found a duplicate ${type} with the same name.`; // [W-9927596] Ideally we always throw an error when detecting duplicate observed field.
2961
+ // This branch is only here for backward compatibility reasons.
2962
+
2963
+ if (type === "accessor"
2964
+ /* Accessor */
2965
+ ) {
2966
+ logError(message);
2967
+ } else {
2968
+ assert.fail(message);
2969
+ }
2961
2970
  }
2962
2971
  }
2963
2972
 
@@ -2984,7 +2993,16 @@ function validateMethodDecoratedWithWire(Ctor, methodName, descriptor) {
2984
2993
  function validateFieldDecoratedWithApi(Ctor, fieldName, descriptor) {
2985
2994
  if (!isUndefined$1(descriptor)) {
2986
2995
  const type = getClassDescriptorType(descriptor);
2987
- assert.fail(`Invalid @api ${fieldName} field. Found a duplicate ${type} with the same name.`);
2996
+ const message = `Invalid @api ${fieldName} field. Found a duplicate ${type} with the same name.`; // [W-9927596] Ideally we always throw an error when detecting duplicate public properties.
2997
+ // This branch is only here for backward compatibility reasons.
2998
+
2999
+ if (type === "accessor"
3000
+ /* Accessor */
3001
+ ) {
3002
+ logError(message);
3003
+ } else {
3004
+ assert.fail(message);
3005
+ }
2988
3006
  }
2989
3007
  }
2990
3008
 
@@ -3047,9 +3065,16 @@ function registerDecorators(Ctor, meta) {
3047
3065
  // field declaration
3048
3066
  if (process.env.NODE_ENV !== 'production') {
3049
3067
  validateFieldDecoratedWithApi(Ctor, fieldName, descriptor);
3050
- }
3068
+ } // [W-9927596] If a component has both a public property and a private setter/getter
3069
+ // with the same name, the property is defined as a public accessor. This branch is
3070
+ // only here for backward compatibility reasons.
3071
+
3051
3072
 
3052
- descriptor = createPublicPropertyDescriptor(fieldName);
3073
+ if (!isUndefined$1(descriptor) && !isUndefined$1(descriptor.get)) {
3074
+ descriptor = createPublicAccessorDescriptor(fieldName, descriptor);
3075
+ } else {
3076
+ descriptor = createPublicPropertyDescriptor(fieldName);
3077
+ }
3053
3078
  }
3054
3079
 
3055
3080
  apiFields[fieldName] = descriptor;
@@ -3129,9 +3154,16 @@ function registerDecorators(Ctor, meta) {
3129
3154
 
3130
3155
  if (process.env.NODE_ENV !== 'production') {
3131
3156
  validateObservedField(Ctor, fieldName, descriptor);
3132
- }
3157
+ } // [W-9927596] Only mark a field as observed whenever it isn't a duplicated public nor
3158
+ // tracked property. This is only here for backward compatibility purposes.
3159
+
3160
+
3161
+ const isDuplicatePublicProp = !isUndefined$1(publicProps) && fieldName in publicProps;
3162
+ const isDuplicateTrackedProp = !isUndefined$1(track) && fieldName in track;
3133
3163
 
3134
- observedFields[fieldName] = createObservedFieldPropertyDescriptor(fieldName);
3164
+ if (!isDuplicatePublicProp && !isDuplicateTrackedProp) {
3165
+ observedFields[fieldName] = createObservedFieldPropertyDescriptor(fieldName);
3166
+ }
3135
3167
  }
3136
3168
  }
3137
3169
 
@@ -3963,8 +3995,20 @@ function observeElementChildNodes(elm) {
3963
3995
 
3964
3996
  function setElementShadowToken(elm, token) {
3965
3997
  elm.$shadowToken$ = token;
3966
- }
3998
+ } // Set the scope token class for *.scoped.css styles
3967
3999
 
4000
+
4001
+ function setScopeTokenClassIfNecessary(elm, owner) {
4002
+ const {
4003
+ cmpTemplate,
4004
+ context
4005
+ } = owner;
4006
+ const token = cmpTemplate === null || cmpTemplate === void 0 ? void 0 : cmpTemplate.stylesheetToken;
4007
+
4008
+ if (!isUndefined$1(token) && context.hasScopedStyles) {
4009
+ owner.renderer.getClassList(elm).add(token);
4010
+ }
4011
+ }
3968
4012
  function updateNodeHook(oldVnode, vnode) {
3969
4013
  const {
3970
4014
  elm,
@@ -4028,10 +4072,21 @@ function createElmHook(vnode) {
4028
4072
  modComputedClassName.create(vnode);
4029
4073
  modComputedStyle.create(vnode);
4030
4074
  }
4075
+ function hydrateElmHook(vnode) {
4076
+ modEvents.create(vnode); // Attrs are already on the element.
4077
+ // modAttrs.create(vnode);
4078
+
4079
+ modProps.create(vnode); // Already set.
4080
+ // modStaticClassName.create(vnode);
4081
+ // modStaticStyle.create(vnode);
4082
+ // modComputedClassName.create(vnode);
4083
+ // modComputedStyle.create(vnode);
4084
+ }
4031
4085
  function fallbackElmHook(elm, vnode) {
4032
4086
  const {
4033
4087
  owner
4034
4088
  } = vnode;
4089
+ setScopeTokenClassIfNecessary(elm, owner);
4035
4090
 
4036
4091
  if (owner.shadowMode === 1
4037
4092
  /* Synthetic */
@@ -4042,7 +4097,7 @@ function fallbackElmHook(elm, vnode) {
4042
4097
  }
4043
4098
  } = vnode;
4044
4099
  const {
4045
- shadowAttribute
4100
+ stylesheetToken
4046
4101
  } = owner.context;
4047
4102
 
4048
4103
  if (!isUndefined$1(context) && !isUndefined$1(context.lwc) && context.lwc.dom === "manual"
@@ -4054,7 +4109,7 @@ function fallbackElmHook(elm, vnode) {
4054
4109
  // into each element from the template, so they can be styled accordingly.
4055
4110
 
4056
4111
 
4057
- setElementShadowToken(elm, shadowAttribute);
4112
+ setElementShadowToken(elm, stylesheetToken);
4058
4113
  }
4059
4114
 
4060
4115
  if (process.env.NODE_ENV !== 'production') {
@@ -4139,16 +4194,17 @@ function createViewModelHook(elm, vnode) {
4139
4194
  ctor,
4140
4195
  owner
4141
4196
  } = vnode;
4197
+ setScopeTokenClassIfNecessary(elm, owner);
4142
4198
 
4143
4199
  if (owner.shadowMode === 1
4144
4200
  /* Synthetic */
4145
4201
  ) {
4146
4202
  const {
4147
- shadowAttribute
4203
+ stylesheetToken
4148
4204
  } = owner.context; // when running in synthetic shadow mode, we need to set the shadowToken value
4149
4205
  // into each element from the template, so they can be styled accordingly.
4150
4206
 
4151
- setElementShadowToken(elm, shadowAttribute);
4207
+ setElementShadowToken(elm, stylesheetToken);
4152
4208
  }
4153
4209
 
4154
4210
  const def = getComponentInternalDef(ctor);
@@ -4190,6 +4246,172 @@ function createChildrenHook(vnode) {
4190
4246
  }
4191
4247
  }
4192
4248
  }
4249
+
4250
+ function isElementNode(node) {
4251
+ // @todo: should the hydrate be part of engine-dom? can we move hydrate out of the hooks?
4252
+ // eslint-disable-next-line lwc-internal/no-global-node
4253
+ return node.nodeType === Node.ELEMENT_NODE;
4254
+ }
4255
+
4256
+ function vnodesAndElementHaveCompatibleAttrs(vnode, elm) {
4257
+ const {
4258
+ data: {
4259
+ attrs = {}
4260
+ },
4261
+ owner: {
4262
+ renderer
4263
+ }
4264
+ } = vnode;
4265
+ let nodesAreCompatible = true; // Validate attributes, though we could always recovery from those by running the update mods.
4266
+ // Note: intentionally ONLY matching vnodes.attrs to elm.attrs, in case SSR is adding extra attributes.
4267
+
4268
+ for (const [attrName, attrValue] of Object.entries(attrs)) {
4269
+ const elmAttrValue = renderer.getAttribute(elm, attrName);
4270
+
4271
+ if (attrValue !== elmAttrValue) {
4272
+ logError(`Error hydrating element: attribute "${attrName}" has different values, expected "${attrValue}" but found "${elmAttrValue}"`, vnode.owner);
4273
+ nodesAreCompatible = false;
4274
+ }
4275
+ }
4276
+
4277
+ return nodesAreCompatible;
4278
+ }
4279
+
4280
+ function vnodesAndElementHaveCompatibleClass(vnode, elm) {
4281
+ const {
4282
+ data: {
4283
+ className,
4284
+ classMap
4285
+ },
4286
+ owner: {
4287
+ renderer
4288
+ }
4289
+ } = vnode;
4290
+ let nodesAreCompatible = true;
4291
+
4292
+ if (!isUndefined$1(className) && className !== elm.className) {
4293
+ // @todo: not sure if the above comparison is correct, maybe we should normalize to classlist
4294
+ // className is used when class is bound to an expr.
4295
+ logError(`Mismatch hydrating element: attribute "class" has different values, expected "${className}" but found "${elm.className}"`, vnode.owner);
4296
+ nodesAreCompatible = false;
4297
+ } else if (!isUndefined$1(classMap)) {
4298
+ // classMap is used when class is set to static value.
4299
+ // @todo: there might be a simpler method to do this.
4300
+ const classList = renderer.getClassList(elm);
4301
+ let hasClassMismatch = false;
4302
+ let computedClassName = ''; // all classes from the vnode should be in the element.classList
4303
+
4304
+ for (const name in classMap) {
4305
+ computedClassName += ' ' + name;
4306
+
4307
+ if (!classList.contains(name)) {
4308
+ nodesAreCompatible = false;
4309
+ hasClassMismatch = true;
4310
+ }
4311
+ } // all classes from element.classList should be in the vnode classMap
4312
+
4313
+
4314
+ classList.forEach(name => {
4315
+ if (!classMap[name]) {
4316
+ nodesAreCompatible = false;
4317
+ hasClassMismatch = true;
4318
+ }
4319
+ });
4320
+
4321
+ if (hasClassMismatch) {
4322
+ logError(`Mismatch hydrating element: attribute "class" has different values, expected "${computedClassName.trim()}" but found "${elm.className}"`, vnode.owner);
4323
+ }
4324
+ }
4325
+
4326
+ return nodesAreCompatible;
4327
+ }
4328
+
4329
+ function vnodesAndElementHaveCompatibleStyle(vnode, elm) {
4330
+ const {
4331
+ data: {
4332
+ style,
4333
+ styleDecls
4334
+ },
4335
+ owner: {
4336
+ renderer
4337
+ }
4338
+ } = vnode;
4339
+ const elmStyle = renderer.getAttribute(elm, 'style');
4340
+ let nodesAreCompatible = true; // @todo: question: would it be the same or is there a chance that the browser tweak the result of elm.setAttribute('style', ...)?
4341
+ // ex: such "str" exist that after elm.setAttribute('style', str), elm.getAttribute('style') !== str.
4342
+
4343
+ if (!isUndefined$1(style) && style !== elmStyle) {
4344
+ // style is used when class is bound to an expr.
4345
+ logError(`Mismatch hydrating element: attribute "style" has different values, expected "${style}" but found "${elmStyle}".`, vnode.owner);
4346
+ nodesAreCompatible = false;
4347
+ } else if (!isUndefined$1(styleDecls)) {
4348
+ // styleMap is used when class is set to static value.
4349
+ for (let i = 0; i < styleDecls.length; i++) {
4350
+ const [prop, value, important] = styleDecls[i];
4351
+ const elmPropValue = elm.style.getPropertyValue(prop);
4352
+ const elmPropPriority = elm.style.getPropertyPriority(prop);
4353
+
4354
+ if (value !== elmPropValue || important !== (elmPropPriority === 'important')) {
4355
+ nodesAreCompatible = false;
4356
+ }
4357
+ } // questions: is there a way to check that only those props in styleMap are set in the element?
4358
+ // how to generate the style?
4359
+
4360
+
4361
+ logError('Error hydrating element: attribute "style" has different values.', vnode.owner);
4362
+ }
4363
+
4364
+ return nodesAreCompatible;
4365
+ }
4366
+
4367
+ function throwHydrationError() {
4368
+ // @todo: maybe create a type for these type of hydration errors
4369
+ assert.fail('Server rendered elements do not match client side generated elements');
4370
+ }
4371
+
4372
+ function hydrateChildrenHook(elmChildren, children, vm) {
4373
+ var _a;
4374
+
4375
+ if (process.env.NODE_ENV !== 'production') {
4376
+ const filteredVNodes = ArrayFilter.call(children, vnode => !!vnode);
4377
+
4378
+ if (elmChildren.length !== filteredVNodes.length) {
4379
+ logError(`Hydration mismatch: incorrect number of rendered elements, expected ${filteredVNodes.length} but found ${elmChildren.length}.`, vm);
4380
+ throwHydrationError();
4381
+ }
4382
+ }
4383
+
4384
+ let elmCurrentChildIdx = 0;
4385
+
4386
+ for (let j = 0, n = children.length; j < n; j++) {
4387
+ const ch = children[j];
4388
+
4389
+ if (ch != null) {
4390
+ const childNode = elmChildren[elmCurrentChildIdx];
4391
+
4392
+ if (process.env.NODE_ENV !== 'production') {
4393
+ // VComments and VTexts validation is handled in their hooks
4394
+ if (isElementNode(childNode)) {
4395
+ if (((_a = ch.sel) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== childNode.tagName.toLowerCase()) {
4396
+ logError(`Hydration mismatch: expecting element with tag "${ch.sel}" but found "${childNode.tagName}".`, vm);
4397
+ throwHydrationError();
4398
+ } // Note: props are not yet set
4399
+
4400
+
4401
+ const isVNodeAndElementCompatible = vnodesAndElementHaveCompatibleAttrs(ch, childNode) && vnodesAndElementHaveCompatibleClass(ch, childNode) && vnodesAndElementHaveCompatibleStyle(ch, childNode);
4402
+
4403
+ if (!isVNodeAndElementCompatible) {
4404
+ logError(`Hydration mismatch: incompatible attributes for element with tag "${childNode.tagName}".`, vm);
4405
+ throwHydrationError();
4406
+ }
4407
+ }
4408
+ }
4409
+
4410
+ ch.hook.hydrate(ch, childNode);
4411
+ elmCurrentChildIdx++;
4412
+ }
4413
+ }
4414
+ }
4193
4415
  function updateCustomElmHook(oldVnode, vnode) {
4194
4416
  // Attrs need to be applied to element before props
4195
4417
  // IE11 will wipe out value on radio inputs if value
@@ -4286,7 +4508,27 @@ const TextHook = {
4286
4508
  update: updateNodeHook,
4287
4509
  insert: insertNodeHook,
4288
4510
  move: insertNodeHook,
4289
- remove: removeNodeHook
4511
+ remove: removeNodeHook,
4512
+ hydrate: (vNode, node) => {
4513
+ var _a; // @todo tests.
4514
+
4515
+
4516
+ if (process.env.NODE_ENV !== 'production') {
4517
+ // eslint-disable-next-line lwc-internal/no-global-node
4518
+ if (node.nodeType !== Node.TEXT_NODE) {
4519
+ logError('Hydration mismatch: incorrect node type received', vNode.owner);
4520
+ assert.fail('Hydration mismatch: incorrect node type received.');
4521
+ }
4522
+
4523
+ if (node.nodeValue !== vNode.text) {
4524
+ logError('Hydration mismatch: text values do not match, will recover from the difference', vNode.owner);
4525
+ }
4526
+ } // always set the text value to the one from the vnode.
4527
+
4528
+
4529
+ node.nodeValue = (_a = vNode.text) !== null && _a !== void 0 ? _a : null;
4530
+ vNode.elm = node;
4531
+ }
4290
4532
  };
4291
4533
  const CommentHook = {
4292
4534
  create: vnode => {
@@ -4304,7 +4546,23 @@ const CommentHook = {
4304
4546
  update: updateNodeHook,
4305
4547
  insert: insertNodeHook,
4306
4548
  move: insertNodeHook,
4307
- remove: removeNodeHook
4549
+ remove: removeNodeHook,
4550
+ hydrate: (vNode, node) => {
4551
+ var _a; // @todo tests.
4552
+
4553
+
4554
+ if (process.env.NODE_ENV !== 'production') {
4555
+ // eslint-disable-next-line lwc-internal/no-global-node
4556
+ if (node.nodeType !== Node.COMMENT_NODE) {
4557
+ logError('Hydration mismatch: incorrect node type received', vNode.owner);
4558
+ assert.fail('Hydration mismatch: incorrect node type received.');
4559
+ }
4560
+ } // always set the text value to the one from the vnode.
4561
+
4562
+
4563
+ node.nodeValue = (_a = vNode.text) !== null && _a !== void 0 ? _a : null;
4564
+ vNode.elm = node;
4565
+ }
4308
4566
  }; // insert is called after update, which is used somewhere else (via a module)
4309
4567
  // to mark the vm as inserted, that means we cannot use update as the main channel
4310
4568
  // to rehydrate when dirty, because sometimes the element is not inserted just yet,
@@ -4344,6 +4602,12 @@ const ElementHook = {
4344
4602
  remove: (vnode, parentNode) => {
4345
4603
  removeNodeHook(vnode, parentNode);
4346
4604
  removeElmHook(vnode);
4605
+ },
4606
+ hydrate: (vnode, node) => {
4607
+ vnode.elm = node;
4608
+ hydrateElmHook(vnode); // hydrate children hook
4609
+
4610
+ hydrateChildrenHook(vnode.elm.childNodes, vnode.children, vnode.owner);
4347
4611
  }
4348
4612
  };
4349
4613
  const CustomElementHook = {
@@ -4435,6 +4699,52 @@ const CustomElementHook = {
4435
4699
  // will take care of disconnecting any child VM attached to its shadow as well.
4436
4700
  removeVM(vm);
4437
4701
  }
4702
+ },
4703
+ hydrate: (vnode, elm) => {
4704
+ // the element is created, but the vm is not
4705
+ const {
4706
+ sel,
4707
+ mode,
4708
+ ctor,
4709
+ owner
4710
+ } = vnode;
4711
+ const def = getComponentInternalDef(ctor);
4712
+ createVM(elm, def, {
4713
+ mode,
4714
+ owner,
4715
+ tagName: sel,
4716
+ renderer: owner.renderer
4717
+ });
4718
+ vnode.elm = elm;
4719
+ const vm = getAssociatedVMIfPresent(elm);
4720
+
4721
+ if (vm) {
4722
+ allocateChildrenHook(vnode, vm);
4723
+ }
4724
+
4725
+ hydrateElmHook(vnode); // Insert hook section:
4726
+
4727
+ if (vm) {
4728
+ if (process.env.NODE_ENV !== 'production') {
4729
+ assert.isTrue(vm.state === 0
4730
+ /* created */
4731
+ , `${vm} cannot be recycled.`);
4732
+ }
4733
+
4734
+ runConnectedCallback(vm);
4735
+ }
4736
+
4737
+ if (!(vm && vm.renderMode === 0
4738
+ /* Light */
4739
+ )) {
4740
+ // VM is not rendering in Light DOM, we can proceed and hydrate the slotted content.
4741
+ // Note: for Light DOM, this is handled while hydrating the VM
4742
+ hydrateChildrenHook(vnode.elm.childNodes, vnode.children, vm);
4743
+ }
4744
+
4745
+ if (vm) {
4746
+ hydrateVM(vm);
4747
+ }
4438
4748
  }
4439
4749
  };
4440
4750
 
@@ -4923,6 +5233,10 @@ var api = /*#__PURE__*/Object.freeze({
4923
5233
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
4924
5234
  */
4925
5235
 
5236
+ function makeHostToken(token) {
5237
+ return `${token}-host`;
5238
+ }
5239
+
4926
5240
  function createInlineStyleVNode(content) {
4927
5241
  return h('style', {
4928
5242
  key: 'style',
@@ -4932,59 +5246,100 @@ function createInlineStyleVNode(content) {
4932
5246
  }, [t(content)]);
4933
5247
  }
4934
5248
 
4935
- function updateSyntheticShadowAttributes(vm, template) {
5249
+ function updateStylesheetToken(vm, template) {
4936
5250
  const {
4937
5251
  elm,
4938
5252
  context,
4939
5253
  renderer,
4940
- renderMode
5254
+ renderMode,
5255
+ shadowMode
4941
5256
  } = vm;
4942
5257
  const {
4943
5258
  stylesheets: newStylesheets,
4944
- stylesheetTokens: newStylesheetTokens
5259
+ stylesheetToken: newStylesheetToken
4945
5260
  } = template;
4946
- let newTokens; // Reset the styling token applied to the host element.
5261
+ const isSyntheticShadow = renderMode === 1
5262
+ /* Shadow */
5263
+ && shadowMode === 1
5264
+ /* Synthetic */
5265
+ ;
5266
+ const {
5267
+ hasScopedStyles
5268
+ } = context;
5269
+ let newToken;
5270
+ let newHasTokenInClass;
5271
+ let newHasTokenInAttribute; // Reset the styling token applied to the host element.
4947
5272
 
4948
- const oldHostAttribute = context.hostAttribute;
5273
+ const {
5274
+ stylesheetToken: oldToken,
5275
+ hasTokenInClass: oldHasTokenInClass,
5276
+ hasTokenInAttribute: oldHasTokenInAttribute
5277
+ } = context;
4949
5278
 
4950
- if (!isUndefined$1(oldHostAttribute)) {
4951
- renderer.removeAttribute(elm, oldHostAttribute);
5279
+ if (oldHasTokenInClass) {
5280
+ renderer.getClassList(elm).remove(makeHostToken(oldToken));
5281
+ }
5282
+
5283
+ if (oldHasTokenInAttribute) {
5284
+ renderer.removeAttribute(elm, makeHostToken(oldToken));
4952
5285
  } // Apply the new template styling token to the host element, if the new template has any
4953
- // associated stylesheets.
5286
+ // associated stylesheets. In the case of light DOM, also ensure there is at least one scoped stylesheet.
4954
5287
 
4955
5288
 
4956
- if (!isUndefined$1(newStylesheets) && newStylesheets.length !== 0 && renderMode === 1
4957
- /* Shadow */
4958
- ) {
4959
- newTokens = newStylesheetTokens;
4960
- }
5289
+ if (!isUndefined$1(newStylesheets) && newStylesheets.length !== 0) {
5290
+ newToken = newStylesheetToken;
5291
+ } // Set the new styling token on the host element
5292
+
5293
+
5294
+ if (!isUndefined$1(newToken)) {
5295
+ if (hasScopedStyles) {
5296
+ renderer.getClassList(elm).add(makeHostToken(newToken));
5297
+ newHasTokenInClass = true;
5298
+ }
4961
5299
 
4962
- if (!isUndefined$1(newTokens)) {
4963
- renderer.setAttribute(elm, newTokens.hostAttribute, '');
5300
+ if (isSyntheticShadow) {
5301
+ renderer.setAttribute(elm, makeHostToken(newToken), '');
5302
+ newHasTokenInAttribute = true;
5303
+ }
4964
5304
  } // Update the styling tokens present on the context object.
4965
5305
 
4966
5306
 
4967
- context.hostAttribute = newTokens === null || newTokens === void 0 ? void 0 : newTokens.hostAttribute;
4968
- context.shadowAttribute = newTokens === null || newTokens === void 0 ? void 0 : newTokens.shadowAttribute;
5307
+ context.stylesheetToken = newToken;
5308
+ context.hasTokenInClass = newHasTokenInClass;
5309
+ context.hasTokenInAttribute = newHasTokenInAttribute;
4969
5310
  }
4970
5311
 
4971
- function evaluateStylesheetsContent(stylesheets, hostSelector, shadowSelector, nativeShadow) {
5312
+ function evaluateStylesheetsContent(stylesheets, stylesheetToken, vm) {
4972
5313
  const content = [];
4973
5314
 
4974
5315
  for (let i = 0; i < stylesheets.length; i++) {
4975
5316
  let stylesheet = stylesheets[i];
4976
5317
 
4977
5318
  if (isArray$1(stylesheet)) {
4978
- ArrayPush$1.apply(content, evaluateStylesheetsContent(stylesheet, hostSelector, shadowSelector, nativeShadow));
5319
+ ArrayPush$1.apply(content, evaluateStylesheetsContent(stylesheet, stylesheetToken, vm));
4979
5320
  } else {
4980
5321
  if (process.env.NODE_ENV !== 'production') {
4981
5322
  // in dev-mode, we support hot swapping of stylesheet, which means that
4982
5323
  // the component instance might be attempting to use an old version of
4983
5324
  // the stylesheet, while internally, we have a replacement for it.
4984
5325
  stylesheet = getStyleOrSwappedStyle(stylesheet);
4985
- }
5326
+ } // Use the actual `:host` selector if we're rendering global CSS for light DOM, or if we're rendering
5327
+ // native shadow DOM. Synthetic shadow DOM never uses `:host`.
5328
+
4986
5329
 
4987
- ArrayPush$1.call(content, stylesheet(hostSelector, shadowSelector, nativeShadow));
5330
+ const isScopedCss = stylesheet[KEY__SCOPED_CSS];
5331
+ const useActualHostSelector = vm.renderMode === 0
5332
+ /* Light */
5333
+ ? !isScopedCss : vm.shadowMode === 0
5334
+ /* Native */
5335
+ ; // Apply the scope token only if the stylesheet itself is scoped, or if we're rendering synthetic shadow.
5336
+
5337
+ const scopeToken = isScopedCss || vm.shadowMode === 1
5338
+ /* Synthetic */
5339
+ && vm.renderMode === 1
5340
+ /* Shadow */
5341
+ ? stylesheetToken : undefined;
5342
+ ArrayPush$1.call(content, stylesheet(useActualHostSelector, scopeToken));
4988
5343
  }
4989
5344
  }
4990
5345
 
@@ -4994,34 +5349,12 @@ function evaluateStylesheetsContent(stylesheets, hostSelector, shadowSelector, n
4994
5349
  function getStylesheetsContent(vm, template) {
4995
5350
  const {
4996
5351
  stylesheets,
4997
- stylesheetTokens
5352
+ stylesheetToken
4998
5353
  } = template;
4999
- const {
5000
- renderMode,
5001
- shadowMode
5002
- } = vm;
5003
5354
  let content = [];
5004
5355
 
5005
5356
  if (!isUndefined$1(stylesheets) && stylesheets.length !== 0) {
5006
- let hostSelector;
5007
- let shadowSelector; // Scoping with the tokens is only necessary for synthetic shadow. For both
5008
- // light DOM elements and native shadow, we just render the CSS as-is.
5009
-
5010
- if (renderMode === 1
5011
- /* Shadow */
5012
- && shadowMode === 1
5013
- /* Synthetic */
5014
- && !isUndefined$1(stylesheetTokens)) {
5015
- hostSelector = `[${stylesheetTokens.hostAttribute}]`;
5016
- shadowSelector = `[${stylesheetTokens.shadowAttribute}]`;
5017
- } else {
5018
- hostSelector = '';
5019
- shadowSelector = '';
5020
- }
5021
-
5022
- content = evaluateStylesheetsContent(stylesheets, hostSelector, shadowSelector, shadowMode === 0
5023
- /* Native */
5024
- );
5357
+ content = evaluateStylesheetsContent(stylesheets, stylesheetToken, vm);
5025
5358
  }
5026
5359
 
5027
5360
  return content;
@@ -5062,7 +5395,7 @@ function createStylesheet(vm, stylesheets) {
5062
5395
  for (let i = 0; i < stylesheets.length; i++) {
5063
5396
  renderer.insertGlobalStylesheet(stylesheets[i]);
5064
5397
  }
5065
- } else if (renderer.ssr) {
5398
+ } else if (renderer.ssr || renderer.isHydrating) {
5066
5399
  // native shadow or light DOM, SSR
5067
5400
  const combinedStylesheetContent = ArrayJoin.call(stylesheets, '\n');
5068
5401
  return createInlineStyleVNode(combinedStylesheetContent);
@@ -5248,9 +5581,9 @@ function validateLightDomTemplate(template, vm) {
5248
5581
  if (vm.renderMode === 0
5249
5582
  /* Light */
5250
5583
  ) {
5251
- assert.isTrue(template.renderMode === 'light', `Light DOM components can't render shadow DOM templates. Add an 'lwc:render-mode="light"' directive on the root template tag.`);
5584
+ assert.isTrue(template.renderMode === 'light', `Light DOM components can't render shadow DOM templates. Add an 'lwc:render-mode="light"' directive to the root template tag of ${getComponentTag(vm)}.`);
5252
5585
  } else {
5253
- assert.isTrue(isUndefined$1(template.renderMode), `Shadow DOM components template can't render light DOM templates. Either remove the 'lwc:render-mode' directive or set it to 'lwc:render-mode="shadow"`);
5586
+ assert.isTrue(isUndefined$1(template.renderMode), `Shadow DOM components template can't render light DOM templates. Either remove the 'lwc:render-mode' directive from ${getComponentTag(vm)} or set it to 'lwc:render-mode="shadow"`);
5254
5587
  }
5255
5588
  }
5256
5589
 
@@ -5279,8 +5612,7 @@ function evaluateTemplate(vm, html) {
5279
5612
  context,
5280
5613
  cmpSlots,
5281
5614
  cmpTemplate,
5282
- tro,
5283
- shadowMode
5615
+ tro
5284
5616
  } = vm;
5285
5617
  tro.observe(() => {
5286
5618
  // Reset the cache memoizer for template when needed.
@@ -5305,15 +5637,12 @@ function evaluateTemplate(vm, html) {
5305
5637
 
5306
5638
  vm.cmpTemplate = html; // Create a brand new template cache for the swapped templated.
5307
5639
 
5308
- context.tplCache = create(null); // Update the synthetic shadow attributes on the host element if necessary.
5640
+ context.tplCache = create(null); // Set the computeHasScopedStyles property in the context, to avoid recomputing it repeatedly.
5309
5641
 
5310
- if (shadowMode === 1
5311
- /* Synthetic */
5312
- ) {
5313
- updateSyntheticShadowAttributes(vm, html);
5314
- } // Evaluate, create stylesheet and cache the produced VNode for future
5315
- // re-rendering.
5642
+ context.hasScopedStyles = computeHasScopedStyles(html); // Update the scoping token on the host element.
5316
5643
 
5644
+ updateStylesheetToken(vm, html); // Evaluate, create stylesheet and cache the produced VNode for future
5645
+ // re-rendering.
5317
5646
 
5318
5647
  const stylesheetsContent = getStylesheetsContent(vm, html);
5319
5648
  context.styleVNode = stylesheetsContent.length === 0 ? null : createStylesheet(vm, stylesheetsContent);
@@ -5355,6 +5684,21 @@ function evaluateTemplate(vm, html) {
5355
5684
 
5356
5685
  return vnodes;
5357
5686
  }
5687
+ function computeHasScopedStyles(template) {
5688
+ const {
5689
+ stylesheets
5690
+ } = template;
5691
+
5692
+ if (!isUndefined$1(stylesheets)) {
5693
+ for (let i = 0; i < stylesheets.length; i++) {
5694
+ if (isTrue(stylesheets[i][KEY__SCOPED_CSS])) {
5695
+ return true;
5696
+ }
5697
+ }
5698
+ }
5699
+
5700
+ return false;
5701
+ }
5358
5702
 
5359
5703
  /*
5360
5704
  * Copyright (c) 2018, salesforce.com, inc.
@@ -5648,12 +5992,28 @@ function connectRootElement(elm) {
5648
5992
  /* GlobalHydrate */
5649
5993
  , vm);
5650
5994
  }
5995
+ function hydrateRootElement(elm) {
5996
+ const vm = getAssociatedVM(elm); // Usually means moving the element from one place to another, which is observable via
5997
+ // life-cycle hooks.
5998
+
5999
+ if (vm.state === 1
6000
+ /* connected */
6001
+ ) {
6002
+ disconnectRootElement(elm);
6003
+ }
6004
+
6005
+ runConnectedCallback(vm);
6006
+ hydrateVM(vm); // should we hydrate the root children? light dom case.
6007
+ }
5651
6008
  function disconnectRootElement(elm) {
5652
6009
  const vm = getAssociatedVM(elm);
5653
6010
  resetComponentStateWhenRemoved(vm);
5654
6011
  }
5655
6012
  function appendVM(vm) {
5656
6013
  rehydrate(vm);
6014
+ }
6015
+ function hydrateVM(vm) {
6016
+ hydrate(vm);
5657
6017
  } // just in case the component comes back, with this we guarantee re-rendering it
5658
6018
  // while preventing any attempt to rehydration until after reinsertion.
5659
6019
 
@@ -5744,8 +6104,10 @@ function createVM(elm, def, options) {
5744
6104
  renderMode: def.renderMode,
5745
6105
  shadowMode: null,
5746
6106
  context: {
5747
- hostAttribute: undefined,
5748
- shadowAttribute: undefined,
6107
+ stylesheetToken: undefined,
6108
+ hasTokenInClass: undefined,
6109
+ hasTokenInAttribute: undefined,
6110
+ hasScopedStyles: undefined,
5749
6111
  styleVNode: null,
5750
6112
  tplCache: EmptyObject,
5751
6113
  wiredConnecting: EmptyArray,
@@ -5876,6 +6238,22 @@ function rehydrate(vm) {
5876
6238
  }
5877
6239
  }
5878
6240
 
6241
+ function hydrate(vm) {
6242
+ if (isTrue(vm.isDirty)) {
6243
+ // manually diffing/patching here.
6244
+ // This routine is:
6245
+ // patchShadowRoot(vm, children);
6246
+ // -> addVnodes.
6247
+ const children = renderComponent(vm);
6248
+ vm.children = children;
6249
+ const vmChildren = vm.renderMode === 0
6250
+ /* Light */
6251
+ ? vm.elm.childNodes : vm.elm.shadowRoot.childNodes;
6252
+ hydrateChildrenHook(vmChildren, children, vm);
6253
+ runRenderedCallback(vm);
6254
+ }
6255
+ }
6256
+
5879
6257
  function patchShadowRoot(vm, newCh) {
5880
6258
  const {
5881
6259
  children: oldCh
@@ -6679,5 +7057,5 @@ function readonly(obj) {
6679
7057
  return reactiveMembrane.getReadOnlyProxy(obj);
6680
7058
  }
6681
7059
 
6682
- export { LightningElement, profilerControl as __unstable__ProfilerControl, api$1 as api, connectRootElement, createContextProvider, createVM, disconnectRootElement, getAssociatedVMIfPresent, getComponentDef, getComponentInternalDef, getUpgradableConstructor, isComponentConstructor, readonly, register, registerComponent, registerDecorators, registerTemplate, sanitizeAttribute, swapComponent, swapStyle, swapTemplate, track, unwrap, wire };
6683
- /* version: 2.3.7 */
7060
+ export { LightningElement, profilerControl as __unstable__ProfilerControl, api$1 as api, connectRootElement, createContextProvider, createVM, disconnectRootElement, getAssociatedVMIfPresent, getComponentDef, getComponentInternalDef, getUpgradableConstructor, hydrateRootElement, isComponentConstructor, readonly, register, registerComponent, registerDecorators, registerTemplate, sanitizeAttribute, swapComponent, swapStyle, swapTemplate, track, unwrap, wire };
7061
+ /* version: 2.5.2-canary1 */