{"version":3,"file":"react.es.mjs","names":[],"sources":["../../src/links/react/hasMouseEventProperties.ts","../../src/links/react/isModifiedNativeEvent.ts","../../src/links/react/isNativeLinkEvent.ts","../../src/links/react/isTouchLinkEvent.ts","../../src/links/react/nativeLinkHandlers.ts","../../src/links/react/tryStaffbaseContentOpenLink.ts","../../src/links/react/useInAppLinkHandling.ts"],"sourcesContent":["import type { NativeLinkEvent } from '../../types/links/NativeLinkEvent'\n\n/**\n * Whether a native link event exposes MouseEvent modifier properties.\n * @param {NativeLinkEvent} e - The native event.\n * @returns {boolean} True when the event has `button` and `metaKey`.\n */\nexport const hasMouseEventProperties = (\n  e: NativeLinkEvent,\n): e is MouseEvent | PointerEvent => {\n  return 'button' in e && 'metaKey' in e\n}\n","import type { NativeLinkEvent } from '../../types/links/NativeLinkEvent'\nimport { hasMouseEventProperties } from './hasMouseEventProperties'\n\n/**\n * Whether a native link event is \"modified\" and should be left to the browser\n * (default prevented, a non-primary mouse button, or a modifier key held).\n * @param {NativeLinkEvent} e - The native event.\n * @returns {boolean} True when the event should not be intercepted.\n */\nexport const isModifiedNativeEvent = (e: NativeLinkEvent): boolean => {\n  const hasMouseProps = hasMouseEventProperties(e)\n  const button = hasMouseProps && 'button' in e ? e.button : undefined\n  const metaKey = hasMouseProps ? e.metaKey : false\n  const ctrlKey = hasMouseProps ? e.ctrlKey : false\n  const shiftKey = hasMouseProps ? e.shiftKey : false\n  const altKey = hasMouseProps ? e.altKey : false\n\n  return Boolean(\n    e.defaultPrevented ||\n    (typeof button === 'number' && button !== 0) ||\n    metaKey ||\n    ctrlKey ||\n    shiftKey ||\n    altKey,\n  )\n}\n","import type { NativeLinkEvent } from '../../types/links/NativeLinkEvent'\n\n/**\n * Whether a value is a real native DOM event (as opposed to a React synthetic\n * event-like object), so the Staffbase content open-link path can be tried.\n * @param {NativeLinkEvent | { preventDefault?: () => void; stopPropagation?: () => void } | undefined} e - The candidate.\n * @returns {boolean} True when the value is a native Event.\n */\nexport const isNativeLinkEvent = (\n  e:\n    | { preventDefault?: () => void; stopPropagation?: () => void }\n    | NativeLinkEvent\n    | undefined,\n): e is NativeLinkEvent => {\n  return e !== undefined && 'target' in e && e instanceof Event\n}\n","import type { NativeLinkEvent } from '../../types/links/NativeLinkEvent'\n\n/**\n * Whether a native link event is a TouchEvent (has `changedTouches`).\n * @param {NativeLinkEvent} e - The native event.\n * @returns {boolean} True when the event is a TouchEvent.\n */\nexport const isTouchLinkEvent = (e: NativeLinkEvent): e is TouchEvent => {\n  return 'changedTouches' in e\n}\n","import type { NativeLinkEvent } from '../../types/links/NativeLinkEvent'\n\n/**\n * Tracks the capture-phase handler installed per container element, so the same\n * container is never wired twice and can be cleanly torn down on unmount.\n */\nexport const nativeLinkHandlers = new WeakMap<\n  HTMLElement,\n  (e: NativeLinkEvent) => void\n>()\n","import type { NativeLinkEvent } from '../../types/links/NativeLinkEvent'\nimport type { StaffbaseContentWindow } from '../../types/links/StaffbaseContentWindow'\n\n/**\n * Tries the host's own content open-link helper (the one Staffbase's widget\n * manager uses), to stay maximally aligned with platform behavior. Returns false\n * when the helper is absent or throws, so the caller can fall back.\n * @param {NativeLinkEvent} e - The originating native event.\n * @returns {boolean} True when the host helper handled the open.\n */\nexport const tryStaffbaseContentOpenLink = (e: NativeLinkEvent): boolean => {\n  const staffbase = (window as unknown as StaffbaseContentWindow).staffbase\n  const fn =\n    staffbase?.content?.link?.openLink ||\n    staffbase?.content?.links?.openLink ||\n    staffbase?.content?.loader?.link?.openLink\n\n  if (typeof fn !== 'function') return false\n\n  try {\n    fn({ useDefault: false }, e)\n    return true\n  } catch {\n    // The host helper is best-effort; fall back to standard navigation on error.\n    return false\n  }\n}\n","import type {\n  MouseEvent as ReactMouseEvent,\n  PointerEvent as ReactPointerEvent,\n  TouchEvent as ReactTouchEvent,\n} from 'react'\nimport { useCallback, useEffect, useRef } from 'react'\n\nimport type { NativeLinkEvent } from '../../types/links/NativeLinkEvent'\nimport type { UseInAppLinkHandlingOptions } from '../../types/links/UseInAppLinkHandlingOptions'\nimport type { UseInAppLinkHandlingReturn } from '../../types/links/UseInAppLinkHandlingReturn'\nimport { getInAppOpenLinkTarget } from '../getInAppOpenLinkTarget'\nimport { normalizeInAppLinks } from '../normalizeInAppLinks'\nimport { openStaffbaseAware } from '../openStaffbaseAware'\nimport { isModifiedNativeEvent } from './isModifiedNativeEvent'\nimport { isNativeLinkEvent } from './isNativeLinkEvent'\nimport { isTouchLinkEvent } from './isTouchLinkEvent'\nimport { nativeLinkHandlers } from './nativeLinkHandlers'\nimport { tryStaffbaseContentOpenLink } from './tryStaffbaseContentOpenLink'\n\nconst SUPPRESS_CLICK_WINDOW_MS = 700\n\n/**\n * Centralizes in-content link handling for Staffbase mobile/webview environments.\n *\n * Always attempts Staffbase-aware navigation (the host openLink when available,\n * otherwise same-tab navigation). It exposes React handlers for click/touchend/\n * pointerup and, when `containerRef` is given, installs a more reliable native\n * capture-phase handler. Touch/pointer/click are de-duplicated within a short\n * window so a single tap never fires navigation twice in iOS webviews.\n * @param {UseInAppLinkHandlingOptions} options - Origin, after-open callback and optional container ref.\n * @returns {UseInAppLinkHandlingReturn} prepareHtmlContent plus the React event handlers.\n */\nexport const useInAppLinkHandling = ({\n  staffbaseOrigin,\n  onAfterOpen,\n  containerRef,\n}: UseInAppLinkHandlingOptions): UseInAppLinkHandlingReturn => {\n  const lastTouchAtRef = useRef<number | null>(null)\n  const lastHandledAtRef = useRef<number | null>(null)\n  const lastHandledTypeRef = useRef<'touch' | 'pointer' | null>(null)\n  const lastHandledAnchorRef = useRef<HTMLAnchorElement | null>(null)\n\n  const prepareHtmlContent = useCallback(\n    (content: HTMLElement): HTMLElement => {\n      normalizeInAppLinks(content, staffbaseOrigin)\n      return content\n    },\n    [staffbaseOrigin],\n  )\n\n  const handleAnchor = useCallback(\n    (\n      anchor: HTMLAnchorElement,\n      e?:\n        | { preventDefault?: () => void; stopPropagation?: () => void }\n        | NativeLinkEvent,\n    ) => {\n      const linkToOpen = getInAppOpenLinkTarget(\n        anchor.getAttribute('href') ?? anchor.href ?? null,\n        staffbaseOrigin,\n      )\n      if (!linkToOpen) return\n\n      // Handle both React synthetic event-like objects and native events.\n      if (e && 'preventDefault' in e) {\n        e.preventDefault?.()\n        e.stopPropagation?.()\n      }\n\n      // Prefer Staffbase's own content link handler when this is a native event.\n      if (isNativeLinkEvent(e)) {\n        // Touch events in some webviews don't trigger Staffbase openLink reliably.\n        if (isTouchLinkEvent(e)) {\n          openStaffbaseAware(linkToOpen)\n          onAfterOpen?.()\n          return\n        }\n        if (!tryStaffbaseContentOpenLink(e)) {\n          openStaffbaseAware(linkToOpen)\n        }\n      } else {\n        openStaffbaseAware(linkToOpen)\n      }\n      onAfterOpen?.()\n    },\n    [onAfterOpen, staffbaseOrigin],\n  )\n\n  const handleContentClick = useCallback(\n    (e: ReactMouseEvent<HTMLElement>) => {\n      if (e.defaultPrevented) return\n      if (\n        lastTouchAtRef.current &&\n        Date.now() - lastTouchAtRef.current < SUPPRESS_CLICK_WINDOW_MS\n      ) {\n        return\n      }\n\n      const target = e.target\n      if (!(target instanceof Element)) return\n\n      const anchor = target.closest('a')\n      if (!anchor) return\n      handleAnchor(anchor, e)\n    },\n    [handleAnchor],\n  )\n\n  const handleContentTouchEnd = useCallback(\n    (e: ReactTouchEvent<HTMLElement>) => {\n      if (e.defaultPrevented) return\n      const target = e.target\n      if (!(target instanceof Element)) return\n\n      const anchor = target.closest('a')\n      if (!anchor) return\n\n      if (\n        lastHandledAtRef.current &&\n        lastHandledTypeRef.current === 'pointer' &&\n        lastHandledAnchorRef.current === anchor &&\n        Date.now() - lastHandledAtRef.current < SUPPRESS_CLICK_WINDOW_MS\n      ) {\n        return\n      }\n\n      lastTouchAtRef.current = Date.now()\n      lastHandledAtRef.current = lastTouchAtRef.current\n      lastHandledTypeRef.current = 'touch'\n      lastHandledAnchorRef.current = anchor\n      handleAnchor(anchor, e.nativeEvent)\n    },\n    [handleAnchor],\n  )\n\n  const handleContentPointerUp = useCallback(\n    (e: ReactPointerEvent<HTMLElement>) => {\n      if (e.defaultPrevented) return\n      const target = e.target\n      if (!(target instanceof Element)) return\n\n      const anchor = target.closest('a')\n      if (!anchor) return\n\n      if (\n        lastHandledAtRef.current &&\n        lastHandledTypeRef.current === 'touch' &&\n        lastHandledAnchorRef.current === anchor &&\n        Date.now() - lastHandledAtRef.current < SUPPRESS_CLICK_WINDOW_MS\n      ) {\n        return\n      }\n\n      lastTouchAtRef.current = Date.now()\n      lastHandledAtRef.current = lastTouchAtRef.current\n      lastHandledTypeRef.current = 'pointer'\n      lastHandledAnchorRef.current = anchor\n      handleAnchor(anchor, e.nativeEvent)\n    },\n    [handleAnchor],\n  )\n\n  useEffect(() => {\n    const container = containerRef?.current\n    if (!container) return\n\n    if (nativeLinkHandlers.has(container)) return\n\n    /**\n     * Capture-phase handler intercepting link activations on the container.\n     * @param {NativeLinkEvent} e - The native click/touchend/pointerup event.\n     * @returns {void} Nothing.\n     */\n    const handler = (e: NativeLinkEvent) => {\n      try {\n        if (isModifiedNativeEvent(e)) return\n        const target = e.target\n        if (!(target instanceof Element)) return\n\n        const anchor = target.closest('a')\n        if (!anchor) return\n\n        const now = Date.now()\n        if (\n          lastHandledAtRef.current &&\n          lastHandledAnchorRef.current === anchor &&\n          now - lastHandledAtRef.current < SUPPRESS_CLICK_WINDOW_MS\n        ) {\n          return\n        }\n\n        lastHandledAtRef.current = now\n        lastHandledTypeRef.current = isTouchLinkEvent(e) ? 'touch' : 'pointer'\n        lastHandledAnchorRef.current = anchor\n        handleAnchor(anchor, e)\n      } catch {\n        // Capture-phase handler must never throw into the host event loop.\n      }\n    }\n\n    nativeLinkHandlers.set(container, handler)\n    container.addEventListener('click', handler, true)\n    container.addEventListener('touchend', handler, true)\n    // Pointer events may be enabled in some webviews; harmless if unused.\n    container.addEventListener('pointerup', handler, true)\n\n    return () => {\n      container.removeEventListener('click', handler, true)\n      container.removeEventListener('touchend', handler, true)\n      container.removeEventListener('pointerup', handler, true)\n      nativeLinkHandlers.delete(container)\n    }\n  }, [containerRef, handleAnchor])\n\n  return {\n    prepareHtmlContent,\n    handleContentClick,\n    handleContentTouchEnd,\n    handleContentPointerUp,\n  }\n}\n"],"mappings":"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"}