mount-observer 0.1.5 → 0.1.7

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.
@@ -16,7 +16,11 @@ Object.defineProperty(Element.prototype, 'mount', {
16
16
  const scope = options.scope ?? 'registry';
17
17
  let thingToObserve;
18
18
  if (scope === 'registry') {
19
- thingToObserve = getRootRegistryContainer(this);
19
+ const registryContainer = getRootRegistryContainer(this);
20
+ if (!registryContainer) {
21
+ throw new Error('Could not find root registry container');
22
+ }
23
+ thingToObserve = registryContainer;
20
24
  }
21
25
  else if (scope === 'self') {
22
26
  thingToObserve = this;
@@ -35,7 +35,11 @@ Object.defineProperty(Element.prototype, 'mount', {
35
35
  let thingToObserve: Node;
36
36
 
37
37
  if (scope === 'registry') {
38
- thingToObserve = getRootRegistryContainer(this);
38
+ const registryContainer = getRootRegistryContainer(this);
39
+ if (!registryContainer) {
40
+ throw new Error('Could not find root registry container');
41
+ }
42
+ thingToObserve = registryContainer;
39
43
  } else if (scope === 'self') {
40
44
  thingToObserve = this;
41
45
  } else if (scope === 'root') {
@@ -1,27 +1,49 @@
1
1
  /**
2
- * Finds the highest scoped container that has the same customElementRegistry as the given element.
2
+ * Recursively traverses up the DOM tree to find the highest node
3
+ * that shares the same customElementRegistry as the passed in node.
3
4
  * This is useful for scoped custom element registries where we want to observe within the correct scope.
4
5
  *
5
- * @param element - The element to find the root registry container for
6
- * @returns The root node or highest parent element with the same customElementRegistry
6
+ * @param node - The starting node to check
7
+ * @returns The highest node with matching customElementRegistry, or null if node is invalid
7
8
  */
8
- export function getRootRegistryContainer(element) {
9
- const rn = element.getRootNode();
10
- const { customElementRegistry } = element;
11
- // If root node has the same registry, return it
9
+ export function getRootRegistryContainer(node) {
10
+ if (!node) {
11
+ return null;
12
+ }
13
+ // Quick check: if root node has the same registry, return it immediately
14
+ const rn = node.getRootNode();
15
+ const { customElementRegistry } = node;
12
16
  if (rn.customElementRegistry === customElementRegistry) {
13
17
  return rn;
14
18
  }
15
- // Walk up the parent chain to find the highest element with the same registry
16
- let parent = element.parentElement;
17
- while (parent) {
18
- const prevParent = parent;
19
- parent = parent.parentElement;
20
- // If parent has a different registry, return the previous parent
21
- if (parent && parent.customElementRegistry !== customElementRegistry) {
22
- return prevParent;
19
+ const startRegistry = node.customElementRegistry;
20
+ let currentNode = node;
21
+ let highestMatch = node;
22
+ while (currentNode) {
23
+ // Check if current node has matching customElementRegistry
24
+ if (currentNode.customElementRegistry === startRegistry) {
25
+ highestMatch = currentNode;
26
+ }
27
+ // Try to get parent element first
28
+ const parent = currentNode.parentElement;
29
+ if (parent) {
30
+ currentNode = parent;
31
+ continue;
32
+ }
33
+ // If no parent element, check for rootNode (shadow root case)
34
+ const root = currentNode.getRootNode();
35
+ if (root && root !== currentNode) {
36
+ // If it's a shadow root (not document), return it
37
+ if (root !== document) {
38
+ return root;
39
+ }
40
+ // If it's the document, check if it has the same registry
41
+ if (root.customElementRegistry === startRegistry) {
42
+ return root;
43
+ }
23
44
  }
45
+ // Reached the top
46
+ break;
24
47
  }
25
- // If we reached the top without finding a different registry, return the element itself
26
- return element;
48
+ return highestMatch;
27
49
  }
@@ -1,32 +1,56 @@
1
1
  /**
2
- * Finds the highest scoped container that has the same customElementRegistry as the given element.
2
+ * Recursively traverses up the DOM tree to find the highest node
3
+ * that shares the same customElementRegistry as the passed in node.
3
4
  * This is useful for scoped custom element registries where we want to observe within the correct scope.
4
5
  *
5
- * @param element - The element to find the root registry container for
6
- * @returns The root node or highest parent element with the same customElementRegistry
6
+ * @param node - The starting node to check
7
+ * @returns The highest node with matching customElementRegistry, or null if node is invalid
7
8
  */
8
- export function getRootRegistryContainer(element: Element): Node {
9
- const rn = element.getRootNode();
10
- const { customElementRegistry } = element as any;
11
-
12
- // If root node has the same registry, return it
9
+ export function getRootRegistryContainer(node: Node): Node | null {
10
+ if (!node) {
11
+ return null;
12
+ }
13
+
14
+ // Quick check: if root node has the same registry, return it immediately
15
+ const rn = node.getRootNode();
16
+ const { customElementRegistry } = node as any;
13
17
  if ((rn as any).customElementRegistry === customElementRegistry) {
14
18
  return rn;
15
19
  }
16
-
17
- // Walk up the parent chain to find the highest element with the same registry
18
- let parent = element.parentElement;
19
-
20
- while (parent) {
21
- const prevParent = parent;
22
- parent = parent.parentElement;
23
-
24
- // If parent has a different registry, return the previous parent
25
- if (parent && (parent as any).customElementRegistry !== customElementRegistry) {
26
- return prevParent;
20
+
21
+ const startRegistry = (node as any).customElementRegistry;
22
+ let currentNode: Node | null = node;
23
+ let highestMatch: Node = node;
24
+
25
+ while (currentNode) {
26
+ // Check if current node has matching customElementRegistry
27
+ if ((currentNode as any).customElementRegistry === startRegistry) {
28
+ highestMatch = currentNode;
29
+ }
30
+
31
+ // Try to get parent element first
32
+ const parent = (currentNode as any).parentElement as Element | null;
33
+ if (parent) {
34
+ currentNode = parent;
35
+ continue;
27
36
  }
37
+
38
+ // If no parent element, check for rootNode (shadow root case)
39
+ const root = currentNode.getRootNode();
40
+ if (root && root !== currentNode) {
41
+ // If it's a shadow root (not document), return it
42
+ if (root !== document) {
43
+ return root;
44
+ }
45
+ // If it's the document, check if it has the same registry
46
+ if ((root as any).customElementRegistry === startRegistry) {
47
+ return root;
48
+ }
49
+ }
50
+
51
+ // Reached the top
52
+ break;
28
53
  }
29
-
30
- // If we reached the top without finding a different registry, return the element itself
31
- return element;
54
+
55
+ return highestMatch;
32
56
  }
package/index.js CHANGED
@@ -9,6 +9,7 @@ export { mountEventName, dismountEventName, disconnectEventName, loadEventName,
9
9
  // Register built-in handlers
10
10
  import { MountObserver } from './MountObserver.js';
11
11
  import { EvtRt } from './EvtRt.js';
12
- import { DefineCustomElementHandler } from './DefineCustomElementHandler.js';
12
+ import { DefineCustomElementHandler, DefineScopedCustomElementHandler } from './DefineCustomElementHandler.js';
13
13
  MountObserver.define('builtIns.logToConsole', EvtRt);
14
14
  MountObserver.define('builtIns.defineCustomElement', DefineCustomElementHandler);
15
+ MountObserver.define('buildIns.defineScopedCustomElement', DefineScopedCustomElementHandler);
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "mount-observer",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Observe and act on css matches.",
5
5
  "main": "MountObserver.js",
6
6
  "module": "MountObserver.js",
7
7
  "dependencies": {
8
- "assign-gingerly": "0.0.12"
8
+ "assign-gingerly": "0.0.13"
9
9
  },
10
10
  "devDependencies": {
11
11
  "@playwright/test": "1.58.2",