@lwc/engine-core 2.23.6 → 2.25.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.
- package/dist/engine-core.cjs.js +141 -14
- package/dist/engine-core.js +142 -15
- package/package.json +3 -3
- package/types/framework/base-lightning-element.d.ts +4 -0
- package/types/framework/stylesheet.d.ts +6 -1
- package/types/framework/template.d.ts +2 -0
- package/types/framework/utils.d.ts +3 -0
- package/types/framework/vm.d.ts +8 -1
- package/types/framework/vnodes.d.ts +3 -0
package/dist/engine-core.cjs.js
CHANGED
|
@@ -111,6 +111,20 @@ function flattenStylesheets(stylesheets) {
|
|
|
111
111
|
}
|
|
112
112
|
return list;
|
|
113
113
|
}
|
|
114
|
+
// Set a ref (lwc:ref) on a VM, from a template API
|
|
115
|
+
function setRefVNode(vm, ref, vnode) {
|
|
116
|
+
if (process.env.NODE_ENV !== 'production' && shared.isUndefined(vm.refVNodes)) {
|
|
117
|
+
throw new Error('refVNodes must be defined when setting a ref');
|
|
118
|
+
}
|
|
119
|
+
// If this method is called, then vm.refVNodes is set as the template has refs.
|
|
120
|
+
// If not, then something went wrong and we threw an error above.
|
|
121
|
+
const refVNodes = vm.refVNodes;
|
|
122
|
+
// In cases of conflict (two elements with the same ref), prefer, the last one,
|
|
123
|
+
// in depth-first traversal order.
|
|
124
|
+
if (!(ref in refVNodes) || refVNodes[ref].key < vnode.key) {
|
|
125
|
+
refVNodes[ref] = vnode;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
114
128
|
|
|
115
129
|
/*
|
|
116
130
|
* Copyright (c) 2019, salesforce.com, inc.
|
|
@@ -1441,6 +1455,8 @@ function createBridgeToElementDescriptor(propName, descriptor) {
|
|
|
1441
1455
|
},
|
|
1442
1456
|
};
|
|
1443
1457
|
}
|
|
1458
|
+
const EMPTY_REFS = shared.freeze(shared.create(null));
|
|
1459
|
+
const refsCache = new WeakMap();
|
|
1444
1460
|
/**
|
|
1445
1461
|
* This class is the base class for any LWC element.
|
|
1446
1462
|
* Some elements directly extends this class, others implement it via inheritance.
|
|
@@ -1620,6 +1636,70 @@ LightningElement.prototype = {
|
|
|
1620
1636
|
}
|
|
1621
1637
|
return vm.shadowRoot;
|
|
1622
1638
|
},
|
|
1639
|
+
get refs() {
|
|
1640
|
+
const vm = getAssociatedVM(this);
|
|
1641
|
+
if (isUpdatingTemplate) {
|
|
1642
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1643
|
+
logError(`this.refs should not be called while ${getComponentTag(vm)} is rendering. Use this.refs only when the DOM is stable, e.g. in renderedCallback().`);
|
|
1644
|
+
}
|
|
1645
|
+
// If the template is in the process of being updated, then we don't want to go through the normal
|
|
1646
|
+
// process of returning the refs and caching them, because the state of the refs is unstable.
|
|
1647
|
+
// This can happen if e.g. a template contains `<div class={foo}></div>` and `foo` is computed
|
|
1648
|
+
// based on `this.refs.bar`.
|
|
1649
|
+
return;
|
|
1650
|
+
}
|
|
1651
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1652
|
+
warnIfInvokedDuringConstruction(vm, 'refs');
|
|
1653
|
+
}
|
|
1654
|
+
const { refVNodes, hasRefVNodes, cmpTemplate } = vm;
|
|
1655
|
+
// If the `cmpTemplate` is null, that means that the template has not been rendered yet. Most likely this occurs
|
|
1656
|
+
// if `this.refs` is called during the `connectedCallback` phase. The DOM elements have not been rendered yet,
|
|
1657
|
+
// so log a warning. Note we also check `isBeingConstructed()` to avoid a double warning (due to
|
|
1658
|
+
// `warnIfInvokedDuringConstruction` above).
|
|
1659
|
+
if (process.env.NODE_ENV !== 'production' &&
|
|
1660
|
+
shared.isNull(cmpTemplate) &&
|
|
1661
|
+
!isBeingConstructed(vm)) {
|
|
1662
|
+
logError(`this.refs is undefined for ${getComponentTag(vm)}. This is either because the attached template has no "lwc:ref" directive, or this.refs was ` +
|
|
1663
|
+
`invoked before renderedCallback(). Use this.refs only when the referenced HTML elements have ` +
|
|
1664
|
+
`been rendered to the DOM, such as within renderedCallback() or disconnectedCallback().`);
|
|
1665
|
+
}
|
|
1666
|
+
// For backwards compatibility with component written before template refs
|
|
1667
|
+
// were introduced, we return undefined if the template has no refs defined
|
|
1668
|
+
// anywhere. This fixes components that may want to add an expando called `refs`
|
|
1669
|
+
// and are checking if it exists with `if (this.refs)` before adding it.
|
|
1670
|
+
// Note it is not sufficient to just check if `refVNodes` is null or empty,
|
|
1671
|
+
// because a template may have `lwc:ref` defined within a falsy `if:true` block.
|
|
1672
|
+
if (!hasRefVNodes) {
|
|
1673
|
+
return;
|
|
1674
|
+
}
|
|
1675
|
+
// For templates that are using `lwc:ref`, if there are no refs currently available
|
|
1676
|
+
// (e.g. refs inside of a falsy `if:true` block), we return an empty object.
|
|
1677
|
+
if (shared.isNull(refVNodes)) {
|
|
1678
|
+
return EMPTY_REFS;
|
|
1679
|
+
}
|
|
1680
|
+
// The refNodes can be cached based on the refVNodes, since the refVNodes
|
|
1681
|
+
// are recreated from scratch every time the template is rendered.
|
|
1682
|
+
// This happens with `vm.refVNodes = null` in `template.ts` in `@lwc/engine-core`.
|
|
1683
|
+
let refs = refsCache.get(refVNodes);
|
|
1684
|
+
if (shared.isUndefined(refs)) {
|
|
1685
|
+
refs = shared.create(null);
|
|
1686
|
+
for (const key of shared.keys(refVNodes)) {
|
|
1687
|
+
refs[key] = refVNodes[key].elm;
|
|
1688
|
+
}
|
|
1689
|
+
shared.freeze(refs);
|
|
1690
|
+
refsCache.set(refVNodes, refs);
|
|
1691
|
+
}
|
|
1692
|
+
return refs;
|
|
1693
|
+
},
|
|
1694
|
+
// For backwards compat, we allow component authors to set `refs` as an expando
|
|
1695
|
+
set refs(value) {
|
|
1696
|
+
shared.defineProperty(this, 'refs', {
|
|
1697
|
+
configurable: true,
|
|
1698
|
+
enumerable: true,
|
|
1699
|
+
writable: true,
|
|
1700
|
+
value,
|
|
1701
|
+
});
|
|
1702
|
+
},
|
|
1623
1703
|
get shadowRoot() {
|
|
1624
1704
|
// From within the component instance, the shadowRoot is always reported as "closed".
|
|
1625
1705
|
// Authors should rely on this.template instead.
|
|
@@ -3051,6 +3131,14 @@ function getScopeTokenClass(owner) {
|
|
|
3051
3131
|
const { cmpTemplate, context } = owner;
|
|
3052
3132
|
return (context.hasScopedStyles && (cmpTemplate === null || cmpTemplate === void 0 ? void 0 : cmpTemplate.stylesheetToken)) || null;
|
|
3053
3133
|
}
|
|
3134
|
+
/**
|
|
3135
|
+
* This function returns the host style token for a custom element if it
|
|
3136
|
+
* exists. Otherwise it returns null.
|
|
3137
|
+
*/
|
|
3138
|
+
function getStylesheetTokenHost(vnode) {
|
|
3139
|
+
const { template: { stylesheetToken }, } = getComponentInternalDef(vnode.ctor);
|
|
3140
|
+
return !shared.isUndefined(stylesheetToken) ? makeHostToken(stylesheetToken) : null;
|
|
3141
|
+
}
|
|
3054
3142
|
function getNearestNativeShadowComponent(vm) {
|
|
3055
3143
|
const owner = getNearestShadowComponent(vm);
|
|
3056
3144
|
if (!shared.isNull(owner) && owner.shadowMode === 1 /* ShadowMode.Synthetic */) {
|
|
@@ -3168,6 +3256,9 @@ function isVBaseElement(vnode) {
|
|
|
3168
3256
|
function isSameVnode(vnode1, vnode2) {
|
|
3169
3257
|
return vnode1.key === vnode2.key && vnode1.sel === vnode2.sel;
|
|
3170
3258
|
}
|
|
3259
|
+
function isVCustomElement(vnode) {
|
|
3260
|
+
return vnode.type === 3 /* VNodeType.CustomElement */;
|
|
3261
|
+
}
|
|
3171
3262
|
|
|
3172
3263
|
/*
|
|
3173
3264
|
* Copyright (c) 2018, salesforce.com, inc.
|
|
@@ -3223,13 +3314,27 @@ function isLiveBindingProp(sel, key) {
|
|
|
3223
3314
|
return sel === 'input' && (key === 'value' || key === 'checked');
|
|
3224
3315
|
}
|
|
3225
3316
|
function patchProps(oldVnode, vnode, renderer) {
|
|
3226
|
-
|
|
3227
|
-
|
|
3317
|
+
let { props } = vnode.data;
|
|
3318
|
+
const { spread } = vnode.data;
|
|
3319
|
+
if (shared.isUndefined(props) && shared.isUndefined(spread)) {
|
|
3228
3320
|
return;
|
|
3229
3321
|
}
|
|
3230
|
-
|
|
3231
|
-
if (
|
|
3232
|
-
|
|
3322
|
+
let oldProps;
|
|
3323
|
+
if (!shared.isNull(oldVnode)) {
|
|
3324
|
+
oldProps = oldVnode.data.props;
|
|
3325
|
+
const oldSpread = oldVnode.data.spread;
|
|
3326
|
+
if (oldProps === props && oldSpread === spread) {
|
|
3327
|
+
return;
|
|
3328
|
+
}
|
|
3329
|
+
if (shared.isUndefined(oldProps)) {
|
|
3330
|
+
oldProps = EmptyObject;
|
|
3331
|
+
}
|
|
3332
|
+
if (!shared.isUndefined(oldSpread)) {
|
|
3333
|
+
oldProps = shared.assign({}, oldProps, oldSpread);
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
if (!shared.isUndefined(spread)) {
|
|
3337
|
+
props = shared.assign({}, props, spread);
|
|
3233
3338
|
}
|
|
3234
3339
|
const isFirstPatch = shared.isNull(oldVnode);
|
|
3235
3340
|
const { elm, sel } = vnode;
|
|
@@ -3239,7 +3344,9 @@ function patchProps(oldVnode, vnode, renderer) {
|
|
|
3239
3344
|
// Set the property if it's the first time is is patched or if the previous property is
|
|
3240
3345
|
// different than the one previously set.
|
|
3241
3346
|
if (isFirstPatch ||
|
|
3242
|
-
cur !== (isLiveBindingProp(sel, key) ? getProperty(elm, key) : oldProps[key])
|
|
3347
|
+
cur !== (isLiveBindingProp(sel, key) ? getProperty(elm, key) : oldProps[key]) ||
|
|
3348
|
+
!(key in oldProps) // this is required because the above case will pass when `cur` is `undefined` and key is missing in `oldProps`
|
|
3349
|
+
) {
|
|
3243
3350
|
// Additional verification if properties are supported by the element
|
|
3244
3351
|
// Validation relies on html properties and public properties being defined on the element,
|
|
3245
3352
|
// SSR has its own custom validation.
|
|
@@ -4303,17 +4410,20 @@ function h(sel, data, children = EmptyArray) {
|
|
|
4303
4410
|
}
|
|
4304
4411
|
});
|
|
4305
4412
|
}
|
|
4306
|
-
|
|
4307
|
-
const
|
|
4308
|
-
return {
|
|
4413
|
+
const { key, ref } = data;
|
|
4414
|
+
const vnode = {
|
|
4309
4415
|
type: 2 /* VNodeType.Element */,
|
|
4310
4416
|
sel,
|
|
4311
4417
|
data,
|
|
4312
4418
|
children,
|
|
4313
|
-
elm,
|
|
4419
|
+
elm: undefined,
|
|
4314
4420
|
key,
|
|
4315
4421
|
owner: vmBeingRendered,
|
|
4316
4422
|
};
|
|
4423
|
+
if (!shared.isUndefined(ref)) {
|
|
4424
|
+
setRefVNode(vmBeingRendered, ref, vnode);
|
|
4425
|
+
}
|
|
4426
|
+
return vnode;
|
|
4317
4427
|
}
|
|
4318
4428
|
// [t]ab[i]ndex function
|
|
4319
4429
|
function ti(value) {
|
|
@@ -4378,7 +4488,7 @@ function c(sel, Ctor, data, children = EmptyArray) {
|
|
|
4378
4488
|
});
|
|
4379
4489
|
}
|
|
4380
4490
|
}
|
|
4381
|
-
const { key } = data;
|
|
4491
|
+
const { key, ref } = data;
|
|
4382
4492
|
let elm, aChildren, vm;
|
|
4383
4493
|
const vnode = {
|
|
4384
4494
|
type: 3 /* VNodeType.CustomElement */,
|
|
@@ -4394,6 +4504,9 @@ function c(sel, Ctor, data, children = EmptyArray) {
|
|
|
4394
4504
|
vm,
|
|
4395
4505
|
};
|
|
4396
4506
|
addVNodeToChildLWC(vnode);
|
|
4507
|
+
if (!shared.isUndefined(ref)) {
|
|
4508
|
+
setRefVNode(vmBeingRendered, ref, vnode);
|
|
4509
|
+
}
|
|
4397
4510
|
return vnode;
|
|
4398
4511
|
}
|
|
4399
4512
|
// [i]terable node
|
|
@@ -4922,6 +5035,10 @@ function evaluateTemplate(vm, html) {
|
|
|
4922
5035
|
// add the VM to the list of host VMs that can be re-rendered if html is swapped
|
|
4923
5036
|
setActiveVM(vm);
|
|
4924
5037
|
}
|
|
5038
|
+
// reset the refs; they will be set during the tmpl() instantiation
|
|
5039
|
+
const hasRefVNodes = Boolean(html.hasRefs);
|
|
5040
|
+
vm.hasRefVNodes = hasRefVNodes;
|
|
5041
|
+
vm.refVNodes = hasRefVNodes ? shared.create(null) : null;
|
|
4925
5042
|
// right before producing the vnodes, we clear up all internal references
|
|
4926
5043
|
// to custom elements from the template.
|
|
4927
5044
|
vm.velements = [];
|
|
@@ -5280,6 +5397,8 @@ function createVM(elm, ctor, renderer, options) {
|
|
|
5280
5397
|
tagName,
|
|
5281
5398
|
mode,
|
|
5282
5399
|
owner,
|
|
5400
|
+
refVNodes: null,
|
|
5401
|
+
hasRefVNodes: false,
|
|
5283
5402
|
children: EmptyArray,
|
|
5284
5403
|
aChildren: EmptyArray,
|
|
5285
5404
|
velements: EmptyArray,
|
|
@@ -6433,6 +6552,7 @@ function validateClassAttr(vnode, elm, renderer) {
|
|
|
6433
6552
|
let { className, classMap } = data;
|
|
6434
6553
|
const { getProperty, getClassList } = renderer;
|
|
6435
6554
|
const scopedToken = getScopeTokenClass(owner);
|
|
6555
|
+
const stylesheetTokenHost = isVCustomElement(vnode) ? getStylesheetTokenHost(vnode) : null;
|
|
6436
6556
|
// Classnames for scoped CSS are added directly to the DOM during rendering,
|
|
6437
6557
|
// or to the VDOM on the server in the case of SSR. As such, these classnames
|
|
6438
6558
|
// are never present in VDOM nodes in the browser.
|
|
@@ -6441,10 +6561,17 @@ function validateClassAttr(vnode, elm, renderer) {
|
|
|
6441
6561
|
// are rendered during SSR. This needs to be accounted for when validating.
|
|
6442
6562
|
if (scopedToken) {
|
|
6443
6563
|
if (!shared.isUndefined(className)) {
|
|
6444
|
-
className =
|
|
6564
|
+
className = shared.isNull(stylesheetTokenHost)
|
|
6565
|
+
? `${scopedToken} ${className}`
|
|
6566
|
+
: `${scopedToken} ${className} ${stylesheetTokenHost}`;
|
|
6445
6567
|
}
|
|
6446
6568
|
else if (!shared.isUndefined(classMap)) {
|
|
6447
|
-
classMap = Object.assign(Object.assign({}, classMap), { [scopedToken]: true });
|
|
6569
|
+
classMap = Object.assign(Object.assign(Object.assign({}, classMap), { [scopedToken]: true }), (shared.isNull(stylesheetTokenHost) ? {} : { [stylesheetTokenHost]: true }));
|
|
6570
|
+
}
|
|
6571
|
+
else {
|
|
6572
|
+
className = shared.isNull(stylesheetTokenHost)
|
|
6573
|
+
? `${scopedToken}`
|
|
6574
|
+
: `${scopedToken} ${stylesheetTokenHost}`;
|
|
6448
6575
|
}
|
|
6449
6576
|
}
|
|
6450
6577
|
let nodesAreCompatible = true;
|
|
@@ -6725,4 +6852,4 @@ exports.swapTemplate = swapTemplate;
|
|
|
6725
6852
|
exports.track = track;
|
|
6726
6853
|
exports.unwrap = unwrap;
|
|
6727
6854
|
exports.wire = wire;
|
|
6728
|
-
/* version: 2.
|
|
6855
|
+
/* version: 2.25.0 */
|
package/dist/engine-core.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* proxy-compat-disable */
|
|
2
2
|
import { lwcRuntimeFlags } from '@lwc/features';
|
|
3
3
|
export { setFeatureFlag, setFeatureFlagForTest } from '@lwc/features';
|
|
4
|
-
import { seal, create,
|
|
4
|
+
import { seal, create, isUndefined as isUndefined$1, isFunction as isFunction$1, ArrayPush as ArrayPush$1, ArrayIndexOf, ArraySplice, StringToLowerCase, isNull, ArrayJoin, isFrozen, defineProperty, hasOwnProperty as hasOwnProperty$1, assign, forEach, keys, AriaPropNameToAttrNameMap, getPropertyDescriptor, defineProperties, getOwnPropertyNames as getOwnPropertyNames$1, getPrototypeOf as getPrototypeOf$1, setPrototypeOf, isObject, freeze, assert, KEY__SYNTHETIC_MODE, isFalse, isTrue, toString as toString$1, getOwnPropertyDescriptor as getOwnPropertyDescriptor$1, LWC_VERSION_COMMENT_REGEX, LWC_VERSION, htmlPropertyToAttribute, ArraySlice, ArrayMap, isArray as isArray$1, KEY__SCOPED_CSS, StringCharCodeAt, XML_NAMESPACE, XLINK_NAMESPACE, isString, StringSlice, SVG_NAMESPACE, KEY__SHADOW_STATIC, KEY__SHADOW_RESOLVER, isNumber, StringReplace, noop, ArrayUnshift, ArrayCopyWithin, ArrayFill, ArraySort, ArrayReverse, ArrayShift, ArrayPop } from '@lwc/shared';
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
7
|
* Copyright (c) 2018, salesforce.com, inc.
|
|
@@ -108,6 +108,20 @@ function flattenStylesheets(stylesheets) {
|
|
|
108
108
|
}
|
|
109
109
|
return list;
|
|
110
110
|
}
|
|
111
|
+
// Set a ref (lwc:ref) on a VM, from a template API
|
|
112
|
+
function setRefVNode(vm, ref, vnode) {
|
|
113
|
+
if (process.env.NODE_ENV !== 'production' && isUndefined$1(vm.refVNodes)) {
|
|
114
|
+
throw new Error('refVNodes must be defined when setting a ref');
|
|
115
|
+
}
|
|
116
|
+
// If this method is called, then vm.refVNodes is set as the template has refs.
|
|
117
|
+
// If not, then something went wrong and we threw an error above.
|
|
118
|
+
const refVNodes = vm.refVNodes;
|
|
119
|
+
// In cases of conflict (two elements with the same ref), prefer, the last one,
|
|
120
|
+
// in depth-first traversal order.
|
|
121
|
+
if (!(ref in refVNodes) || refVNodes[ref].key < vnode.key) {
|
|
122
|
+
refVNodes[ref] = vnode;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
111
125
|
|
|
112
126
|
/*
|
|
113
127
|
* Copyright (c) 2019, salesforce.com, inc.
|
|
@@ -1438,6 +1452,8 @@ function createBridgeToElementDescriptor(propName, descriptor) {
|
|
|
1438
1452
|
},
|
|
1439
1453
|
};
|
|
1440
1454
|
}
|
|
1455
|
+
const EMPTY_REFS = freeze(create(null));
|
|
1456
|
+
const refsCache = new WeakMap();
|
|
1441
1457
|
/**
|
|
1442
1458
|
* This class is the base class for any LWC element.
|
|
1443
1459
|
* Some elements directly extends this class, others implement it via inheritance.
|
|
@@ -1617,6 +1633,70 @@ LightningElement.prototype = {
|
|
|
1617
1633
|
}
|
|
1618
1634
|
return vm.shadowRoot;
|
|
1619
1635
|
},
|
|
1636
|
+
get refs() {
|
|
1637
|
+
const vm = getAssociatedVM(this);
|
|
1638
|
+
if (isUpdatingTemplate) {
|
|
1639
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1640
|
+
logError(`this.refs should not be called while ${getComponentTag(vm)} is rendering. Use this.refs only when the DOM is stable, e.g. in renderedCallback().`);
|
|
1641
|
+
}
|
|
1642
|
+
// If the template is in the process of being updated, then we don't want to go through the normal
|
|
1643
|
+
// process of returning the refs and caching them, because the state of the refs is unstable.
|
|
1644
|
+
// This can happen if e.g. a template contains `<div class={foo}></div>` and `foo` is computed
|
|
1645
|
+
// based on `this.refs.bar`.
|
|
1646
|
+
return;
|
|
1647
|
+
}
|
|
1648
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1649
|
+
warnIfInvokedDuringConstruction(vm, 'refs');
|
|
1650
|
+
}
|
|
1651
|
+
const { refVNodes, hasRefVNodes, cmpTemplate } = vm;
|
|
1652
|
+
// If the `cmpTemplate` is null, that means that the template has not been rendered yet. Most likely this occurs
|
|
1653
|
+
// if `this.refs` is called during the `connectedCallback` phase. The DOM elements have not been rendered yet,
|
|
1654
|
+
// so log a warning. Note we also check `isBeingConstructed()` to avoid a double warning (due to
|
|
1655
|
+
// `warnIfInvokedDuringConstruction` above).
|
|
1656
|
+
if (process.env.NODE_ENV !== 'production' &&
|
|
1657
|
+
isNull(cmpTemplate) &&
|
|
1658
|
+
!isBeingConstructed(vm)) {
|
|
1659
|
+
logError(`this.refs is undefined for ${getComponentTag(vm)}. This is either because the attached template has no "lwc:ref" directive, or this.refs was ` +
|
|
1660
|
+
`invoked before renderedCallback(). Use this.refs only when the referenced HTML elements have ` +
|
|
1661
|
+
`been rendered to the DOM, such as within renderedCallback() or disconnectedCallback().`);
|
|
1662
|
+
}
|
|
1663
|
+
// For backwards compatibility with component written before template refs
|
|
1664
|
+
// were introduced, we return undefined if the template has no refs defined
|
|
1665
|
+
// anywhere. This fixes components that may want to add an expando called `refs`
|
|
1666
|
+
// and are checking if it exists with `if (this.refs)` before adding it.
|
|
1667
|
+
// Note it is not sufficient to just check if `refVNodes` is null or empty,
|
|
1668
|
+
// because a template may have `lwc:ref` defined within a falsy `if:true` block.
|
|
1669
|
+
if (!hasRefVNodes) {
|
|
1670
|
+
return;
|
|
1671
|
+
}
|
|
1672
|
+
// For templates that are using `lwc:ref`, if there are no refs currently available
|
|
1673
|
+
// (e.g. refs inside of a falsy `if:true` block), we return an empty object.
|
|
1674
|
+
if (isNull(refVNodes)) {
|
|
1675
|
+
return EMPTY_REFS;
|
|
1676
|
+
}
|
|
1677
|
+
// The refNodes can be cached based on the refVNodes, since the refVNodes
|
|
1678
|
+
// are recreated from scratch every time the template is rendered.
|
|
1679
|
+
// This happens with `vm.refVNodes = null` in `template.ts` in `@lwc/engine-core`.
|
|
1680
|
+
let refs = refsCache.get(refVNodes);
|
|
1681
|
+
if (isUndefined$1(refs)) {
|
|
1682
|
+
refs = create(null);
|
|
1683
|
+
for (const key of keys(refVNodes)) {
|
|
1684
|
+
refs[key] = refVNodes[key].elm;
|
|
1685
|
+
}
|
|
1686
|
+
freeze(refs);
|
|
1687
|
+
refsCache.set(refVNodes, refs);
|
|
1688
|
+
}
|
|
1689
|
+
return refs;
|
|
1690
|
+
},
|
|
1691
|
+
// For backwards compat, we allow component authors to set `refs` as an expando
|
|
1692
|
+
set refs(value) {
|
|
1693
|
+
defineProperty(this, 'refs', {
|
|
1694
|
+
configurable: true,
|
|
1695
|
+
enumerable: true,
|
|
1696
|
+
writable: true,
|
|
1697
|
+
value,
|
|
1698
|
+
});
|
|
1699
|
+
},
|
|
1620
1700
|
get shadowRoot() {
|
|
1621
1701
|
// From within the component instance, the shadowRoot is always reported as "closed".
|
|
1622
1702
|
// Authors should rely on this.template instead.
|
|
@@ -3048,6 +3128,14 @@ function getScopeTokenClass(owner) {
|
|
|
3048
3128
|
const { cmpTemplate, context } = owner;
|
|
3049
3129
|
return (context.hasScopedStyles && (cmpTemplate === null || cmpTemplate === void 0 ? void 0 : cmpTemplate.stylesheetToken)) || null;
|
|
3050
3130
|
}
|
|
3131
|
+
/**
|
|
3132
|
+
* This function returns the host style token for a custom element if it
|
|
3133
|
+
* exists. Otherwise it returns null.
|
|
3134
|
+
*/
|
|
3135
|
+
function getStylesheetTokenHost(vnode) {
|
|
3136
|
+
const { template: { stylesheetToken }, } = getComponentInternalDef(vnode.ctor);
|
|
3137
|
+
return !isUndefined$1(stylesheetToken) ? makeHostToken(stylesheetToken) : null;
|
|
3138
|
+
}
|
|
3051
3139
|
function getNearestNativeShadowComponent(vm) {
|
|
3052
3140
|
const owner = getNearestShadowComponent(vm);
|
|
3053
3141
|
if (!isNull(owner) && owner.shadowMode === 1 /* ShadowMode.Synthetic */) {
|
|
@@ -3165,6 +3253,9 @@ function isVBaseElement(vnode) {
|
|
|
3165
3253
|
function isSameVnode(vnode1, vnode2) {
|
|
3166
3254
|
return vnode1.key === vnode2.key && vnode1.sel === vnode2.sel;
|
|
3167
3255
|
}
|
|
3256
|
+
function isVCustomElement(vnode) {
|
|
3257
|
+
return vnode.type === 3 /* VNodeType.CustomElement */;
|
|
3258
|
+
}
|
|
3168
3259
|
|
|
3169
3260
|
/*
|
|
3170
3261
|
* Copyright (c) 2018, salesforce.com, inc.
|
|
@@ -3220,13 +3311,27 @@ function isLiveBindingProp(sel, key) {
|
|
|
3220
3311
|
return sel === 'input' && (key === 'value' || key === 'checked');
|
|
3221
3312
|
}
|
|
3222
3313
|
function patchProps(oldVnode, vnode, renderer) {
|
|
3223
|
-
|
|
3224
|
-
|
|
3314
|
+
let { props } = vnode.data;
|
|
3315
|
+
const { spread } = vnode.data;
|
|
3316
|
+
if (isUndefined$1(props) && isUndefined$1(spread)) {
|
|
3225
3317
|
return;
|
|
3226
3318
|
}
|
|
3227
|
-
|
|
3228
|
-
if (
|
|
3229
|
-
|
|
3319
|
+
let oldProps;
|
|
3320
|
+
if (!isNull(oldVnode)) {
|
|
3321
|
+
oldProps = oldVnode.data.props;
|
|
3322
|
+
const oldSpread = oldVnode.data.spread;
|
|
3323
|
+
if (oldProps === props && oldSpread === spread) {
|
|
3324
|
+
return;
|
|
3325
|
+
}
|
|
3326
|
+
if (isUndefined$1(oldProps)) {
|
|
3327
|
+
oldProps = EmptyObject;
|
|
3328
|
+
}
|
|
3329
|
+
if (!isUndefined$1(oldSpread)) {
|
|
3330
|
+
oldProps = assign({}, oldProps, oldSpread);
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3333
|
+
if (!isUndefined$1(spread)) {
|
|
3334
|
+
props = assign({}, props, spread);
|
|
3230
3335
|
}
|
|
3231
3336
|
const isFirstPatch = isNull(oldVnode);
|
|
3232
3337
|
const { elm, sel } = vnode;
|
|
@@ -3236,7 +3341,9 @@ function patchProps(oldVnode, vnode, renderer) {
|
|
|
3236
3341
|
// Set the property if it's the first time is is patched or if the previous property is
|
|
3237
3342
|
// different than the one previously set.
|
|
3238
3343
|
if (isFirstPatch ||
|
|
3239
|
-
cur !== (isLiveBindingProp(sel, key) ? getProperty(elm, key) : oldProps[key])
|
|
3344
|
+
cur !== (isLiveBindingProp(sel, key) ? getProperty(elm, key) : oldProps[key]) ||
|
|
3345
|
+
!(key in oldProps) // this is required because the above case will pass when `cur` is `undefined` and key is missing in `oldProps`
|
|
3346
|
+
) {
|
|
3240
3347
|
// Additional verification if properties are supported by the element
|
|
3241
3348
|
// Validation relies on html properties and public properties being defined on the element,
|
|
3242
3349
|
// SSR has its own custom validation.
|
|
@@ -4300,17 +4407,20 @@ function h(sel, data, children = EmptyArray) {
|
|
|
4300
4407
|
}
|
|
4301
4408
|
});
|
|
4302
4409
|
}
|
|
4303
|
-
|
|
4304
|
-
const
|
|
4305
|
-
return {
|
|
4410
|
+
const { key, ref } = data;
|
|
4411
|
+
const vnode = {
|
|
4306
4412
|
type: 2 /* VNodeType.Element */,
|
|
4307
4413
|
sel,
|
|
4308
4414
|
data,
|
|
4309
4415
|
children,
|
|
4310
|
-
elm,
|
|
4416
|
+
elm: undefined,
|
|
4311
4417
|
key,
|
|
4312
4418
|
owner: vmBeingRendered,
|
|
4313
4419
|
};
|
|
4420
|
+
if (!isUndefined$1(ref)) {
|
|
4421
|
+
setRefVNode(vmBeingRendered, ref, vnode);
|
|
4422
|
+
}
|
|
4423
|
+
return vnode;
|
|
4314
4424
|
}
|
|
4315
4425
|
// [t]ab[i]ndex function
|
|
4316
4426
|
function ti(value) {
|
|
@@ -4375,7 +4485,7 @@ function c(sel, Ctor, data, children = EmptyArray) {
|
|
|
4375
4485
|
});
|
|
4376
4486
|
}
|
|
4377
4487
|
}
|
|
4378
|
-
const { key } = data;
|
|
4488
|
+
const { key, ref } = data;
|
|
4379
4489
|
let elm, aChildren, vm;
|
|
4380
4490
|
const vnode = {
|
|
4381
4491
|
type: 3 /* VNodeType.CustomElement */,
|
|
@@ -4391,6 +4501,9 @@ function c(sel, Ctor, data, children = EmptyArray) {
|
|
|
4391
4501
|
vm,
|
|
4392
4502
|
};
|
|
4393
4503
|
addVNodeToChildLWC(vnode);
|
|
4504
|
+
if (!isUndefined$1(ref)) {
|
|
4505
|
+
setRefVNode(vmBeingRendered, ref, vnode);
|
|
4506
|
+
}
|
|
4394
4507
|
return vnode;
|
|
4395
4508
|
}
|
|
4396
4509
|
// [i]terable node
|
|
@@ -4919,6 +5032,10 @@ function evaluateTemplate(vm, html) {
|
|
|
4919
5032
|
// add the VM to the list of host VMs that can be re-rendered if html is swapped
|
|
4920
5033
|
setActiveVM(vm);
|
|
4921
5034
|
}
|
|
5035
|
+
// reset the refs; they will be set during the tmpl() instantiation
|
|
5036
|
+
const hasRefVNodes = Boolean(html.hasRefs);
|
|
5037
|
+
vm.hasRefVNodes = hasRefVNodes;
|
|
5038
|
+
vm.refVNodes = hasRefVNodes ? create(null) : null;
|
|
4922
5039
|
// right before producing the vnodes, we clear up all internal references
|
|
4923
5040
|
// to custom elements from the template.
|
|
4924
5041
|
vm.velements = [];
|
|
@@ -5277,6 +5394,8 @@ function createVM(elm, ctor, renderer, options) {
|
|
|
5277
5394
|
tagName,
|
|
5278
5395
|
mode,
|
|
5279
5396
|
owner,
|
|
5397
|
+
refVNodes: null,
|
|
5398
|
+
hasRefVNodes: false,
|
|
5280
5399
|
children: EmptyArray,
|
|
5281
5400
|
aChildren: EmptyArray,
|
|
5282
5401
|
velements: EmptyArray,
|
|
@@ -6430,6 +6549,7 @@ function validateClassAttr(vnode, elm, renderer) {
|
|
|
6430
6549
|
let { className, classMap } = data;
|
|
6431
6550
|
const { getProperty, getClassList } = renderer;
|
|
6432
6551
|
const scopedToken = getScopeTokenClass(owner);
|
|
6552
|
+
const stylesheetTokenHost = isVCustomElement(vnode) ? getStylesheetTokenHost(vnode) : null;
|
|
6433
6553
|
// Classnames for scoped CSS are added directly to the DOM during rendering,
|
|
6434
6554
|
// or to the VDOM on the server in the case of SSR. As such, these classnames
|
|
6435
6555
|
// are never present in VDOM nodes in the browser.
|
|
@@ -6438,10 +6558,17 @@ function validateClassAttr(vnode, elm, renderer) {
|
|
|
6438
6558
|
// are rendered during SSR. This needs to be accounted for when validating.
|
|
6439
6559
|
if (scopedToken) {
|
|
6440
6560
|
if (!isUndefined$1(className)) {
|
|
6441
|
-
className =
|
|
6561
|
+
className = isNull(stylesheetTokenHost)
|
|
6562
|
+
? `${scopedToken} ${className}`
|
|
6563
|
+
: `${scopedToken} ${className} ${stylesheetTokenHost}`;
|
|
6442
6564
|
}
|
|
6443
6565
|
else if (!isUndefined$1(classMap)) {
|
|
6444
|
-
classMap = Object.assign(Object.assign({}, classMap), { [scopedToken]: true });
|
|
6566
|
+
classMap = Object.assign(Object.assign(Object.assign({}, classMap), { [scopedToken]: true }), (isNull(stylesheetTokenHost) ? {} : { [stylesheetTokenHost]: true }));
|
|
6567
|
+
}
|
|
6568
|
+
else {
|
|
6569
|
+
className = isNull(stylesheetTokenHost)
|
|
6570
|
+
? `${scopedToken}`
|
|
6571
|
+
: `${scopedToken} ${stylesheetTokenHost}`;
|
|
6445
6572
|
}
|
|
6446
6573
|
}
|
|
6447
6574
|
let nodesAreCompatible = true;
|
|
@@ -6685,4 +6812,4 @@ function getComponentConstructor(elm) {
|
|
|
6685
6812
|
}
|
|
6686
6813
|
|
|
6687
6814
|
export { LightningElement, profilerControl as __unstable__ProfilerControl, api$1 as api, connectRootElement, createContextProvider, createVM, disconnectRootElement, freezeTemplate, getAssociatedVMIfPresent, getComponentConstructor, getComponentDef, getComponentHtmlPrototype, getUpgradableConstructor, hydrateRoot, isComponentConstructor, parseFragment, parseSVGFragment, readonly, register, registerComponent, registerDecorators, registerTemplate, sanitizeAttribute, setHooks, swapComponent, swapStyle, swapTemplate, track, unwrap, wire };
|
|
6688
|
-
/* version: 2.
|
|
6815
|
+
/* version: 2.25.0 */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lwc/engine-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.25.0",
|
|
4
4
|
"description": "Core LWC engine APIs.",
|
|
5
5
|
"homepage": "https://lwc.dev/",
|
|
6
6
|
"repository": {
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"types/"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@lwc/features": "2.
|
|
28
|
-
"@lwc/shared": "2.
|
|
27
|
+
"@lwc/features": "2.25.0",
|
|
28
|
+
"@lwc/shared": "2.25.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"observable-membrane": "2.0.0"
|
|
@@ -19,8 +19,12 @@ export interface LightningElementConstructor {
|
|
|
19
19
|
shadowSupportMode?: ShadowSupportMode;
|
|
20
20
|
}
|
|
21
21
|
declare type HTMLElementTheGoodParts = Pick<Object, 'toString'> & Pick<HTMLElement, 'accessKey' | 'addEventListener' | 'children' | 'childNodes' | 'classList' | 'dir' | 'dispatchEvent' | 'draggable' | 'firstChild' | 'firstElementChild' | 'getAttribute' | 'getAttributeNS' | 'getBoundingClientRect' | 'getElementsByClassName' | 'getElementsByTagName' | 'hasAttribute' | 'hasAttributeNS' | 'hidden' | 'id' | 'isConnected' | 'lang' | 'lastChild' | 'lastElementChild' | 'querySelector' | 'querySelectorAll' | 'removeAttribute' | 'removeAttributeNS' | 'removeEventListener' | 'setAttribute' | 'setAttributeNS' | 'spellcheck' | 'tabIndex' | 'title'>;
|
|
22
|
+
declare type RefNodes = {
|
|
23
|
+
[name: string]: Element;
|
|
24
|
+
};
|
|
22
25
|
export interface LightningElement extends HTMLElementTheGoodParts, AccessibleElementProperties {
|
|
23
26
|
template: ShadowRoot | null;
|
|
27
|
+
refs: RefNodes;
|
|
24
28
|
render(): Template;
|
|
25
29
|
connectedCallback?(): void;
|
|
26
30
|
disconnectedCallback?(): void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { VM } from './vm';
|
|
2
2
|
import { Template } from './template';
|
|
3
|
-
import { VNode } from './vnodes';
|
|
3
|
+
import { VCustomElement, VNode } from './vnodes';
|
|
4
4
|
/**
|
|
5
5
|
* Function producing style based on a host and a shadow selector. This function is invoked by
|
|
6
6
|
* the engine with different values depending on the mode that the component is running on.
|
|
@@ -20,4 +20,9 @@ export declare function getStylesheetsContent(vm: VM, template: Template): strin
|
|
|
20
20
|
* it returns null.
|
|
21
21
|
*/
|
|
22
22
|
export declare function getScopeTokenClass(owner: VM): string | null;
|
|
23
|
+
/**
|
|
24
|
+
* This function returns the host style token for a custom element if it
|
|
25
|
+
* exists. Otherwise it returns null.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getStylesheetTokenHost(vnode: VCustomElement): string | null;
|
|
23
28
|
export declare function createStylesheet(vm: VM, stylesheets: string[]): VNode[] | null;
|
|
@@ -12,6 +12,8 @@ export interface Template {
|
|
|
12
12
|
stylesheetToken?: string;
|
|
13
13
|
/** Render mode for the template. Could be light or undefined (which means it's shadow) */
|
|
14
14
|
renderMode?: 'light';
|
|
15
|
+
/** True if this template contains template refs, undefined or false otherwise */
|
|
16
|
+
hasRefs?: boolean;
|
|
15
17
|
}
|
|
16
18
|
export declare let isUpdatingTemplate: boolean;
|
|
17
19
|
export declare function getVMBeingRendered(): VM | null;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { StylesheetFactory, TemplateStylesheetFactories } from './stylesheet';
|
|
2
|
+
import { VM } from './vm';
|
|
3
|
+
import { VBaseElement } from './vnodes';
|
|
2
4
|
declare type Callback = () => void;
|
|
3
5
|
export declare const SPACE_CHAR = 32;
|
|
4
6
|
export declare const EmptyObject: any;
|
|
@@ -14,4 +16,5 @@ export declare function cloneAndOmitKey(object: {
|
|
|
14
16
|
[key: string]: any;
|
|
15
17
|
};
|
|
16
18
|
export declare function flattenStylesheets(stylesheets: TemplateStylesheetFactories): StylesheetFactory[];
|
|
19
|
+
export declare function setRefVNode(vm: VM, ref: string, vnode: VBaseElement): void;
|
|
17
20
|
export {};
|
package/types/framework/vm.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { ComponentDef } from './def';
|
|
|
4
4
|
import { LightningElement, LightningElementConstructor } from './base-lightning-element';
|
|
5
5
|
import { ReactiveObserver } from './mutation-tracker';
|
|
6
6
|
import { AccessorReactiveObserver } from './accessor-reactive-observer';
|
|
7
|
-
import { VNodes, VCustomElement, VNode } from './vnodes';
|
|
7
|
+
import { VNodes, VCustomElement, VNode, VBaseElement } from './vnodes';
|
|
8
8
|
declare type ShadowRootMode = 'open' | 'closed';
|
|
9
9
|
export interface TemplateCache {
|
|
10
10
|
[key: string]: any;
|
|
@@ -51,6 +51,9 @@ export interface Context {
|
|
|
51
51
|
/** List of wire hooks that are invoked when the component gets disconnected. */
|
|
52
52
|
wiredDisconnecting: Array<() => void>;
|
|
53
53
|
}
|
|
54
|
+
export declare type RefVNodes = {
|
|
55
|
+
[name: string]: VBaseElement;
|
|
56
|
+
};
|
|
54
57
|
export interface VM<N = HostNode, E = HostElement> {
|
|
55
58
|
/** The host element */
|
|
56
59
|
readonly elm: HostElement;
|
|
@@ -62,6 +65,10 @@ export interface VM<N = HostNode, E = HostElement> {
|
|
|
62
65
|
readonly context: Context;
|
|
63
66
|
/** The owner VM or null for root elements. */
|
|
64
67
|
readonly owner: VM<N, E> | null;
|
|
68
|
+
/** References to elements rendered using lwc:ref (template refs) */
|
|
69
|
+
refVNodes: RefVNodes | null;
|
|
70
|
+
/** Whether this template has any references to elements (template refs) */
|
|
71
|
+
hasRefVNodes: boolean;
|
|
65
72
|
/** Whether or not the VM was hydrated */
|
|
66
73
|
readonly hydrated: boolean;
|
|
67
74
|
/** Rendering operations associated with the VM */
|
|
@@ -72,9 +72,12 @@ export interface VNodeData {
|
|
|
72
72
|
readonly on?: Readonly<Record<string, (event: Event) => any>>;
|
|
73
73
|
readonly svg?: boolean;
|
|
74
74
|
readonly renderer?: RendererAPI;
|
|
75
|
+
readonly spread?: Readonly<Record<string, any>>;
|
|
75
76
|
}
|
|
76
77
|
export interface VElementData extends VNodeData {
|
|
77
78
|
readonly key: Key;
|
|
79
|
+
readonly ref?: string;
|
|
78
80
|
}
|
|
79
81
|
export declare function isVBaseElement(vnode: VNode): vnode is VElement | VCustomElement;
|
|
80
82
|
export declare function isSameVnode(vnode1: VNode, vnode2: VNode): boolean;
|
|
83
|
+
export declare function isVCustomElement(vnode: VBaseElement): vnode is VCustomElement;
|