fix: implement external link handling with Tauri shell in UrlPreviewCard and react-custom-html-parser

This commit is contained in:
2026-01-25 00:40:38 +11:00
parent 92c3ec8082
commit 0cfc6cb0ab
2 changed files with 52 additions and 13 deletions

View File

@@ -1,6 +1,7 @@
/* eslint-disable jsx-a11y/alt-text */
import React, {
ComponentPropsWithoutRef,
MouseEvent,
ReactEventHandler,
Suspense,
lazy,
@@ -42,15 +43,28 @@ import { onEnterOrSpace } from '../utils/keyboard';
import { copyToClipboard, tryDecodeURIComponent } from '../utils/dom';
import { useTimeoutToggle } from '../hooks/useTimeoutToggle';
import { AuthenticatedImg } from '../components/authenticated-media';
import { openExternalUrl } from '../utils/tauri';
const ReactPrism = lazy(() => import('./react-prism/ReactPrism'));
const EMOJI_REG_G = new RegExp(`${URL_NEG_LB}(${EMOJI_PATTERN})`, 'g');
/**
* Click handler for external links - uses Tauri shell on desktop/mobile
*/
const handleExternalLinkClick = (e: MouseEvent<HTMLAnchorElement>) => {
const href = e.currentTarget.href;
if (href && (href.startsWith('http://') || href.startsWith('https://'))) {
e.preventDefault();
openExternalUrl(href);
}
};
export const LINKIFY_OPTS: LinkifyOpts = {
attributes: {
target: '_blank',
rel: 'noreferrer noopener',
onClick: handleExternalLinkClick,
},
validate: {
url: (value) => /^(https|http|ftp|mailto|magnet)?:/.test(value),
@@ -161,7 +175,7 @@ export const factoryRenderLinkifyWithMention = (
if (mention) return mention;
}
return <a {...attributes}>{content}</a>;
return <a {...attributes} onClick={handleExternalLinkClick}>{content}</a>;
};
return render;
};
@@ -441,19 +455,31 @@ export const getReactCustomHtmlParser = (
}
}
if (name === 'a' && testMatrixTo(tryDecodeURIComponent(props.href))) {
const content = children.find((child) => !(child instanceof DOMText))
? undefined
: children.map((c) => (c instanceof DOMText ? c.data : '')).join();
if (name === 'a') {
const href = tryDecodeURIComponent(props.href);
// Handle matrix.to links as mentions
if (testMatrixTo(href)) {
const content = children.find((child) => !(child instanceof DOMText))
? undefined
: children.map((c) => (c instanceof DOMText ? c.data : '')).join();
const mention = renderMatrixMention(
mx,
roomId,
tryDecodeURIComponent(props.href),
makeMentionCustomProps(params.handleMentionClick, content)
);
const mention = renderMatrixMention(
mx,
roomId,
href,
makeMentionCustomProps(params.handleMentionClick, content)
);
if (mention) return mention;
if (mention) return mention;
}
// Handle external links - add click handler for Tauri
if (props.href?.startsWith('http://') || props.href?.startsWith('https://')) {
return (
<a {...props} onClick={handleExternalLinkClick}>
{domToReact(children, opts)}
</a>
);
}
}
if (name === 'span' && 'data-mx-spoiler' in props) {