{"version":3,"file":"use-link-action-Degb-dB7.mjs","names":[],"sources":["../../widgets/src/hooks/use-link-action.ts"],"sourcesContent":["import { useCallback, useMemo } from \"react\";\nimport type { ShareableItem } from \"@fluid-app/portal-core/types\";\nimport { useRepUser } from \"../contexts/RepUserContext\";\nimport { useWidgetInteraction } from \"../contexts/WidgetInteractionContext\";\nimport { isBrowserHandledClick } from \"../lib/browser-click\";\nimport {\n  type LinkType,\n  type ShareSource,\n  decoratedHref,\n  sanitizeHref,\n  triggerShare,\n} from \"../lib/link-type-utils\";\n\nexport interface UseLinkActionOptions {\n  linkType?: LinkType | undefined;\n  href?: string | undefined;\n  openInNewTab?: boolean | undefined;\n  screenSlug?: string | undefined;\n  shareSource?: ShareSource | undefined;\n  shareResource?: ShareableItem | undefined;\n  shareUrl?: string | undefined;\n}\n\nexport interface LinkAction {\n  /** The resolved href for anchor elements (URL and Screen modes). */\n  resolvedHref: string | undefined;\n  /** Click handler — use for screen navigation and share actions. */\n  handleClick: (e: React.MouseEvent) => void;\n  /** Whether the link target is valid and should be interactive. */\n  hasTarget: boolean;\n  /** Props to spread on an anchor element for URL mode. */\n  anchorProps: Record<string, string> | undefined;\n}\n\nexport function useLinkAction(options: UseLinkActionOptions): LinkAction {\n  const {\n    linkType = \"url\",\n    href = \"\",\n    openInNewTab = true,\n    screenSlug,\n    shareSource,\n    shareResource,\n    shareUrl,\n  } = options;\n\n  const { onNavigate, buildHref, resolveInternalSlug } = useWidgetInteraction();\n  const repUser = useRepUser();\n  const publicId = repUser?.publicId;\n\n  // A URL-mode link may still point at a screen in this portal (e.g.\n  // \"/profile\"). Follow it in-app rather than as a document load, which would\n  // drop the in-session referrer and leave the destination with no back button.\n  // \"Open in new tab\" is the author's explicit choice and stays a real link.\n  const internalSlug = useMemo(() => {\n    if (linkType !== \"url\" || openInNewTab) return undefined;\n    return resolveInternalSlug?.(href);\n  }, [linkType, openInNewTab, href, resolveInternalSlug]);\n\n  const resolvedHref = useMemo(() => {\n    if (linkType === \"url\") {\n      // Keep the authored URL as the href so long-press/copy-link still work,\n      // but skip the rep public_id — that decorates outbound affiliate links,\n      // not our own routes.\n      if (internalSlug) return sanitizeHref(href.trim());\n      return decoratedHref(href, publicId);\n    }\n    if (linkType === \"screen\" && screenSlug)\n      return buildHref?.(screenSlug) ?? screenSlug;\n    return undefined;\n  }, [linkType, href, publicId, screenSlug, buildHref, internalSlug]);\n\n  const handleClick = useCallback(\n    (e: React.MouseEvent) => {\n      const navigationSlug = linkType === \"screen\" ? screenSlug : internalSlug;\n\n      // Cmd/Ctrl/Shift/Alt and middle clicks asked for a new tab or window —\n      // the anchor's href already points at the destination, so step aside.\n      if (navigationSlug && isBrowserHandledClick(e)) return;\n\n      if (navigationSlug && onNavigate) {\n        e.preventDefault();\n        onNavigate(navigationSlug);\n      } else if (linkType === \"share\") {\n        e.preventDefault();\n        void triggerShare({ shareSource, shareResource, shareUrl });\n      }\n    },\n    [\n      linkType,\n      onNavigate,\n      screenSlug,\n      internalSlug,\n      shareSource,\n      shareResource,\n      shareUrl,\n    ],\n  );\n\n  const hasTarget = useMemo(() => {\n    if (linkType === \"url\") {\n      return Boolean(internalSlug) || Boolean(decoratedHref(href, publicId));\n    }\n    if (linkType === \"screen\") return Boolean(screenSlug);\n    if (linkType === \"share\") {\n      const shareIsResource = shareSource === \"resource\" || shareSource == null;\n      return shareIsResource\n        ? Boolean(shareResource?.share_link)\n        : Boolean(shareUrl);\n    }\n    return false;\n  }, [\n    linkType,\n    href,\n    publicId,\n    screenSlug,\n    internalSlug,\n    shareSource,\n    shareResource,\n    shareUrl,\n  ]);\n\n  const anchorProps = useMemo(() => {\n    if (linkType === \"url\" && openInNewTab) {\n      return { target: \"_blank\", rel: \"noopener noreferrer\" };\n    }\n    return undefined;\n  }, [linkType, openInNewTab]);\n\n  return { resolvedHref, handleClick, hasTarget, anchorProps };\n}\n"],"mappings":";;;;;;AAkCA,SAAgB,cAAc,SAA2C;CACvE,MAAM,EACJ,WAAW,OACX,OAAO,IACP,eAAe,MACf,YACA,aACA,eACA,aACE;CAEJ,MAAM,EAAE,YAAY,WAAW,wBAAwB,sBAAsB;CAE7E,MAAM,WADU,YAAY,EACF;CAM1B,MAAM,eAAe,cAAc;AACjC,MAAI,aAAa,SAAS,aAAc,QAAO,KAAA;AAC/C,SAAO,sBAAsB,KAAK;IACjC;EAAC;EAAU;EAAc;EAAM;EAAoB,CAAC;AAwEvD,QAAO;EAAE,cAtEY,cAAc;AACjC,OAAI,aAAa,OAAO;AAItB,QAAI,aAAc,QAAO,aAAa,KAAK,MAAM,CAAC;AAClD,WAAO,cAAc,MAAM,SAAS;;AAEtC,OAAI,aAAa,YAAY,WAC3B,QAAO,YAAY,WAAW,IAAI;KAEnC;GAAC;GAAU;GAAM;GAAU;GAAY;GAAW;GAAa,CAAC;EA2D5C,aAzDH,aACjB,MAAwB;GACvB,MAAM,iBAAiB,aAAa,WAAW,aAAa;AAI5D,OAAI,kBAAkB,sBAAsB,EAAE,CAAE;AAEhD,OAAI,kBAAkB,YAAY;AAChC,MAAE,gBAAgB;AAClB,eAAW,eAAe;cACjB,aAAa,SAAS;AAC/B,MAAE,gBAAgB;AACb,iBAAa;KAAE;KAAa;KAAe;KAAU,CAAC;;KAG/D;GACE;GACA;GACA;GACA;GACA;GACA;GACA;GACD,CACF;EAgCmC,WA9BlB,cAAc;AAC9B,OAAI,aAAa,MACf,QAAO,QAAQ,aAAa,IAAI,QAAQ,cAAc,MAAM,SAAS,CAAC;AAExE,OAAI,aAAa,SAAU,QAAO,QAAQ,WAAW;AACrD,OAAI,aAAa,QAEf,QADwB,gBAAgB,cAAc,eAAe,OAEjE,QAAQ,eAAe,WAAW,GAClC,QAAQ,SAAS;AAEvB,UAAO;KACN;GACD;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACD,CAAC;EAS6C,aAP3B,cAAc;AAChC,OAAI,aAAa,SAAS,aACxB,QAAO;IAAE,QAAQ;IAAU,KAAK;IAAuB;KAGxD,CAAC,UAAU,aAAa,CAAC;EAEgC"}