From c90c8aa19e98cdfd84c8b5eebc6939f95826ebfe Mon Sep 17 00:00:00 2001 From: Andrea Vaccari Date: Tue, 23 Nov 2021 11:47:21 -0600 Subject: [PATCH] feat: Use `composedPath` to find anchor elements (#2769) * feat: Use `composedPath` to find anchor elements The client-side router registers event handlers on mouse movements and clicks that search anchor elements in an event's target's ancestors to perform prefetching or routing. The current implementation uses `parentNode` which "skips" anchor elements in shadow doms. This change searches instead the `event.composedPath()`, which includes nodes in open shadow trees. * refactor: `find_anchor` to receive a full event * test: Add integration tests * docs: Add changeset --- .changeset/unlucky-phones-promise.md | 5 ++++ packages/kit/src/runtime/client/router.js | 16 +++++++------ .../src/routes/routing/shadow-dom/_tests.js | 24 +++++++++++++++++++ .../routes/routing/shadow-dom/index.svelte | 18 ++++++++++++++ 4 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 .changeset/unlucky-phones-promise.md create mode 100644 packages/kit/test/apps/basics/src/routes/routing/shadow-dom/_tests.js create mode 100644 packages/kit/test/apps/basics/src/routes/routing/shadow-dom/index.svelte diff --git a/.changeset/unlucky-phones-promise.md b/.changeset/unlucky-phones-promise.md new file mode 100644 index 000000000000..f443495c62f2 --- /dev/null +++ b/.changeset/unlucky-phones-promise.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +[feat] Use `event.composedPath` to find anchors for prefetching and routing diff --git a/packages/kit/src/runtime/client/router.js b/packages/kit/src/runtime/client/router.js index 98501951c4cc..927bbe59f088 100644 --- a/packages/kit/src/runtime/client/router.js +++ b/packages/kit/src/runtime/client/router.js @@ -8,12 +8,14 @@ function scroll_state() { } /** - * @param {Node | null} node - * @returns {HTMLAnchorElement | SVGAElement | null} + * @param {Event} event + * @returns {HTMLAnchorElement | SVGAElement | undefined} */ -function find_anchor(node) { - while (node && node.nodeName.toUpperCase() !== 'A') node = node.parentNode; // SVG elements have a lowercase name - return /** @type {HTMLAnchorElement | SVGAElement} */ (node); +function find_anchor(event) { + const node = event + .composedPath() + .find((e) => e instanceof Node && e.nodeName.toUpperCase() === 'A'); // SVG elements have a lowercase name + return /** @type {HTMLAnchorElement | SVGAElement | undefined} */ (node); } /** @@ -94,7 +96,7 @@ export class Router { /** @param {MouseEvent|TouchEvent} event */ const trigger_prefetch = (event) => { - const a = find_anchor(/** @type {Node} */ (event.target)); + const a = find_anchor(event); if (a && a.href && a.hasAttribute('sveltekit:prefetch')) { this.prefetch(get_href(a)); } @@ -124,7 +126,7 @@ export class Router { if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return; if (event.defaultPrevented) return; - const a = find_anchor(/** @type {Node} */ (event.target)); + const a = find_anchor(event); if (!a) return; if (!a.href) return; diff --git a/packages/kit/test/apps/basics/src/routes/routing/shadow-dom/_tests.js b/packages/kit/test/apps/basics/src/routes/routing/shadow-dom/_tests.js new file mode 100644 index 000000000000..32450f90b5d3 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/routing/shadow-dom/_tests.js @@ -0,0 +1,24 @@ +import * as assert from 'uvu/assert'; + +/** @type {import('test').TestMaker} */ +export default function (test) { + test( + 'client router captures anchors in shadow dom', + '/routing/shadow-dom', + async ({ app, capture_requests, page, clicknav, js }) => { + if (js) { + await app.prefetchRoutes(['/routing/a']).catch((e) => { + // from error handler tests; ignore + if (!e.message.includes('Crashing now')) throw e; + }); + + const requests = await capture_requests(async () => { + await clicknav('div[id="clickme"]'); + assert.equal(await page.textContent('h1'), 'a'); + }); + + assert.equal(requests, []); + } + } + ); +} diff --git a/packages/kit/test/apps/basics/src/routes/routing/shadow-dom/index.svelte b/packages/kit/test/apps/basics/src/routes/routing/shadow-dom/index.svelte new file mode 100644 index 000000000000..9f5160f46e83 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/routing/shadow-dom/index.svelte @@ -0,0 +1,18 @@ + + +
+
Hello world
+