Files
usememos--memos/web/src/components/MemoContent/markdown/Paragraph.tsx
T
wehub-resource-sync 4cddfcf2f3
Backend Tests / Tests (other) (push) Failing after 1s
Backend Tests / Static Checks (push) Failing after 2s
Backend Tests / Tests (internal) (push) Failing after 2s
Backend Tests / Tests (server) (push) Failing after 1s
Backend Tests / Tests (store) (push) Failing after 1s
Build Canary Image / build-frontend (push) Failing after 1s
Frontend Tests / Lint (push) Failing after 1s
Build Canary Image / build-push (linux/amd64) (push) Has been skipped
Build Canary Image / build-push (linux/arm64) (push) Has been skipped
Build Canary Image / merge (push) Has been skipped
Frontend Tests / Build (push) Failing after 1s
Release Please / release-please (push) Failing after 0s
Proto Linter / Lint Protos (push) Failing after 2s
chore: import upstream snapshot with attribution
2026-07-13 12:02:24 +08:00

64 lines
1.9 KiB
TypeScript

import type { Element } from "hast";
import { useLinkPreviewEnabled } from "@/contexts/ViewContext";
import { markdownStyles } from "@/lib/markdownStyles";
import { cn } from "@/lib/utils";
import LinkMetadataCard from "../LinkMetadataCard";
import { useMarkdownRenderContext } from "../MarkdownRenderContext";
import type { ReactMarkdownProps } from "./types";
interface ParagraphProps extends React.HTMLAttributes<HTMLParagraphElement>, ReactMarkdownProps {
children: React.ReactNode;
}
export function getSingleLinkHref(node?: Element): string | undefined {
if (!node || node.tagName !== "p") {
return undefined;
}
const meaningfulChildren = node.children.filter((child) => {
return !(child.type === "text" && child.value.trim() === "");
});
if (meaningfulChildren.length !== 1) {
return undefined;
}
const onlyChild = meaningfulChildren[0];
if (onlyChild.type !== "element" || onlyChild.tagName !== "a") {
return undefined;
}
const href = onlyChild.properties?.href;
if (typeof href !== "string") {
return undefined;
}
const meaningfulLinkChildren = onlyChild.children.filter((child) => {
return !(child.type === "text" && child.value.trim() === "");
});
if (meaningfulLinkChildren.length !== 1) {
return undefined;
}
const onlyLinkChild = meaningfulLinkChildren[0];
return onlyLinkChild.type === "text" && onlyLinkChild.value === href ? href : undefined;
}
export const Paragraph = ({ children, className, node, ...props }: ParagraphProps) => {
const { blockDepth } = useMarkdownRenderContext();
const linkPreviewEnabled = useLinkPreviewEnabled();
const href = blockDepth === 0 && linkPreviewEnabled ? getSingleLinkHref(node) : undefined;
const paragraph = (
<p className={cn(markdownStyles.paragraph, className)} {...props}>
{children}
</p>
);
if (href) {
return <LinkMetadataCard url={href} fallback={paragraph} />;
}
return paragraph;
};