@lwc/engine-core 3.3.2 → 3.4.0

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,6 +1,7 @@
1
+ import { LightningElement } from './base-lightning-element';
1
2
  export interface HTMLElementConstructor {
2
3
  prototype: HTMLElement;
3
4
  new (): HTMLElement;
4
5
  }
5
- export declare function HTMLBridgeElementFactory(SuperClass: HTMLElementConstructor, props: string[], methods: string[]): HTMLElementConstructor;
6
+ export declare function HTMLBridgeElementFactory(SuperClass: HTMLElementConstructor, publicProperties: string[], methods: string[], observedFields: string[], proto: LightningElement | null): HTMLElementConstructor;
6
7
  export declare const BaseBridgeElement: HTMLElementConstructor;
@@ -12,14 +12,14 @@ export type StylesheetFactory = (stylesheetToken: string | undefined, useActualH
12
12
  * @import CSS declaration).
13
13
  */
14
14
  export type TemplateStylesheetFactories = Array<StylesheetFactory | TemplateStylesheetFactories>;
15
- export declare function updateStylesheetToken(vm: VM, template: Template): void;
15
+ export declare function updateStylesheetToken(vm: VM, template: Template, legacy: boolean): void;
16
16
  export declare function getStylesheetsContent(vm: VM, template: Template): string[];
17
17
  /**
18
18
  * If the component that is currently being rendered uses scoped styles,
19
19
  * this returns the unique token for that scoped stylesheet. Otherwise
20
20
  * it returns null.
21
21
  */
22
- export declare function getScopeTokenClass(owner: VM): string | null;
22
+ export declare function getScopeTokenClass(owner: VM, legacy: boolean): string | null;
23
23
  /**
24
24
  * This function returns the host style token for a custom element if it
25
25
  * exists. Otherwise it returns null.
@@ -10,6 +10,8 @@ export interface Template {
10
10
  stylesheets?: TemplateStylesheetFactories;
11
11
  /** The string used for synthetic shadow style scoping and light DOM style scoping. */
12
12
  stylesheetToken?: string;
13
+ /** Same as the above, but for legacy use cases (pre-LWC v3.0.0) */
14
+ legacyStylesheetToken?: string;
13
15
  /** Render mode for the template. Could be light or undefined (which means it's shadow) */
14
16
  renderMode?: 'light';
15
17
  /** True if this template contains template refs, undefined or false otherwise */
@@ -42,6 +42,12 @@ export interface Context {
42
42
  hasTokenInClass: boolean | undefined;
43
43
  /** True if a stylesheetToken was added to the host attributes */
44
44
  hasTokenInAttribute: boolean | undefined;
45
+ /** The legacy string used for synthetic shadow DOM and light DOM style scoping. */
46
+ legacyStylesheetToken: string | undefined;
47
+ /** True if a legacyStylesheetToken was added to the host class */
48
+ hasLegacyTokenInClass: boolean | undefined;
49
+ /** True if a legacyStylesheetToken was added to the host attributes */
50
+ hasLegacyTokenInAttribute: boolean | undefined;
45
51
  /** Whether or not light DOM scoped styles are present in the stylesheets. */
46
52
  hasScopedStyles: boolean | undefined;
47
53
  /** The VNodes injected in all the shadow trees to apply the associated component stylesheets. */
package/dist/index.cjs.js CHANGED
@@ -2567,7 +2567,22 @@ function createAttributeChangedCallback(attributeToPropMap, superAttributeChange
2567
2567
  this[propName] = newValue;
2568
2568
  };
2569
2569
  }
2570
- function HTMLBridgeElementFactory(SuperClass, props, methods) {
2570
+ function createAccessorThatWarns(propName) {
2571
+ let prop;
2572
+ return {
2573
+ get() {
2574
+ logWarn(`The property "${propName}" is not publicly accessible. Add the @api annotation to the property declaration or getter/setter in the component to make it accessible.`);
2575
+ return prop;
2576
+ },
2577
+ set(value) {
2578
+ logWarn(`The property "${propName}" is not publicly accessible. Add the @api annotation to the property declaration or getter/setter in the component to make it accessible.`);
2579
+ prop = value;
2580
+ },
2581
+ enumerable: true,
2582
+ configurable: true,
2583
+ };
2584
+ }
2585
+ function HTMLBridgeElementFactory(SuperClass, publicProperties, methods, observedFields, proto) {
2571
2586
  const HTMLBridgeElement = class extends SuperClass {
2572
2587
  };
2573
2588
  // generating the hash table for attributes to avoid duplicate fields and facilitate validation
@@ -2576,9 +2591,30 @@ function HTMLBridgeElementFactory(SuperClass, props, methods) {
2576
2591
  const { attributeChangedCallback: superAttributeChangedCallback } = SuperClass.prototype;
2577
2592
  const { observedAttributes: superObservedAttributes = [] } = SuperClass;
2578
2593
  const descriptors = shared.create(null);
2594
+ // present a hint message so that developers are aware that they have not decorated property with @api
2595
+ if (process.env.NODE_ENV !== 'production') {
2596
+ if (!shared.isUndefined(proto) && !shared.isNull(proto)) {
2597
+ const nonPublicPropertiesToWarnOn = new Set([
2598
+ // getters, setters, and methods
2599
+ ...shared.keys(shared.getOwnPropertyDescriptors(proto)),
2600
+ // class properties
2601
+ ...observedFields,
2602
+ ]
2603
+ // we don't want to override HTMLElement props because these are meaningful in other ways,
2604
+ // and can break tooling that expects it to be iterable or defined, e.g. Jest:
2605
+ // https://github.com/jestjs/jest/blob/b4c9587/packages/pretty-format/src/plugins/DOMElement.ts#L95
2606
+ // It also doesn't make sense to override e.g. "constructor".
2607
+ .filter((propName) => !(propName in HTMLElementPrototype)));
2608
+ for (const propName of nonPublicPropertiesToWarnOn) {
2609
+ if (shared.ArrayIndexOf.call(publicProperties, propName) === -1) {
2610
+ descriptors[propName] = createAccessorThatWarns(propName);
2611
+ }
2612
+ }
2613
+ }
2614
+ }
2579
2615
  // expose getters and setters for each public props on the new Element Bridge
2580
- for (let i = 0, len = props.length; i < len; i += 1) {
2581
- const propName = props[i];
2616
+ for (let i = 0, len = publicProperties.length; i < len; i += 1) {
2617
+ const propName = publicProperties[i];
2582
2618
  attributeToPropMap[shared.htmlPropertyToAttribute(propName)] = propName;
2583
2619
  descriptors[propName] = {
2584
2620
  get: createGetter(propName),
@@ -2621,7 +2657,7 @@ function HTMLBridgeElementFactory(SuperClass, props, methods) {
2621
2657
  shared.defineProperties(HTMLBridgeElement.prototype, descriptors);
2622
2658
  return HTMLBridgeElement;
2623
2659
  }
2624
- const BaseBridgeElement = HTMLBridgeElementFactory(HTMLElementConstructor, shared.getOwnPropertyNames(HTMLElementOriginalDescriptors), []);
2660
+ const BaseBridgeElement = HTMLBridgeElementFactory(HTMLElementConstructor, shared.getOwnPropertyNames(HTMLElementOriginalDescriptors), [], [], null);
2625
2661
  if (process.env.IS_BROWSER) {
2626
2662
  // This ARIA reflection only really makes sense in the browser. On the server, there is no `renderedCallback()`,
2627
2663
  // so you cannot do e.g. `this.template.querySelector('x-child').ariaBusy = 'true'`. So we don't need to expose
@@ -2946,7 +2982,7 @@ function createComponentDef(Ctor) {
2946
2982
  let { connectedCallback, disconnectedCallback, renderedCallback, errorCallback, render } = proto;
2947
2983
  const superProto = getCtorProto(Ctor);
2948
2984
  const superDef = superProto !== LightningElement ? getComponentInternalDef(superProto) : lightingElementDef;
2949
- const bridge = HTMLBridgeElementFactory(superDef.bridge, shared.keys(apiFields), shared.keys(apiMethods));
2985
+ const bridge = HTMLBridgeElementFactory(superDef.bridge, shared.keys(apiFields), shared.keys(apiMethods), shared.keys(observedFields), proto);
2950
2986
  const props = shared.assign(shared.create(null), superDef.props, apiFields);
2951
2987
  const propsConfig = shared.assign(shared.create(null), superDef.propsConfig, apiFieldsConfig);
2952
2988
  const methods = shared.assign(shared.create(null), superDef.methods, apiMethods);
@@ -3115,9 +3151,11 @@ function createInlineStyleVNode(content) {
3115
3151
  },
3116
3152
  }, [api.t(content)]);
3117
3153
  }
3118
- function updateStylesheetToken(vm, template) {
3154
+ // TODO [#3733]: remove support for legacy scope tokens
3155
+ function updateStylesheetToken(vm, template, legacy) {
3119
3156
  const { elm, context, renderMode, shadowMode, renderer: { getClassList, removeAttribute, setAttribute }, } = vm;
3120
- const { stylesheets: newStylesheets, stylesheetToken: newStylesheetToken } = template;
3157
+ const { stylesheets: newStylesheets } = template;
3158
+ const newStylesheetToken = legacy ? template.legacyStylesheetToken : template.stylesheetToken;
3121
3159
  const { stylesheets: newVmStylesheets } = vm;
3122
3160
  const isSyntheticShadow = renderMode === 1 /* RenderMode.Shadow */ && shadowMode === 1 /* ShadowMode.Synthetic */;
3123
3161
  const { hasScopedStyles } = context;
@@ -3125,7 +3163,19 @@ function updateStylesheetToken(vm, template) {
3125
3163
  let newHasTokenInClass;
3126
3164
  let newHasTokenInAttribute;
3127
3165
  // Reset the styling token applied to the host element.
3128
- const { stylesheetToken: oldToken, hasTokenInClass: oldHasTokenInClass, hasTokenInAttribute: oldHasTokenInAttribute, } = context;
3166
+ let oldToken;
3167
+ let oldHasTokenInClass;
3168
+ let oldHasTokenInAttribute;
3169
+ if (legacy) {
3170
+ oldToken = context.legacyStylesheetToken;
3171
+ oldHasTokenInClass = context.hasLegacyTokenInClass;
3172
+ oldHasTokenInAttribute = context.hasLegacyTokenInAttribute;
3173
+ }
3174
+ else {
3175
+ oldToken = context.stylesheetToken;
3176
+ oldHasTokenInClass = context.hasTokenInClass;
3177
+ oldHasTokenInAttribute = context.hasTokenInAttribute;
3178
+ }
3129
3179
  if (!shared.isUndefined(oldToken)) {
3130
3180
  if (oldHasTokenInClass) {
3131
3181
  getClassList(elm).remove(makeHostToken(oldToken));
@@ -3153,9 +3203,16 @@ function updateStylesheetToken(vm, template) {
3153
3203
  }
3154
3204
  }
3155
3205
  // Update the styling tokens present on the context object.
3156
- context.stylesheetToken = newToken;
3157
- context.hasTokenInClass = newHasTokenInClass;
3158
- context.hasTokenInAttribute = newHasTokenInAttribute;
3206
+ if (legacy) {
3207
+ context.legacyStylesheetToken = newToken;
3208
+ context.hasLegacyTokenInClass = newHasTokenInClass;
3209
+ context.hasLegacyTokenInAttribute = newHasTokenInAttribute;
3210
+ }
3211
+ else {
3212
+ context.stylesheetToken = newToken;
3213
+ context.hasTokenInClass = newHasTokenInClass;
3214
+ context.hasTokenInAttribute = newHasTokenInAttribute;
3215
+ }
3159
3216
  }
3160
3217
  function evaluateStylesheetsContent(stylesheets, stylesheetToken, vm) {
3161
3218
  const content = [];
@@ -3243,9 +3300,12 @@ function getNearestShadowComponent(vm) {
3243
3300
  * this returns the unique token for that scoped stylesheet. Otherwise
3244
3301
  * it returns null.
3245
3302
  */
3246
- function getScopeTokenClass(owner) {
3303
+ // TODO [#3733]: remove support for legacy scope tokens
3304
+ function getScopeTokenClass(owner, legacy) {
3247
3305
  const { cmpTemplate, context } = owner;
3248
- return (context.hasScopedStyles && (cmpTemplate === null || cmpTemplate === void 0 ? void 0 : cmpTemplate.stylesheetToken)) || null;
3306
+ return ((context.hasScopedStyles &&
3307
+ (legacy ? cmpTemplate === null || cmpTemplate === void 0 ? void 0 : cmpTemplate.legacyStylesheetToken : cmpTemplate === null || cmpTemplate === void 0 ? void 0 : cmpTemplate.stylesheetToken)) ||
3308
+ null);
3249
3309
  }
3250
3310
  /**
3251
3311
  * This function returns the host style token for a custom element if it
@@ -3963,18 +4023,35 @@ function patchElementPropsAndAttrs$1(oldVnode, vnode, renderer) {
3963
4023
  patchProps(oldVnode, vnode, renderer);
3964
4024
  }
3965
4025
  function applyStyleScoping(elm, owner, renderer) {
4026
+ const { getClassList } = renderer;
3966
4027
  // Set the class name for `*.scoped.css` style scoping.
3967
- const scopeToken = getScopeTokenClass(owner);
4028
+ const scopeToken = getScopeTokenClass(owner, /* legacy */ false);
3968
4029
  if (!shared.isNull(scopeToken)) {
3969
- const { getClassList } = renderer;
3970
4030
  // TODO [#2762]: this dot notation with add is probably problematic
3971
4031
  // probably we should have a renderer api for just the add operation
3972
4032
  getClassList(elm).add(scopeToken);
3973
4033
  }
4034
+ // TODO [#3733]: remove support for legacy scope tokens
4035
+ if (lwcRuntimeFlags.ENABLE_LEGACY_SCOPE_TOKENS) {
4036
+ const legacyScopeToken = getScopeTokenClass(owner, /* legacy */ true);
4037
+ if (!shared.isNull(legacyScopeToken)) {
4038
+ // TODO [#2762]: this dot notation with add is probably problematic
4039
+ // probably we should have a renderer api for just the add operation
4040
+ getClassList(elm).add(legacyScopeToken);
4041
+ }
4042
+ }
3974
4043
  // Set property element for synthetic shadow DOM style scoping.
3975
4044
  const { stylesheetToken: syntheticToken } = owner.context;
3976
- if (owner.shadowMode === 1 /* ShadowMode.Synthetic */ && !shared.isUndefined(syntheticToken)) {
3977
- elm.$shadowToken$ = syntheticToken;
4045
+ if (owner.shadowMode === 1 /* ShadowMode.Synthetic */) {
4046
+ if (!shared.isUndefined(syntheticToken)) {
4047
+ elm.$shadowToken$ = syntheticToken;
4048
+ }
4049
+ if (lwcRuntimeFlags.ENABLE_LEGACY_SCOPE_TOKENS) {
4050
+ const legacyToken = owner.context.legacyStylesheetToken;
4051
+ if (!shared.isUndefined(legacyToken)) {
4052
+ elm.$legacyShadowToken$ = legacyToken;
4053
+ }
4054
+ }
3978
4055
  }
3979
4056
  }
3980
4057
  function applyDomManual(elm, vnode) {
@@ -5001,9 +5078,10 @@ function buildParseFragmentFn(createFragmentFn) {
5001
5078
  return (strings, ...keys) => {
5002
5079
  const cache = shared.create(null);
5003
5080
  return function () {
5004
- const { context: { hasScopedStyles, stylesheetToken }, shadowMode, renderer, } = getVMBeingRendered();
5081
+ const { context: { hasScopedStyles, stylesheetToken, legacyStylesheetToken }, shadowMode, renderer, } = getVMBeingRendered();
5005
5082
  const hasStyleToken = !shared.isUndefined(stylesheetToken);
5006
5083
  const isSyntheticShadow = shadowMode === 1 /* ShadowMode.Synthetic */;
5084
+ const hasLegacyToken = lwcRuntimeFlags.ENABLE_LEGACY_SCOPE_TOKENS && !shared.isUndefined(legacyStylesheetToken);
5007
5085
  let cacheKey = 0;
5008
5086
  if (hasStyleToken && hasScopedStyles) {
5009
5087
  cacheKey |= 1 /* FragmentCache.HAS_SCOPED_STYLE */;
@@ -5011,12 +5089,19 @@ function buildParseFragmentFn(createFragmentFn) {
5011
5089
  if (hasStyleToken && isSyntheticShadow) {
5012
5090
  cacheKey |= 2 /* FragmentCache.SHADOW_MODE_SYNTHETIC */;
5013
5091
  }
5092
+ if (hasLegacyToken) {
5093
+ // This isn't strictly required for prod, but it's required for our karma tests
5094
+ // since the lwcRuntimeFlag may change over time
5095
+ cacheKey |= 4 /* FragmentCache.HAS_LEGACY_SCOPE_TOKEN */;
5096
+ }
5014
5097
  if (!shared.isUndefined(cache[cacheKey])) {
5015
5098
  return cache[cacheKey];
5016
5099
  }
5017
- const classToken = hasScopedStyles && hasStyleToken ? ' ' + stylesheetToken : '';
5018
- const classAttrToken = hasScopedStyles && hasStyleToken ? ` class="${stylesheetToken}"` : '';
5019
- const attrToken = hasStyleToken && isSyntheticShadow ? ' ' + stylesheetToken : '';
5100
+ // If legacy stylesheet tokens are required, then add them to the rendered string
5101
+ const stylesheetTokenToRender = stylesheetToken + (hasLegacyToken ? ` ${legacyStylesheetToken}` : '');
5102
+ const classToken = hasScopedStyles && hasStyleToken ? ' ' + stylesheetTokenToRender : '';
5103
+ const classAttrToken = hasScopedStyles && hasStyleToken ? ` class="${stylesheetTokenToRender}"` : '';
5104
+ const attrToken = hasStyleToken && isSyntheticShadow ? ' ' + stylesheetTokenToRender : '';
5020
5105
  let htmlFragment = '';
5021
5106
  for (let i = 0, n = keys.length; i < n; i++) {
5022
5107
  switch (keys[i]) {
@@ -5092,7 +5177,10 @@ function evaluateTemplate(vm, html) {
5092
5177
  // Set the computeHasScopedStyles property in the context, to avoid recomputing it repeatedly.
5093
5178
  context.hasScopedStyles = computeHasScopedStyles(html, vm);
5094
5179
  // Update the scoping token on the host element.
5095
- updateStylesheetToken(vm, html);
5180
+ updateStylesheetToken(vm, html, /* legacy */ false);
5181
+ if (lwcRuntimeFlags.ENABLE_LEGACY_SCOPE_TOKENS) {
5182
+ updateStylesheetToken(vm, html, /* legacy */ true);
5183
+ }
5096
5184
  // Evaluate, create stylesheet and cache the produced VNode for future
5097
5185
  // re-rendering.
5098
5186
  const stylesheetsContent = getStylesheetsContent(vm, html);
@@ -5430,6 +5518,9 @@ function createVM(elm, ctor, renderer, options) {
5430
5518
  stylesheetToken: undefined,
5431
5519
  hasTokenInClass: undefined,
5432
5520
  hasTokenInAttribute: undefined,
5521
+ legacyStylesheetToken: undefined,
5522
+ hasLegacyTokenInClass: undefined,
5523
+ hasLegacyTokenInAttribute: undefined,
5433
5524
  hasScopedStyles: undefined,
5434
5525
  styleVNodes: null,
5435
5526
  tplCache: EmptyObject,
@@ -6450,7 +6541,8 @@ function validateClassAttr(vnode, elm, renderer) {
6450
6541
  const { data, owner } = vnode;
6451
6542
  let { className, classMap } = data;
6452
6543
  const { getProperty, getClassList, getAttribute } = renderer;
6453
- const scopedToken = getScopeTokenClass(owner);
6544
+ // we don't care about legacy for hydration. it's a new use case
6545
+ const scopedToken = getScopeTokenClass(owner, /* legacy */ false);
6454
6546
  const stylesheetTokenHost = isVCustomElement(vnode) ? getStylesheetTokenHost(vnode) : null;
6455
6547
  // Classnames for scoped CSS are added directly to the DOM during rendering,
6456
6548
  // or to the VDOM on the server in the case of SSR. As such, these classnames
@@ -6898,5 +6990,5 @@ exports.swapTemplate = swapTemplate;
6898
6990
  exports.track = track;
6899
6991
  exports.unwrap = unwrap;
6900
6992
  exports.wire = wire;
6901
- /** version: 3.3.2 */
6993
+ /** version: 3.4.0 */
6902
6994
  //# sourceMappingURL=index.cjs.js.map