@webspatial/core-sdk 1.6.0 → 1.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webspatial/core-sdk",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "description": "this is the core js API for webspatial",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -4,6 +4,7 @@ import {
4
4
  initScene,
5
5
  injectSceneHook,
6
6
  __getSceneConfigSnapshotForTest,
7
+ hijackWindowATag,
7
8
  } from './scene-polyfill'
8
9
  import { SpatialSceneCreationOptions } from './types/types'
9
10
  import { pointToPhysical } from './physicalMetrics'
@@ -464,3 +465,62 @@ describe('initScene callback chaining', () => {
464
465
  expect(cb2).toHaveBeenCalledWith(firstReturn)
465
466
  })
466
467
  })
468
+
469
+ describe('hijackWindowATag', () => {
470
+ afterEach(() => {
471
+ document.body.innerHTML = ''
472
+ document.onclick = null
473
+ vi.restoreAllMocks()
474
+ })
475
+
476
+ it('handles clicks on nested elements inside anchor tags', () => {
477
+ const openSpy = vi.spyOn(window, 'open').mockImplementation(() => null)
478
+ hijackWindowATag(window)
479
+
480
+ const anchor = document.createElement('a')
481
+ anchor.href = 'https://example.com/detail'
482
+ anchor.target = '_blank'
483
+
484
+ const image = document.createElement('img')
485
+ anchor.appendChild(image)
486
+ document.body.appendChild(anchor)
487
+
488
+ image.dispatchEvent(
489
+ new MouseEvent('click', { bubbles: true, cancelable: true }),
490
+ )
491
+
492
+ expect(openSpy).toHaveBeenCalledWith('https://example.com/detail', '_blank')
493
+ })
494
+ })
495
+
496
+ describe('hijackWindowATag – defaultPrevented', () => {
497
+ afterEach(() => {
498
+ document.body.innerHTML = ''
499
+ document.onclick = null
500
+ vi.restoreAllMocks()
501
+ })
502
+
503
+ it('does not open a new window when the click was already preventDefault-ed', () => {
504
+ const openSpy = vi.spyOn(window, 'open').mockImplementation(() => null)
505
+ hijackWindowATag(window)
506
+
507
+ const anchor = document.createElement('a')
508
+ anchor.href = 'https://example.com/detail'
509
+ anchor.target = '_blank'
510
+
511
+ const span = document.createElement('span')
512
+ anchor.appendChild(span)
513
+ document.body.appendChild(anchor)
514
+
515
+ // Simulate an app-level handler that cancels the click before the polyfill sees it.
516
+ span.addEventListener('click', ev => {
517
+ ev.preventDefault()
518
+ })
519
+
520
+ span.dispatchEvent(
521
+ new MouseEvent('click', { bubbles: true, cancelable: true }),
522
+ )
523
+
524
+ expect(openSpy).not.toHaveBeenCalled()
525
+ })
526
+ })
@@ -523,23 +523,22 @@ export function hijackWindowOpen(window: WindowProxy) {
523
523
  export function hijackWindowATag(openedWindow: WindowProxy) {
524
524
  openedWindow!.document.onclick = function (e) {
525
525
  let element = e.target as HTMLElement | null
526
- let found = false
527
526
 
528
527
  // Look for <a> element in the clicked elements parents and if found override navigation behavior if needed
529
- while (!found) {
530
- if (element && element.tagName == 'A') {
528
+ while (element) {
529
+ if (element.tagName == 'A') {
531
530
  // When using libraries like react route's <Link> it sets an onclick event, when this happens we should do nothing and let that occur
532
531
 
533
532
  // if onClick is set for the element, the raw onclick will be noop() trapped so the onclick check is no longer trustable
534
533
  // we handle all the scenarios
535
534
 
536
- if (handleATag(e)) {
535
+ if (handleATag(e, element as HTMLAnchorElement)) {
537
536
  return false // prevent default action and stop event propagation
538
537
  }
539
538
 
540
539
  return true
541
540
  }
542
- if (element && element.parentElement) {
541
+ if (element.parentElement) {
543
542
  element = element.parentElement
544
543
  } else {
545
544
  break
@@ -548,18 +547,17 @@ export function hijackWindowATag(openedWindow: WindowProxy) {
548
547
  }
549
548
  }
550
549
 
551
- function handleATag(event: MouseEvent) {
552
- const targetElement = event.target as HTMLElement
553
- if (targetElement.tagName === 'A') {
554
- const link = targetElement as HTMLAnchorElement
555
- const target = link.target
556
- const url = link.href
557
-
558
- if (target && target !== '_self') {
559
- event.preventDefault()
560
- window.open(url, target)
561
- return true
562
- }
550
+ function handleATag(event: MouseEvent, link: HTMLAnchorElement) {
551
+ // Respect clicks that have already been cancelled (e.g. by app/router handlers).
552
+ if (event.defaultPrevented) return false
553
+ // Use the anchor found during bubbling so nested clicks like <a><img /></a> are handled correctly.
554
+ const target = link.target
555
+ const url = link.href
556
+
557
+ if (target && target !== '_self') {
558
+ event.preventDefault()
559
+ window.open(url, target)
560
+ return true
563
561
  }
564
562
  }
565
563