@lwc/engine-core 8.18.1 → 8.18.2
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/framework/modules/dynamic-events.d.ts +5 -0
- package/dist/framework/vm.d.ts +2 -0
- package/dist/framework/vnodes.d.ts +2 -0
- package/dist/index.cjs.js +71 -14
- package/dist/index.js +71 -14
- package/package.json +4 -4
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { VM } from '../vm';
|
|
2
|
+
import type { VBaseElement } from '../vnodes';
|
|
3
|
+
import type { RendererAPI } from '../renderer';
|
|
4
|
+
export declare function patchDynamicEventListeners(oldVnode: VBaseElement | null, vnode: VBaseElement, renderer: RendererAPI, owner: VM): void;
|
|
5
|
+
//# sourceMappingURL=dynamic-events.d.ts.map
|
package/dist/framework/vm.d.ts
CHANGED
|
@@ -72,6 +72,8 @@ export interface VM<N = HostNode, E = HostElement> {
|
|
|
72
72
|
readonly owner: VM<N, E> | null;
|
|
73
73
|
/** References to elements rendered using lwc:ref (template refs) */
|
|
74
74
|
refVNodes: RefVNodes | null;
|
|
75
|
+
/** event listeners added to elements corresponding to functions provided by lwc:on */
|
|
76
|
+
attachedEventListeners: WeakMap<Element, Record<string, EventListener | undefined>>;
|
|
75
77
|
/** Whether or not the VM was hydrated */
|
|
76
78
|
readonly hydrated: boolean;
|
|
77
79
|
/** Rendering operations associated with the VM */
|
|
@@ -109,6 +109,8 @@ export interface VNodeData {
|
|
|
109
109
|
readonly styleDecls?: ReadonlyArray<[string, string, boolean]>;
|
|
110
110
|
readonly context?: Readonly<Record<string, Readonly<Record<string, any>>>>;
|
|
111
111
|
readonly on?: Readonly<Record<string, (event: Event) => any>>;
|
|
112
|
+
readonly dynamicOn?: Readonly<Record<string, (event: Event) => any>>;
|
|
113
|
+
readonly dynamicOnRaw?: Readonly<Record<string, (event: Event) => any>>;
|
|
112
114
|
readonly svg?: boolean;
|
|
113
115
|
readonly renderer?: RendererAPI;
|
|
114
116
|
}
|
package/dist/index.cjs.js
CHANGED
|
@@ -251,16 +251,6 @@ function shouldBeFormAssociated(Ctor) {
|
|
|
251
251
|
}
|
|
252
252
|
return ctorFormAssociated && apiFeatureEnabled;
|
|
253
253
|
}
|
|
254
|
-
// check if a property is in an object, and if the object throws an error merely because we are
|
|
255
|
-
// checking if the property exists, return false
|
|
256
|
-
function safeHasProp(obj, prop) {
|
|
257
|
-
try {
|
|
258
|
-
return prop in obj;
|
|
259
|
-
}
|
|
260
|
-
catch (_err) {
|
|
261
|
-
return false;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
254
|
|
|
265
255
|
/*
|
|
266
256
|
* Copyright (c) 2024, Salesforce, Inc.
|
|
@@ -620,9 +610,6 @@ function componentValueObserved(vm, key, target = {}) {
|
|
|
620
610
|
if (lwcRuntimeFlags.ENABLE_EXPERIMENTAL_SIGNALS &&
|
|
621
611
|
shared.isObject(target) &&
|
|
622
612
|
!shared.isNull(target) &&
|
|
623
|
-
safeHasProp(target, 'value') &&
|
|
624
|
-
safeHasProp(target, 'subscribe') &&
|
|
625
|
-
shared.isFunction(target.subscribe) &&
|
|
626
613
|
shared.isTrustedSignal(target) &&
|
|
627
614
|
// Only subscribe if a template is being rendered by the engine
|
|
628
615
|
tro.isObserving()) {
|
|
@@ -4243,6 +4230,73 @@ function applyEventListeners(vnode, renderer) {
|
|
|
4243
4230
|
}
|
|
4244
4231
|
}
|
|
4245
4232
|
|
|
4233
|
+
/*
|
|
4234
|
+
* Copyright (c) 2025, salesforce.com, inc.
|
|
4235
|
+
* All rights reserved.
|
|
4236
|
+
* SPDX-License-Identifier: MIT
|
|
4237
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
4238
|
+
*/
|
|
4239
|
+
function patchDynamicEventListeners(oldVnode, vnode, renderer, owner) {
|
|
4240
|
+
const { elm, data: { dynamicOn, dynamicOnRaw }, sel, } = vnode;
|
|
4241
|
+
// dynamicOn : A cloned version of the object passed to lwc:on, with null prototype and only its own enumerable properties.
|
|
4242
|
+
const oldDynamicOn = oldVnode?.data?.dynamicOn ?? EmptyObject;
|
|
4243
|
+
const newDynamicOn = dynamicOn ?? EmptyObject;
|
|
4244
|
+
// dynamicOnRaw : object passed to lwc:on
|
|
4245
|
+
// Compare dynamicOnRaw to check if same object is passed to lwc:on
|
|
4246
|
+
const isObjectSame = oldVnode?.data?.dynamicOnRaw === dynamicOnRaw;
|
|
4247
|
+
const { addEventListener, removeEventListener } = renderer;
|
|
4248
|
+
const attachedEventListeners = getAttachedEventListeners(owner, elm);
|
|
4249
|
+
// Properties that are present in 'oldDynamicOn' but not in 'newDynamicOn'
|
|
4250
|
+
for (const eventType in oldDynamicOn) {
|
|
4251
|
+
if (!(eventType in newDynamicOn)) {
|
|
4252
|
+
// log error if same object is passed
|
|
4253
|
+
if (isObjectSame && process.env.NODE_ENV !== 'production') {
|
|
4254
|
+
logError(`Detected mutation of property '${eventType}' in the object passed to lwc:on for <${sel}>. Reusing the same object with modified properties is prohibited. Please pass a new object instead.`, owner);
|
|
4255
|
+
}
|
|
4256
|
+
// Remove listeners that were attached previously but don't have a corresponding property in `newDynamicOn`
|
|
4257
|
+
const attachedEventListener = attachedEventListeners[eventType];
|
|
4258
|
+
removeEventListener(elm, eventType, attachedEventListener);
|
|
4259
|
+
attachedEventListeners[eventType] = undefined;
|
|
4260
|
+
}
|
|
4261
|
+
}
|
|
4262
|
+
// Ensure that the event listeners that are attached match what is present in `newDynamicOn`
|
|
4263
|
+
for (const eventType in newDynamicOn) {
|
|
4264
|
+
const typeExistsInOld = eventType in oldDynamicOn;
|
|
4265
|
+
const newCallback = newDynamicOn[eventType];
|
|
4266
|
+
// Skip if callback hasn't changed
|
|
4267
|
+
if (typeExistsInOld && oldDynamicOn[eventType] === newCallback) {
|
|
4268
|
+
continue;
|
|
4269
|
+
}
|
|
4270
|
+
// log error if same object is passed
|
|
4271
|
+
if (isObjectSame && process.env.NODE_ENV !== 'production') {
|
|
4272
|
+
logError(`Detected mutation of property '${eventType}' in the object passed to lwc:on for <${sel}>. Reusing the same object with modified properties is prohibited. Please pass a new object instead.`, owner);
|
|
4273
|
+
}
|
|
4274
|
+
// Remove listener that was attached previously
|
|
4275
|
+
if (typeExistsInOld) {
|
|
4276
|
+
const attachedEventListener = attachedEventListeners[eventType];
|
|
4277
|
+
removeEventListener(elm, eventType, attachedEventListener);
|
|
4278
|
+
}
|
|
4279
|
+
// Bind new callback to owner component and add it as listener to element
|
|
4280
|
+
const newBoundEventListener = bindEventListener(owner, newCallback);
|
|
4281
|
+
addEventListener(elm, eventType, newBoundEventListener);
|
|
4282
|
+
// Store the newly added eventListener
|
|
4283
|
+
attachedEventListeners[eventType] = newBoundEventListener;
|
|
4284
|
+
}
|
|
4285
|
+
}
|
|
4286
|
+
function getAttachedEventListeners(vm, elm) {
|
|
4287
|
+
let attachedEventListeners = vm.attachedEventListeners.get(elm);
|
|
4288
|
+
if (shared.isUndefined(attachedEventListeners)) {
|
|
4289
|
+
attachedEventListeners = {};
|
|
4290
|
+
vm.attachedEventListeners.set(elm, attachedEventListeners);
|
|
4291
|
+
}
|
|
4292
|
+
return attachedEventListeners;
|
|
4293
|
+
}
|
|
4294
|
+
function bindEventListener(vm, fn) {
|
|
4295
|
+
return function (event) {
|
|
4296
|
+
invokeEventListener(vm, fn, vm.component, event);
|
|
4297
|
+
};
|
|
4298
|
+
}
|
|
4299
|
+
|
|
4246
4300
|
/*
|
|
4247
4301
|
* Copyright (c) 2018, salesforce.com, inc.
|
|
4248
4302
|
* All rights reserved.
|
|
@@ -4895,6 +4949,7 @@ function patchElementPropsAndAttrsAndRefs$1(oldVnode, vnode, renderer) {
|
|
|
4895
4949
|
applyStaticStyleAttribute(vnode, renderer);
|
|
4896
4950
|
}
|
|
4897
4951
|
const { owner } = vnode;
|
|
4952
|
+
patchDynamicEventListeners(oldVnode, vnode, renderer, owner);
|
|
4898
4953
|
// Attrs need to be applied to element before props IE11 will wipe out value on radio inputs if
|
|
4899
4954
|
// value is set before type=radio.
|
|
4900
4955
|
patchClassAttribute(oldVnode, vnode, renderer);
|
|
@@ -6776,6 +6831,7 @@ function createVM(elm, ctor, renderer, options) {
|
|
|
6776
6831
|
mode,
|
|
6777
6832
|
owner,
|
|
6778
6833
|
refVNodes: null,
|
|
6834
|
+
attachedEventListeners: new WeakMap(),
|
|
6779
6835
|
children: EmptyArray,
|
|
6780
6836
|
aChildren: EmptyArray,
|
|
6781
6837
|
velements: EmptyArray,
|
|
@@ -7982,6 +8038,7 @@ function handleMismatch(node, vnode, renderer) {
|
|
|
7982
8038
|
}
|
|
7983
8039
|
function patchElementPropsAndAttrsAndRefs(vnode, renderer) {
|
|
7984
8040
|
applyEventListeners(vnode, renderer);
|
|
8041
|
+
patchDynamicEventListeners(null, vnode, renderer, vnode.owner);
|
|
7985
8042
|
patchProps(null, vnode, renderer);
|
|
7986
8043
|
// The `refs` object is blown away in every re-render, so we always need to re-apply them
|
|
7987
8044
|
applyRefs(vnode, vnode.owner);
|
|
@@ -8529,5 +8586,5 @@ exports.swapTemplate = swapTemplate;
|
|
|
8529
8586
|
exports.track = track;
|
|
8530
8587
|
exports.unwrap = unwrap;
|
|
8531
8588
|
exports.wire = wire;
|
|
8532
|
-
/** version: 8.18.
|
|
8589
|
+
/** version: 8.18.2 */
|
|
8533
8590
|
//# sourceMappingURL=index.cjs.js.map
|
package/dist/index.js
CHANGED
|
@@ -248,16 +248,6 @@ function shouldBeFormAssociated(Ctor) {
|
|
|
248
248
|
}
|
|
249
249
|
return ctorFormAssociated && apiFeatureEnabled;
|
|
250
250
|
}
|
|
251
|
-
// check if a property is in an object, and if the object throws an error merely because we are
|
|
252
|
-
// checking if the property exists, return false
|
|
253
|
-
function safeHasProp(obj, prop) {
|
|
254
|
-
try {
|
|
255
|
-
return prop in obj;
|
|
256
|
-
}
|
|
257
|
-
catch (_err) {
|
|
258
|
-
return false;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
251
|
|
|
262
252
|
/*
|
|
263
253
|
* Copyright (c) 2024, Salesforce, Inc.
|
|
@@ -617,9 +607,6 @@ function componentValueObserved(vm, key, target = {}) {
|
|
|
617
607
|
if (lwcRuntimeFlags.ENABLE_EXPERIMENTAL_SIGNALS &&
|
|
618
608
|
isObject(target) &&
|
|
619
609
|
!isNull(target) &&
|
|
620
|
-
safeHasProp(target, 'value') &&
|
|
621
|
-
safeHasProp(target, 'subscribe') &&
|
|
622
|
-
isFunction$1(target.subscribe) &&
|
|
623
610
|
isTrustedSignal(target) &&
|
|
624
611
|
// Only subscribe if a template is being rendered by the engine
|
|
625
612
|
tro.isObserving()) {
|
|
@@ -4240,6 +4227,73 @@ function applyEventListeners(vnode, renderer) {
|
|
|
4240
4227
|
}
|
|
4241
4228
|
}
|
|
4242
4229
|
|
|
4230
|
+
/*
|
|
4231
|
+
* Copyright (c) 2025, salesforce.com, inc.
|
|
4232
|
+
* All rights reserved.
|
|
4233
|
+
* SPDX-License-Identifier: MIT
|
|
4234
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
4235
|
+
*/
|
|
4236
|
+
function patchDynamicEventListeners(oldVnode, vnode, renderer, owner) {
|
|
4237
|
+
const { elm, data: { dynamicOn, dynamicOnRaw }, sel, } = vnode;
|
|
4238
|
+
// dynamicOn : A cloned version of the object passed to lwc:on, with null prototype and only its own enumerable properties.
|
|
4239
|
+
const oldDynamicOn = oldVnode?.data?.dynamicOn ?? EmptyObject;
|
|
4240
|
+
const newDynamicOn = dynamicOn ?? EmptyObject;
|
|
4241
|
+
// dynamicOnRaw : object passed to lwc:on
|
|
4242
|
+
// Compare dynamicOnRaw to check if same object is passed to lwc:on
|
|
4243
|
+
const isObjectSame = oldVnode?.data?.dynamicOnRaw === dynamicOnRaw;
|
|
4244
|
+
const { addEventListener, removeEventListener } = renderer;
|
|
4245
|
+
const attachedEventListeners = getAttachedEventListeners(owner, elm);
|
|
4246
|
+
// Properties that are present in 'oldDynamicOn' but not in 'newDynamicOn'
|
|
4247
|
+
for (const eventType in oldDynamicOn) {
|
|
4248
|
+
if (!(eventType in newDynamicOn)) {
|
|
4249
|
+
// log error if same object is passed
|
|
4250
|
+
if (isObjectSame && process.env.NODE_ENV !== 'production') {
|
|
4251
|
+
logError(`Detected mutation of property '${eventType}' in the object passed to lwc:on for <${sel}>. Reusing the same object with modified properties is prohibited. Please pass a new object instead.`, owner);
|
|
4252
|
+
}
|
|
4253
|
+
// Remove listeners that were attached previously but don't have a corresponding property in `newDynamicOn`
|
|
4254
|
+
const attachedEventListener = attachedEventListeners[eventType];
|
|
4255
|
+
removeEventListener(elm, eventType, attachedEventListener);
|
|
4256
|
+
attachedEventListeners[eventType] = undefined;
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4259
|
+
// Ensure that the event listeners that are attached match what is present in `newDynamicOn`
|
|
4260
|
+
for (const eventType in newDynamicOn) {
|
|
4261
|
+
const typeExistsInOld = eventType in oldDynamicOn;
|
|
4262
|
+
const newCallback = newDynamicOn[eventType];
|
|
4263
|
+
// Skip if callback hasn't changed
|
|
4264
|
+
if (typeExistsInOld && oldDynamicOn[eventType] === newCallback) {
|
|
4265
|
+
continue;
|
|
4266
|
+
}
|
|
4267
|
+
// log error if same object is passed
|
|
4268
|
+
if (isObjectSame && process.env.NODE_ENV !== 'production') {
|
|
4269
|
+
logError(`Detected mutation of property '${eventType}' in the object passed to lwc:on for <${sel}>. Reusing the same object with modified properties is prohibited. Please pass a new object instead.`, owner);
|
|
4270
|
+
}
|
|
4271
|
+
// Remove listener that was attached previously
|
|
4272
|
+
if (typeExistsInOld) {
|
|
4273
|
+
const attachedEventListener = attachedEventListeners[eventType];
|
|
4274
|
+
removeEventListener(elm, eventType, attachedEventListener);
|
|
4275
|
+
}
|
|
4276
|
+
// Bind new callback to owner component and add it as listener to element
|
|
4277
|
+
const newBoundEventListener = bindEventListener(owner, newCallback);
|
|
4278
|
+
addEventListener(elm, eventType, newBoundEventListener);
|
|
4279
|
+
// Store the newly added eventListener
|
|
4280
|
+
attachedEventListeners[eventType] = newBoundEventListener;
|
|
4281
|
+
}
|
|
4282
|
+
}
|
|
4283
|
+
function getAttachedEventListeners(vm, elm) {
|
|
4284
|
+
let attachedEventListeners = vm.attachedEventListeners.get(elm);
|
|
4285
|
+
if (isUndefined$1(attachedEventListeners)) {
|
|
4286
|
+
attachedEventListeners = {};
|
|
4287
|
+
vm.attachedEventListeners.set(elm, attachedEventListeners);
|
|
4288
|
+
}
|
|
4289
|
+
return attachedEventListeners;
|
|
4290
|
+
}
|
|
4291
|
+
function bindEventListener(vm, fn) {
|
|
4292
|
+
return function (event) {
|
|
4293
|
+
invokeEventListener(vm, fn, vm.component, event);
|
|
4294
|
+
};
|
|
4295
|
+
}
|
|
4296
|
+
|
|
4243
4297
|
/*
|
|
4244
4298
|
* Copyright (c) 2018, salesforce.com, inc.
|
|
4245
4299
|
* All rights reserved.
|
|
@@ -4892,6 +4946,7 @@ function patchElementPropsAndAttrsAndRefs$1(oldVnode, vnode, renderer) {
|
|
|
4892
4946
|
applyStaticStyleAttribute(vnode, renderer);
|
|
4893
4947
|
}
|
|
4894
4948
|
const { owner } = vnode;
|
|
4949
|
+
patchDynamicEventListeners(oldVnode, vnode, renderer, owner);
|
|
4895
4950
|
// Attrs need to be applied to element before props IE11 will wipe out value on radio inputs if
|
|
4896
4951
|
// value is set before type=radio.
|
|
4897
4952
|
patchClassAttribute(oldVnode, vnode, renderer);
|
|
@@ -6773,6 +6828,7 @@ function createVM(elm, ctor, renderer, options) {
|
|
|
6773
6828
|
mode,
|
|
6774
6829
|
owner,
|
|
6775
6830
|
refVNodes: null,
|
|
6831
|
+
attachedEventListeners: new WeakMap(),
|
|
6776
6832
|
children: EmptyArray,
|
|
6777
6833
|
aChildren: EmptyArray,
|
|
6778
6834
|
velements: EmptyArray,
|
|
@@ -7979,6 +8035,7 @@ function handleMismatch(node, vnode, renderer) {
|
|
|
7979
8035
|
}
|
|
7980
8036
|
function patchElementPropsAndAttrsAndRefs(vnode, renderer) {
|
|
7981
8037
|
applyEventListeners(vnode, renderer);
|
|
8038
|
+
patchDynamicEventListeners(null, vnode, renderer, vnode.owner);
|
|
7982
8039
|
patchProps(null, vnode, renderer);
|
|
7983
8040
|
// The `refs` object is blown away in every re-render, so we always need to re-apply them
|
|
7984
8041
|
applyRefs(vnode, vnode.owner);
|
|
@@ -8475,5 +8532,5 @@ function readonly(obj) {
|
|
|
8475
8532
|
}
|
|
8476
8533
|
|
|
8477
8534
|
export { BaseBridgeElement, LightningElement, profilerControl as __unstable__ProfilerControl, reportingControl as __unstable__ReportingControl, api$1 as api, computeShadowAndRenderMode, connectRootElement, createContextProviderWithRegister, createVM, disconnectRootElement, freezeTemplate, getAssociatedVMIfPresent, getComponentAPIVersion, getComponentConstructor, getComponentDef, getComponentHtmlPrototype, hydrateRoot, isComponentConstructor, parseFragment, parseSVGFragment, readonly, registerComponent, registerDecorators, registerTemplate, runFormAssociatedCallback, runFormDisabledCallback, runFormResetCallback, runFormStateRestoreCallback, sanitizeAttribute, shouldBeFormAssociated, swapComponent, swapStyle, swapTemplate, track, unwrap, wire };
|
|
8478
|
-
/** version: 8.18.
|
|
8535
|
+
/** version: 8.18.2 */
|
|
8479
8536
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"You can safely modify dependencies, devDependencies, keywords, etc., but other props will be overwritten."
|
|
5
5
|
],
|
|
6
6
|
"name": "@lwc/engine-core",
|
|
7
|
-
"version": "8.18.
|
|
7
|
+
"version": "8.18.2",
|
|
8
8
|
"description": "Core LWC engine APIs.",
|
|
9
9
|
"keywords": [
|
|
10
10
|
"lwc"
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
}
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@lwc/features": "8.18.
|
|
50
|
-
"@lwc/shared": "8.18.
|
|
51
|
-
"@lwc/signals": "8.18.
|
|
49
|
+
"@lwc/features": "8.18.2",
|
|
50
|
+
"@lwc/shared": "8.18.2",
|
|
51
|
+
"@lwc/signals": "8.18.2"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"observable-membrane": "2.0.0"
|