@lwc/synthetic-shadow 8.27.0 → 8.28.1

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/LICENSE.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  MIT LICENSE
4
4
 
5
- Copyright (c) 2025, Salesforce, Inc.
5
+ Copyright (c) 2026, Salesforce, Inc.
6
6
  All rights reserved.
7
7
 
8
8
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
@@ -20,9 +20,8 @@ declare const _Node: {
20
20
  readonly DOCUMENT_POSITION_CONTAINED_BY: 16;
21
21
  readonly DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: 32;
22
22
  };
23
- declare const DOCUMENT_POSITION_CONTAINED_BY: 16, DOCUMENT_POSITION_CONTAINS: 8, DOCUMENT_POSITION_PRECEDING: 2, DOCUMENT_POSITION_FOLLOWING: 4, ELEMENT_NODE: 1, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_FRAGMENT_NODE: 11;
24
- declare const appendChild: <T extends Node>(node: T) => T, cloneNode: (subtree?: boolean) => Node, compareDocumentPosition: (other: Node) => number, insertBefore: <T extends Node>(node: T, child: Node | null) => T, removeChild: <T extends Node>(child: T) => T, replaceChild: <T extends Node>(node: Node, child: T) => T, hasChildNodes: () => boolean;
25
- declare const contains: (other: Node | null) => boolean;
23
+ export declare const DOCUMENT_POSITION_CONTAINED_BY: 16, DOCUMENT_POSITION_CONTAINS: 8, DOCUMENT_POSITION_PRECEDING: 2, DOCUMENT_POSITION_FOLLOWING: 4, ELEMENT_NODE: 1, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_FRAGMENT_NODE: 11;
24
+ export declare const appendChild: <T extends Node>(node: T) => T, cloneNode: (subtree?: boolean) => Node, compareDocumentPosition: (other: Node) => number, contains: (other: Node | null) => boolean, getRootNode: (options?: GetRootNodeOptions) => Node, insertBefore: <T extends Node>(node: T, child: Node | null) => T, removeChild: <T extends Node>(child: T) => T, replaceChild: <T extends Node>(node: Node, child: T) => T, hasChildNodes: () => boolean;
26
25
  declare const firstChildGetter: (this: Node) => ChildNode | null;
27
26
  declare const lastChildGetter: (this: Node) => ChildNode | null;
28
27
  declare const textContentGetter: (this: Node) => string;
@@ -33,5 +32,5 @@ declare const textContextSetter: (this: Node, s: string) => void;
33
32
  declare const childNodesGetter: (this: Node) => NodeListOf<Node & Element>;
34
33
  declare const nextSiblingGetter: (this: Node) => ChildNode | null;
35
34
  declare const isConnected: () => any;
36
- export { _Node as Node, appendChild, childNodesGetter, cloneNode, compareDocumentPosition, insertBefore, isConnected, parentElementGetter, parentNodeGetter, removeChild, replaceChild, textContextSetter, ownerDocumentGetter, hasChildNodes, contains, firstChildGetter, lastChildGetter, textContentGetter, nextSiblingGetter, DOCUMENT_POSITION_CONTAINS, DOCUMENT_POSITION_CONTAINED_BY, DOCUMENT_POSITION_PRECEDING, DOCUMENT_POSITION_FOLLOWING, ELEMENT_NODE, TEXT_NODE, CDATA_SECTION_NODE, PROCESSING_INSTRUCTION_NODE, COMMENT_NODE, DOCUMENT_FRAGMENT_NODE, };
35
+ export { _Node as Node, childNodesGetter, isConnected, parentElementGetter, parentNodeGetter, textContextSetter, ownerDocumentGetter, firstChildGetter, lastChildGetter, textContentGetter, nextSiblingGetter, };
37
36
  //# sourceMappingURL=node.d.ts.map
package/dist/index.cjs.js CHANGED
@@ -197,7 +197,7 @@ const KEY__LEGACY_SHADOW_TOKEN_PRIVATE = '$$LegacyShadowTokenKey$$';
197
197
  const KEY__SYNTHETIC_MODE = '$$lwc-synthetic-mode';
198
198
  const KEY__NATIVE_GET_ELEMENT_BY_ID = '$nativeGetElementById$';
199
199
  const KEY__NATIVE_QUERY_SELECTOR_ALL = '$nativeQuerySelectorAll$';
200
- /** version: 8.27.0 */
200
+ /** version: 8.28.1 */
201
201
 
202
202
  /**
203
203
  * Copyright (c) 2026 Salesforce, Inc.
@@ -205,7 +205,7 @@ const KEY__NATIVE_QUERY_SELECTOR_ALL = '$nativeQuerySelectorAll$';
205
205
  if (!globalThis.lwcRuntimeFlags) {
206
206
  Object.defineProperty(globalThis, 'lwcRuntimeFlags', { value: create(null) });
207
207
  }
208
- /** version: 8.27.0 */
208
+ /** version: 8.28.1 */
209
209
 
210
210
  /*
211
211
  * Copyright (c) 2018, salesforce.com, inc.
@@ -218,8 +218,7 @@ if (!globalThis.lwcRuntimeFlags) {
218
218
  const _Node = Node;
219
219
  const nodePrototype = _Node.prototype;
220
220
  const { DOCUMENT_POSITION_CONTAINED_BY, DOCUMENT_POSITION_CONTAINS, DOCUMENT_POSITION_PRECEDING, DOCUMENT_POSITION_FOLLOWING, ELEMENT_NODE, TEXT_NODE, CDATA_SECTION_NODE, PROCESSING_INSTRUCTION_NODE, COMMENT_NODE} = _Node;
221
- const { appendChild, cloneNode, compareDocumentPosition, insertBefore, removeChild, replaceChild, hasChildNodes, } = nodePrototype;
222
- const { contains } = HTMLElement.prototype;
221
+ const { appendChild, cloneNode, compareDocumentPosition, contains, getRootNode: getRootNode$1, insertBefore, removeChild, replaceChild, hasChildNodes, } = nodePrototype;
223
222
  const firstChildGetter = getOwnPropertyDescriptor(nodePrototype, 'firstChild').get;
224
223
  const lastChildGetter = getOwnPropertyDescriptor(nodePrototype, 'lastChild').get;
225
224
  const textContentGetter = getOwnPropertyDescriptor(nodePrototype, 'textContent').get;
@@ -1104,6 +1103,18 @@ function createStaticHTMLCollection(items) {
1104
1103
  * SPDX-License-Identifier: MIT
1105
1104
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
1106
1105
  */
1106
+ const getRootNode = getRootNode$1 ??
1107
+ // Polyfill for older browsers where it's not defined
1108
+ function () {
1109
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
1110
+ let node = this;
1111
+ let nodeParent = parentNodeGetter.call(node);
1112
+ while (!isNull(nodeParent)) {
1113
+ node = nodeParent;
1114
+ nodeParent = parentElementGetter.call(node);
1115
+ }
1116
+ return node;
1117
+ };
1107
1118
  /**
1108
1119
  * This method checks whether or not the content of the node is computed
1109
1120
  * based on the light-dom slotting mechanism. This applies to synthetic slot elements
@@ -1174,23 +1185,7 @@ function parentElementGetterPatched() {
1174
1185
  // TODO [#1635]: this needs optimization, maybe implementing it based on this.assignedSlot
1175
1186
  return parentNode instanceof Element ? parentNode : null;
1176
1187
  }
1177
- function compareDocumentPositionPatched(otherNode) {
1178
- if (this === otherNode) {
1179
- return 0;
1180
- }
1181
- else if (this.getRootNode() === otherNode) {
1182
- // "this" is in a shadow tree where the shadow root is the "otherNode".
1183
- return 10; // Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING
1184
- }
1185
- else if (getNodeOwnerKey(this) !== getNodeOwnerKey(otherNode)) {
1186
- // "this" and "otherNode" belongs to 2 different shadow tree.
1187
- return 35; // Node.DOCUMENT_POSITION_DISCONNECTED | Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | Node.DOCUMENT_POSITION_PRECEDING
1188
- }
1189
- // Since "this" and "otherNode" are part of the same shadow tree we can safely rely to the native
1190
- // Node.compareDocumentPosition implementation.
1191
- return compareDocumentPosition.call(this, otherNode);
1192
- }
1193
- function containsPatched(otherNode) {
1188
+ function containsPatched$1(otherNode) {
1194
1189
  if (otherNode == null || getNodeOwnerKey(this) !== getNodeOwnerKey(otherNode)) {
1195
1190
  // it is from another shadow
1196
1191
  return false;
@@ -1227,23 +1222,6 @@ function childNodesGetterPatched() {
1227
1222
  // TODO [#1636]: what about slot elements?
1228
1223
  return childNodesGetter.call(this);
1229
1224
  }
1230
- const nativeGetRootNode = _Node.prototype.getRootNode;
1231
- /**
1232
- * Get the root by climbing up the dom tree, beyond the shadow root
1233
- * If Node.prototype.getRootNode is supported, use it
1234
- * else, assume we are working in non-native shadow mode and climb using parentNode
1235
- */
1236
- const getDocumentOrRootNode = !isUndefined(nativeGetRootNode)
1237
- ? nativeGetRootNode
1238
- : function () {
1239
- // eslint-disable-next-line @typescript-eslint/no-this-alias
1240
- let node = this;
1241
- let nodeParent;
1242
- while (!isNull((nodeParent = parentNodeGetter.call(node)))) {
1243
- node = nodeParent;
1244
- }
1245
- return node;
1246
- };
1247
1225
  /**
1248
1226
  * Get the shadow root
1249
1227
  * getNodeOwner() returns the host element that owns the given node
@@ -1257,7 +1235,7 @@ function getNearestRoot(node) {
1257
1235
  const ownerNode = getNodeOwner(node);
1258
1236
  if (isNull(ownerNode)) {
1259
1237
  // we hit a wall, either we are in native shadow mode or the node is not in lwc boundary.
1260
- return getDocumentOrRootNode.call(node);
1238
+ return getRootNode.call(node);
1261
1239
  }
1262
1240
  return getShadowRoot(ownerNode);
1263
1241
  }
@@ -1280,9 +1258,24 @@ function getNearestRoot(node) {
1280
1258
  * _Spec_: https://dom.spec.whatwg.org/#dom-node-getrootnode
1281
1259
  * @param options
1282
1260
  */
1283
- function getRootNodePatched(options) {
1284
- const composed = isUndefined(options) ? false : !!options.composed;
1285
- return isTrue(composed) ? getDocumentOrRootNode.call(this, options) : getNearestRoot(this);
1261
+ function getRootNodePatched$3(options) {
1262
+ return options?.composed ? getRootNode.call(this, options) : getNearestRoot(this);
1263
+ }
1264
+ function compareDocumentPositionPatched(otherNode) {
1265
+ if (this === otherNode) {
1266
+ return 0;
1267
+ }
1268
+ else if (getRootNodePatched$3.call(this) === otherNode) {
1269
+ // "this" is in a shadow tree where the shadow root is the "otherNode".
1270
+ return 10; // Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING
1271
+ }
1272
+ else if (getNodeOwnerKey(this) !== getNodeOwnerKey(otherNode)) {
1273
+ // "this" and "otherNode" belongs to 2 different shadow tree.
1274
+ return 35; // Node.DOCUMENT_POSITION_DISCONNECTED | Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | Node.DOCUMENT_POSITION_PRECEDING
1275
+ }
1276
+ // Since "this" and "otherNode" are part of the same shadow tree we can safely rely to the native
1277
+ // Node.compareDocumentPosition implementation.
1278
+ return compareDocumentPosition.call(this, otherNode);
1286
1279
  }
1287
1280
  // Non-deep-traversing patches: this descriptor map includes all descriptors that
1288
1281
  // do not give access to nodes beyond the immediate children.
@@ -1401,7 +1394,7 @@ defineProperties(_Node.prototype, {
1401
1394
  return false;
1402
1395
  }
1403
1396
  if (isNodeShadowed(this) || isSyntheticShadowHost(this)) {
1404
- return containsPatched.call(this, otherNode);
1397
+ return containsPatched$1.call(this, otherNode);
1405
1398
  }
1406
1399
  return contains.call(this, otherNode);
1407
1400
  },
@@ -1423,7 +1416,7 @@ defineProperties(_Node.prototype, {
1423
1416
  configurable: true,
1424
1417
  },
1425
1418
  getRootNode: {
1426
- value: getRootNodePatched,
1419
+ value: getRootNodePatched$3,
1427
1420
  enumerable: true,
1428
1421
  configurable: true,
1429
1422
  writable: true,
@@ -1711,6 +1704,8 @@ function removeShadowRootEventListener(sr, type, listener, _options) {
1711
1704
  * SPDX-License-Identifier: MIT
1712
1705
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
1713
1706
  */
1707
+ const getRootNodePatched$2 = _Node.prototype.getRootNode;
1708
+ assert.isFalse(String(getRootNodePatched$2).includes('[native code]'), 'Node prototype must be patched before patching shadow root.');
1714
1709
  const InternalSlot = new WeakMap();
1715
1710
  const { createDocumentFragment } = document;
1716
1711
  function hasInternalSlot(root) {
@@ -1803,6 +1798,16 @@ function attachShadow(elm, options) {
1803
1798
  setPrototypeOf(sr, SyntheticShadowRoot.prototype);
1804
1799
  return sr;
1805
1800
  }
1801
+ // Defined separately from others because it's used in `compareDocumentPosition`
1802
+ function containsPatched(otherNode) {
1803
+ if (this === otherNode) {
1804
+ return true;
1805
+ }
1806
+ const host = getHost(this);
1807
+ // must be child of the host and owned by it.
1808
+ return ((compareDocumentPosition.call(host, otherNode) & DOCUMENT_POSITION_CONTAINED_BY) !== 0 &&
1809
+ isNodeOwnedBy(host, otherNode));
1810
+ }
1806
1811
  const SyntheticShadowRootDescriptors = {
1807
1812
  constructor: {
1808
1813
  writable: true,
@@ -2007,7 +2012,7 @@ const NodePatchDescriptors = {
2007
2012
  // "this" and "otherNode" are the same shadow root.
2008
2013
  return 0;
2009
2014
  }
2010
- else if (this.contains(otherNode)) {
2015
+ else if (containsPatched.call(this, otherNode)) {
2011
2016
  // "otherNode" belongs to the shadow tree where "this" is the shadow root.
2012
2017
  return 20; // Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING
2013
2018
  }
@@ -2025,15 +2030,7 @@ const NodePatchDescriptors = {
2025
2030
  writable: true,
2026
2031
  enumerable: true,
2027
2032
  configurable: true,
2028
- value(otherNode) {
2029
- if (this === otherNode) {
2030
- return true;
2031
- }
2032
- const host = getHost(this);
2033
- // must be child of the host and owned by it.
2034
- return ((compareDocumentPosition.call(host, otherNode) & DOCUMENT_POSITION_CONTAINED_BY) !==
2035
- 0 && isNodeOwnedBy(host, otherNode));
2036
- },
2033
+ value: containsPatched,
2037
2034
  },
2038
2035
  firstChild: {
2039
2036
  enumerable: true,
@@ -2148,8 +2145,8 @@ const NodePatchDescriptors = {
2148
2145
  enumerable: true,
2149
2146
  configurable: true,
2150
2147
  value(options) {
2151
- return !isUndefined(options) && isTrue(options.composed)
2152
- ? getHost(this).getRootNode(options)
2148
+ return isTrue(options?.composed)
2149
+ ? getRootNodePatched$2.call(getHost(this), { composed: true })
2153
2150
  : this;
2154
2151
  },
2155
2152
  },
@@ -2864,13 +2861,15 @@ defineProperty(window, 'MutationObserver', {
2864
2861
  * SPDX-License-Identifier: MIT
2865
2862
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
2866
2863
  */
2864
+ const getRootNodePatched$1 = _Node.prototype.getRootNode;
2865
+ assert.isFalse(String(getRootNodePatched$1).includes('[native code]'), 'Node prototype must be patched before event target.');
2867
2866
  function patchedAddEventListener(type, listener, optionsOrCapture) {
2868
2867
  if (isSyntheticShadowHost(this)) {
2869
2868
  // Typescript does not like it when you treat the `arguments` object as an array
2870
2869
  // @ts-expect-error type-mismatch
2871
2870
  return addCustomElementEventListener.apply(this, arguments);
2872
2871
  }
2873
- if (this instanceof _Node && isInstanceOfNativeShadowRoot(this.getRootNode())) {
2872
+ if (this instanceof _Node && isInstanceOfNativeShadowRoot(getRootNodePatched$1.call(this))) {
2874
2873
  // Typescript does not like it when you treat the `arguments` object as an array
2875
2874
  // @ts-expect-error type-mismatch
2876
2875
  return addEventListener.apply(this, arguments);
@@ -3630,6 +3629,8 @@ if (hasOwnProperty.call(HTMLElement.prototype, 'getElementsByClassName')) {
3630
3629
  * SPDX-License-Identifier: MIT
3631
3630
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
3632
3631
  */
3632
+ const getRootNodePatched = _Node.prototype.getRootNode;
3633
+ assert.isFalse(String(getRootNodePatched).includes('[native code]'), 'Node prototype must be patched before patching focus.');
3633
3634
  const FocusableSelector = `
3634
3635
  [contenteditable],
3635
3636
  [tabindex],
@@ -3682,7 +3683,7 @@ function isTabbable(element) {
3682
3683
  return matches.call(element, FocusableSelector) && isVisible(element);
3683
3684
  }
3684
3685
  function hostElementFocus() {
3685
- const _rootNode = this.getRootNode();
3686
+ const _rootNode = getRootNodePatched.call(this);
3686
3687
  if (_rootNode === this) {
3687
3688
  // We invoke the focus() method even if the host is disconnected in order to eliminate
3688
3689
  // observable differences for component authors between synthetic and native.
@@ -4363,6 +4364,6 @@ defineProperty(Element.prototype, '$domManual$', {
4363
4364
  },
4364
4365
  configurable: true,
4365
4366
  });
4366
- /** version: 8.27.0 */
4367
+ /** version: 8.28.1 */
4367
4368
  }
4368
4369
  //# sourceMappingURL=index.cjs.js.map
package/dist/index.js CHANGED
@@ -195,7 +195,7 @@ const KEY__LEGACY_SHADOW_TOKEN_PRIVATE = '$$LegacyShadowTokenKey$$';
195
195
  const KEY__SYNTHETIC_MODE = '$$lwc-synthetic-mode';
196
196
  const KEY__NATIVE_GET_ELEMENT_BY_ID = '$nativeGetElementById$';
197
197
  const KEY__NATIVE_QUERY_SELECTOR_ALL = '$nativeQuerySelectorAll$';
198
- /** version: 8.27.0 */
198
+ /** version: 8.28.1 */
199
199
 
200
200
  /**
201
201
  * Copyright (c) 2026 Salesforce, Inc.
@@ -203,7 +203,7 @@ const KEY__NATIVE_QUERY_SELECTOR_ALL = '$nativeQuerySelectorAll$';
203
203
  if (!globalThis.lwcRuntimeFlags) {
204
204
  Object.defineProperty(globalThis, 'lwcRuntimeFlags', { value: create(null) });
205
205
  }
206
- /** version: 8.27.0 */
206
+ /** version: 8.28.1 */
207
207
 
208
208
  /*
209
209
  * Copyright (c) 2018, salesforce.com, inc.
@@ -216,8 +216,7 @@ if (!globalThis.lwcRuntimeFlags) {
216
216
  const _Node = Node;
217
217
  const nodePrototype = _Node.prototype;
218
218
  const { DOCUMENT_POSITION_CONTAINED_BY, DOCUMENT_POSITION_CONTAINS, DOCUMENT_POSITION_PRECEDING, DOCUMENT_POSITION_FOLLOWING, ELEMENT_NODE, TEXT_NODE, CDATA_SECTION_NODE, PROCESSING_INSTRUCTION_NODE, COMMENT_NODE} = _Node;
219
- const { appendChild, cloneNode, compareDocumentPosition, insertBefore, removeChild, replaceChild, hasChildNodes, } = nodePrototype;
220
- const { contains } = HTMLElement.prototype;
219
+ const { appendChild, cloneNode, compareDocumentPosition, contains, getRootNode: getRootNode$1, insertBefore, removeChild, replaceChild, hasChildNodes, } = nodePrototype;
221
220
  const firstChildGetter = getOwnPropertyDescriptor(nodePrototype, 'firstChild').get;
222
221
  const lastChildGetter = getOwnPropertyDescriptor(nodePrototype, 'lastChild').get;
223
222
  const textContentGetter = getOwnPropertyDescriptor(nodePrototype, 'textContent').get;
@@ -1102,6 +1101,18 @@ function createStaticHTMLCollection(items) {
1102
1101
  * SPDX-License-Identifier: MIT
1103
1102
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
1104
1103
  */
1104
+ const getRootNode = getRootNode$1 ??
1105
+ // Polyfill for older browsers where it's not defined
1106
+ function () {
1107
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
1108
+ let node = this;
1109
+ let nodeParent = parentNodeGetter.call(node);
1110
+ while (!isNull(nodeParent)) {
1111
+ node = nodeParent;
1112
+ nodeParent = parentElementGetter.call(node);
1113
+ }
1114
+ return node;
1115
+ };
1105
1116
  /**
1106
1117
  * This method checks whether or not the content of the node is computed
1107
1118
  * based on the light-dom slotting mechanism. This applies to synthetic slot elements
@@ -1172,23 +1183,7 @@ function parentElementGetterPatched() {
1172
1183
  // TODO [#1635]: this needs optimization, maybe implementing it based on this.assignedSlot
1173
1184
  return parentNode instanceof Element ? parentNode : null;
1174
1185
  }
1175
- function compareDocumentPositionPatched(otherNode) {
1176
- if (this === otherNode) {
1177
- return 0;
1178
- }
1179
- else if (this.getRootNode() === otherNode) {
1180
- // "this" is in a shadow tree where the shadow root is the "otherNode".
1181
- return 10; // Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING
1182
- }
1183
- else if (getNodeOwnerKey(this) !== getNodeOwnerKey(otherNode)) {
1184
- // "this" and "otherNode" belongs to 2 different shadow tree.
1185
- return 35; // Node.DOCUMENT_POSITION_DISCONNECTED | Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | Node.DOCUMENT_POSITION_PRECEDING
1186
- }
1187
- // Since "this" and "otherNode" are part of the same shadow tree we can safely rely to the native
1188
- // Node.compareDocumentPosition implementation.
1189
- return compareDocumentPosition.call(this, otherNode);
1190
- }
1191
- function containsPatched(otherNode) {
1186
+ function containsPatched$1(otherNode) {
1192
1187
  if (otherNode == null || getNodeOwnerKey(this) !== getNodeOwnerKey(otherNode)) {
1193
1188
  // it is from another shadow
1194
1189
  return false;
@@ -1225,23 +1220,6 @@ function childNodesGetterPatched() {
1225
1220
  // TODO [#1636]: what about slot elements?
1226
1221
  return childNodesGetter.call(this);
1227
1222
  }
1228
- const nativeGetRootNode = _Node.prototype.getRootNode;
1229
- /**
1230
- * Get the root by climbing up the dom tree, beyond the shadow root
1231
- * If Node.prototype.getRootNode is supported, use it
1232
- * else, assume we are working in non-native shadow mode and climb using parentNode
1233
- */
1234
- const getDocumentOrRootNode = !isUndefined(nativeGetRootNode)
1235
- ? nativeGetRootNode
1236
- : function () {
1237
- // eslint-disable-next-line @typescript-eslint/no-this-alias
1238
- let node = this;
1239
- let nodeParent;
1240
- while (!isNull((nodeParent = parentNodeGetter.call(node)))) {
1241
- node = nodeParent;
1242
- }
1243
- return node;
1244
- };
1245
1223
  /**
1246
1224
  * Get the shadow root
1247
1225
  * getNodeOwner() returns the host element that owns the given node
@@ -1255,7 +1233,7 @@ function getNearestRoot(node) {
1255
1233
  const ownerNode = getNodeOwner(node);
1256
1234
  if (isNull(ownerNode)) {
1257
1235
  // we hit a wall, either we are in native shadow mode or the node is not in lwc boundary.
1258
- return getDocumentOrRootNode.call(node);
1236
+ return getRootNode.call(node);
1259
1237
  }
1260
1238
  return getShadowRoot(ownerNode);
1261
1239
  }
@@ -1278,9 +1256,24 @@ function getNearestRoot(node) {
1278
1256
  * _Spec_: https://dom.spec.whatwg.org/#dom-node-getrootnode
1279
1257
  * @param options
1280
1258
  */
1281
- function getRootNodePatched(options) {
1282
- const composed = isUndefined(options) ? false : !!options.composed;
1283
- return isTrue(composed) ? getDocumentOrRootNode.call(this, options) : getNearestRoot(this);
1259
+ function getRootNodePatched$3(options) {
1260
+ return options?.composed ? getRootNode.call(this, options) : getNearestRoot(this);
1261
+ }
1262
+ function compareDocumentPositionPatched(otherNode) {
1263
+ if (this === otherNode) {
1264
+ return 0;
1265
+ }
1266
+ else if (getRootNodePatched$3.call(this) === otherNode) {
1267
+ // "this" is in a shadow tree where the shadow root is the "otherNode".
1268
+ return 10; // Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING
1269
+ }
1270
+ else if (getNodeOwnerKey(this) !== getNodeOwnerKey(otherNode)) {
1271
+ // "this" and "otherNode" belongs to 2 different shadow tree.
1272
+ return 35; // Node.DOCUMENT_POSITION_DISCONNECTED | Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | Node.DOCUMENT_POSITION_PRECEDING
1273
+ }
1274
+ // Since "this" and "otherNode" are part of the same shadow tree we can safely rely to the native
1275
+ // Node.compareDocumentPosition implementation.
1276
+ return compareDocumentPosition.call(this, otherNode);
1284
1277
  }
1285
1278
  // Non-deep-traversing patches: this descriptor map includes all descriptors that
1286
1279
  // do not give access to nodes beyond the immediate children.
@@ -1399,7 +1392,7 @@ defineProperties(_Node.prototype, {
1399
1392
  return false;
1400
1393
  }
1401
1394
  if (isNodeShadowed(this) || isSyntheticShadowHost(this)) {
1402
- return containsPatched.call(this, otherNode);
1395
+ return containsPatched$1.call(this, otherNode);
1403
1396
  }
1404
1397
  return contains.call(this, otherNode);
1405
1398
  },
@@ -1421,7 +1414,7 @@ defineProperties(_Node.prototype, {
1421
1414
  configurable: true,
1422
1415
  },
1423
1416
  getRootNode: {
1424
- value: getRootNodePatched,
1417
+ value: getRootNodePatched$3,
1425
1418
  enumerable: true,
1426
1419
  configurable: true,
1427
1420
  writable: true,
@@ -1709,6 +1702,8 @@ function removeShadowRootEventListener(sr, type, listener, _options) {
1709
1702
  * SPDX-License-Identifier: MIT
1710
1703
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
1711
1704
  */
1705
+ const getRootNodePatched$2 = _Node.prototype.getRootNode;
1706
+ assert.isFalse(String(getRootNodePatched$2).includes('[native code]'), 'Node prototype must be patched before patching shadow root.');
1712
1707
  const InternalSlot = new WeakMap();
1713
1708
  const { createDocumentFragment } = document;
1714
1709
  function hasInternalSlot(root) {
@@ -1801,6 +1796,16 @@ function attachShadow(elm, options) {
1801
1796
  setPrototypeOf(sr, SyntheticShadowRoot.prototype);
1802
1797
  return sr;
1803
1798
  }
1799
+ // Defined separately from others because it's used in `compareDocumentPosition`
1800
+ function containsPatched(otherNode) {
1801
+ if (this === otherNode) {
1802
+ return true;
1803
+ }
1804
+ const host = getHost(this);
1805
+ // must be child of the host and owned by it.
1806
+ return ((compareDocumentPosition.call(host, otherNode) & DOCUMENT_POSITION_CONTAINED_BY) !== 0 &&
1807
+ isNodeOwnedBy(host, otherNode));
1808
+ }
1804
1809
  const SyntheticShadowRootDescriptors = {
1805
1810
  constructor: {
1806
1811
  writable: true,
@@ -2005,7 +2010,7 @@ const NodePatchDescriptors = {
2005
2010
  // "this" and "otherNode" are the same shadow root.
2006
2011
  return 0;
2007
2012
  }
2008
- else if (this.contains(otherNode)) {
2013
+ else if (containsPatched.call(this, otherNode)) {
2009
2014
  // "otherNode" belongs to the shadow tree where "this" is the shadow root.
2010
2015
  return 20; // Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING
2011
2016
  }
@@ -2023,15 +2028,7 @@ const NodePatchDescriptors = {
2023
2028
  writable: true,
2024
2029
  enumerable: true,
2025
2030
  configurable: true,
2026
- value(otherNode) {
2027
- if (this === otherNode) {
2028
- return true;
2029
- }
2030
- const host = getHost(this);
2031
- // must be child of the host and owned by it.
2032
- return ((compareDocumentPosition.call(host, otherNode) & DOCUMENT_POSITION_CONTAINED_BY) !==
2033
- 0 && isNodeOwnedBy(host, otherNode));
2034
- },
2031
+ value: containsPatched,
2035
2032
  },
2036
2033
  firstChild: {
2037
2034
  enumerable: true,
@@ -2146,8 +2143,8 @@ const NodePatchDescriptors = {
2146
2143
  enumerable: true,
2147
2144
  configurable: true,
2148
2145
  value(options) {
2149
- return !isUndefined(options) && isTrue(options.composed)
2150
- ? getHost(this).getRootNode(options)
2146
+ return isTrue(options?.composed)
2147
+ ? getRootNodePatched$2.call(getHost(this), { composed: true })
2151
2148
  : this;
2152
2149
  },
2153
2150
  },
@@ -2862,13 +2859,15 @@ defineProperty(window, 'MutationObserver', {
2862
2859
  * SPDX-License-Identifier: MIT
2863
2860
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
2864
2861
  */
2862
+ const getRootNodePatched$1 = _Node.prototype.getRootNode;
2863
+ assert.isFalse(String(getRootNodePatched$1).includes('[native code]'), 'Node prototype must be patched before event target.');
2865
2864
  function patchedAddEventListener(type, listener, optionsOrCapture) {
2866
2865
  if (isSyntheticShadowHost(this)) {
2867
2866
  // Typescript does not like it when you treat the `arguments` object as an array
2868
2867
  // @ts-expect-error type-mismatch
2869
2868
  return addCustomElementEventListener.apply(this, arguments);
2870
2869
  }
2871
- if (this instanceof _Node && isInstanceOfNativeShadowRoot(this.getRootNode())) {
2870
+ if (this instanceof _Node && isInstanceOfNativeShadowRoot(getRootNodePatched$1.call(this))) {
2872
2871
  // Typescript does not like it when you treat the `arguments` object as an array
2873
2872
  // @ts-expect-error type-mismatch
2874
2873
  return addEventListener.apply(this, arguments);
@@ -3628,6 +3627,8 @@ if (hasOwnProperty.call(HTMLElement.prototype, 'getElementsByClassName')) {
3628
3627
  * SPDX-License-Identifier: MIT
3629
3628
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
3630
3629
  */
3630
+ const getRootNodePatched = _Node.prototype.getRootNode;
3631
+ assert.isFalse(String(getRootNodePatched).includes('[native code]'), 'Node prototype must be patched before patching focus.');
3631
3632
  const FocusableSelector = `
3632
3633
  [contenteditable],
3633
3634
  [tabindex],
@@ -3680,7 +3681,7 @@ function isTabbable(element) {
3680
3681
  return matches.call(element, FocusableSelector) && isVisible(element);
3681
3682
  }
3682
3683
  function hostElementFocus() {
3683
- const _rootNode = this.getRootNode();
3684
+ const _rootNode = getRootNodePatched.call(this);
3684
3685
  if (_rootNode === this) {
3685
3686
  // We invoke the focus() method even if the host is disconnected in order to eliminate
3686
3687
  // observable differences for component authors between synthetic and native.
@@ -4361,6 +4362,6 @@ defineProperty(Element.prototype, '$domManual$', {
4361
4362
  },
4362
4363
  configurable: true,
4363
4364
  });
4364
- /** version: 8.27.0 */
4365
+ /** version: 8.28.1 */
4365
4366
  }
4366
4367
  //# 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/synthetic-shadow",
7
- "version": "8.27.0",
7
+ "version": "8.28.1",
8
8
  "description": "Synthetic Shadow Root for LWC",
9
9
  "keywords": [
10
10
  "lwc"
@@ -46,8 +46,8 @@
46
46
  }
47
47
  },
48
48
  "devDependencies": {
49
- "@lwc/features": "8.27.0",
50
- "@lwc/shared": "8.27.0"
49
+ "@lwc/features": "8.28.1",
50
+ "@lwc/shared": "8.28.1"
51
51
  },
52
52
  "lwc": {
53
53
  "modules": [