From 564fe316c494aa0da074de98f5f46252b2d0de7c Mon Sep 17 00:00:00 2001 From: Sam Martin Date: Thu, 14 Mar 2024 13:02:10 -0700 Subject: [PATCH 1/2] utilizing the slottedParent rather than parent when appropriate for recontructing dom. ensuring we process slotted nodes after all others --- packages/clarity-js/src/layout/node.ts | 6 +++ packages/clarity-js/src/layout/traverse.ts | 54 ++++++++++++++-------- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/packages/clarity-js/src/layout/node.ts b/packages/clarity-js/src/layout/node.ts index 61b1a3d7..a73626ab 100644 --- a/packages/clarity-js/src/layout/node.ts +++ b/packages/clarity-js/src/layout/node.ts @@ -90,6 +90,12 @@ export default function (node: Node, source: Source): Node { // In some cases, external libraries like vue-fragment, can modify parentNode property to not be in sync with the DOM // For correctness, we first look at parentElement and if it not present then fall back to using parentNode parent = node.parentElement ? node.parentElement : (node.parentNode ? node.parentNode as HTMLElement : null); + // For HTML slots, the parentElement doesn't actually match what is rendered. If we have an assignedSlot, we use that + // as the parent to ensure our visualizations match the browser behavior for end users. + var slottedParent = (node as HTMLElement).assignedSlot; + if (slottedParent) { + parent = slottedParent; + } // If we encounter a node that is part of SVG namespace, prefix the tag with SVG_PREFIX if (element.namespaceURI === Constant.SvgNamespace) { tag = Constant.SvgPrefix + tag; } diff --git a/packages/clarity-js/src/layout/traverse.ts b/packages/clarity-js/src/layout/traverse.ts index 679e7d44..313e53a1 100644 --- a/packages/clarity-js/src/layout/traverse.ts +++ b/packages/clarity-js/src/layout/traverse.ts @@ -4,25 +4,41 @@ import * as task from "@src/core/task"; import node from "@src/layout/node"; export default async function(root: Node, timer: Timer, source: Source): Promise { - let queue = [root]; - while (queue.length > 0) { - let entry = queue.shift(); - let next = entry.firstChild; - - while (next) { - queue.push(next); - next = next.nextSibling; + let primaryQueue = [root]; + let slottedNodesQueue: Node[] = []; + for (var currentQueue of [primaryQueue, slottedNodesQueue]) { + while (currentQueue.length > 0) { + let entry = currentQueue.shift(); + let next = entry.firstChild; + + while (next) { + // During traversal there is not a guarantee that the assigned child here is being found after the slot to which it is placed + // as the typical parent/child methods don't reflect what is rendered. We need to make sure all other mutations and + // discoveries are processed before we process a slotted element. Once we are processing the slottedNodesQueue we can + // skip this effort and go directly to our breadth first traversal. + if (currentQueue == primaryQueue) { + var slottedParent = (next as HTMLElement).assignedSlot; + if (slottedParent) { + slottedNodesQueue.push(next); + } else { + currentQueue.push(next); + } + } else { + currentQueue.push(next); + } + next = next.nextSibling; + } + + // Check the status of current task to see if we should yield before continuing + let state = task.state(timer); + if (state === Task.Wait) { state = await task.suspend(timer); } + if (state === Task.Stop) { break; } + + // Check if processing a node gives us a pointer to one of its sub nodes for traversal + // E.g. an element node may give us a pointer to traverse shadowDom if shadowRoot property is set + // Or, an iframe from the same origin could give a pointer to it's document for traversing contents of iframe. + let subnode = node(entry, source); + if (subnode) { currentQueue.push(subnode); } } - - // Check the status of current task to see if we should yield before continuing - let state = task.state(timer); - if (state === Task.Wait) { state = await task.suspend(timer); } - if (state === Task.Stop) { break; } - - // Check if processing a node gives us a pointer to one of its sub nodes for traversal - // E.g. an element node may give us a pointer to traverse shadowDom if shadowRoot property is set - // Or, an iframe from the same origin could give a pointer to it's document for traversing contents of iframe. - let subnode = node(entry, source); - if (subnode) { queue.push(subnode); } } } From 835876681313045f6d44a5663b5faaedea31eb46 Mon Sep 17 00:00:00 2001 From: Sam Martin Date: Thu, 14 Mar 2024 13:02:54 -0700 Subject: [PATCH 2/2] version rev --- packages/clarity-decode/package.json | 4 ++-- packages/clarity-devtools/package.json | 8 ++++---- packages/clarity-devtools/static/manifest.json | 4 ++-- packages/clarity-js/package.json | 2 +- packages/clarity-js/src/core/version.ts | 2 +- packages/clarity-visualize/package.json | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/clarity-decode/package.json b/packages/clarity-decode/package.json index 4d41c9bf..cca962be 100644 --- a/packages/clarity-decode/package.json +++ b/packages/clarity-decode/package.json @@ -1,6 +1,6 @@ { "name": "clarity-decode", - "version": "0.7.24", + "version": "0.7.25", "description": "An analytics library that uses web page interactions to generate aggregated insights", "author": "Microsoft Corp.", "license": "MIT", @@ -26,7 +26,7 @@ "url": "https://github.com/Microsoft/clarity/issues" }, "dependencies": { - "clarity-js": "^0.7.24" + "clarity-js": "^0.7.25" }, "devDependencies": { "@rollup/plugin-commonjs": "^24.0.0", diff --git a/packages/clarity-devtools/package.json b/packages/clarity-devtools/package.json index 777e2921..6c354a75 100644 --- a/packages/clarity-devtools/package.json +++ b/packages/clarity-devtools/package.json @@ -1,6 +1,6 @@ { "name": "clarity-devtools", - "version": "0.7.24", + "version": "0.7.25", "private": true, "description": "Adds Clarity debugging support to browser devtools", "author": "Microsoft Corp.", @@ -24,9 +24,9 @@ "url": "https://github.com/Microsoft/clarity/issues" }, "dependencies": { - "clarity-decode": "^0.7.24", - "clarity-js": "^0.7.24", - "clarity-visualize": "^0.7.24" + "clarity-decode": "^0.7.25", + "clarity-js": "^0.7.25", + "clarity-visualize": "^0.7.25" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.0.0", diff --git a/packages/clarity-devtools/static/manifest.json b/packages/clarity-devtools/static/manifest.json index 5fddfdef..8932cb98 100644 --- a/packages/clarity-devtools/static/manifest.json +++ b/packages/clarity-devtools/static/manifest.json @@ -2,8 +2,8 @@ "manifest_version": 2, "name": "Microsoft Clarity Developer Tools", "description": "Clarity helps you understand how users are interacting with your website.", - "version": "0.7.23", - "version_name": "0.7.23", + "version": "0.7.25", + "version_name": "0.7.25", "minimum_chrome_version": "50", "devtools_page": "devtools.html", "icons": { diff --git a/packages/clarity-js/package.json b/packages/clarity-js/package.json index 0aa6aaa6..6d1a4cf1 100644 --- a/packages/clarity-js/package.json +++ b/packages/clarity-js/package.json @@ -1,6 +1,6 @@ { "name": "clarity-js", - "version": "0.7.24", + "version": "0.7.25", "description": "An analytics library that uses web page interactions to generate aggregated insights", "author": "Microsoft Corp.", "license": "MIT", diff --git a/packages/clarity-js/src/core/version.ts b/packages/clarity-js/src/core/version.ts index 4b998d0a..63525337 100644 --- a/packages/clarity-js/src/core/version.ts +++ b/packages/clarity-js/src/core/version.ts @@ -1,2 +1,2 @@ -let version = "0.7.24"; +let version = "0.7.25"; export default version; diff --git a/packages/clarity-visualize/package.json b/packages/clarity-visualize/package.json index fea456b7..e949e408 100644 --- a/packages/clarity-visualize/package.json +++ b/packages/clarity-visualize/package.json @@ -1,6 +1,6 @@ { "name": "clarity-visualize", - "version": "0.7.24", + "version": "0.7.25", "description": "An analytics library that uses web page interactions to generate aggregated insights", "author": "Microsoft Corp.", "license": "MIT", @@ -27,7 +27,7 @@ "url": "https://github.com/Microsoft/clarity/issues" }, "dependencies": { - "clarity-decode": "^0.7.24" + "clarity-decode": "^0.7.25" }, "devDependencies": { "@rollup/plugin-commonjs": "^24.0.0",