Skip to content

Commit d2d2bab

Browse files
committed
Implements linkTarget prop to define link behavior
1 parent eb6053f commit d2d2bab

File tree

4 files changed

+57
-7
lines changed

4 files changed

+57
-7
lines changed

src/block.tsx

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import {
33
DecorationType,
44
BlockType,
55
ContentValueType,
6-
BlockMapType
6+
BlockMapType,
7+
LinkTargetType
78
} from "./types";
89
import Asset from "./components/asset";
910
import Code from "./components/code";
@@ -12,10 +13,17 @@ import {
1213
classNames,
1314
getTextContent,
1415
getListNumber,
15-
toNotionImageUrl
16+
toNotionImageUrl,
17+
getLinkTargetProps
1618
} from "./utils";
1719

18-
export const renderChildText = (properties: DecorationType[]) => {
20+
interface createRenderChildText {
21+
linkTarget?: LinkTargetType;
22+
}
23+
24+
export const createRenderChildText = (options?: createRenderChildText) => (
25+
properties: DecorationType[]
26+
) => {
1927
return properties?.map(([text, decorations], i) => {
2028
if (!decorations) {
2129
return <React.Fragment key={i}>{text}</React.Fragment>;
@@ -43,7 +51,13 @@ export const renderChildText = (properties: DecorationType[]) => {
4351
return <s key={i}>{element}</s>;
4452
case "a":
4553
return (
46-
<a className="notion-link" href={decorator[1]} key={i}>
54+
<a
55+
className="notion-link"
56+
href={decorator[1]}
57+
key={i}
58+
rel="noopener noreferrer"
59+
{...getLinkTargetProps(decorator[1], options?.linkTarget)}
60+
>
4761
{element}
4862
</a>
4963
);
@@ -61,14 +75,17 @@ interface Block {
6175
block: BlockType;
6276
level: number;
6377
blockMap: BlockMapType;
78+
linkTarget?: LinkTargetType;
6479

6580
fullPage?: boolean;
6681
mapPageUrl?: MapPageUrl;
6782
}
6883

6984
export const Block: React.FC<Block> = props => {
70-
const { block, children, level, fullPage, blockMap } = props;
85+
const { block, children, level, fullPage, blockMap, linkTarget } = props;
7186
const blockValue = block?.value;
87+
const renderChildText = createRenderChildText({ linkTarget });
88+
7289
switch (blockValue?.type) {
7390
case "page":
7491
if (level === 0) {

src/renderer.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import React from "react";
2-
import { BlockMapType } from "./types";
2+
import { BlockMapType, LinkTargetType } from "./types";
33
import { Block, MapPageUrl } from "./block";
44

55
export interface NotionRendererProps {
66
blockMap: BlockMapType;
77
mapPageUrl?: MapPageUrl;
88
fullPage?: boolean;
9+
linkTarget?: LinkTargetType;
910

1011
currentId?: string;
1112
level?: number;

src/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,10 @@ export interface LoadPageChunkData {
284284
stack: any[];
285285
};
286286
}
287+
288+
export type LinkTargetType =
289+
| "_self"
290+
| "_blank"
291+
| {
292+
host: string;
293+
};

src/utils.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DecorationType, BlockMapType } from "./types";
1+
import { DecorationType, BlockMapType, LinkTargetType } from "./types";
22

33
export const classNames = (...classes: Array<string | undefined | false>) =>
44
classes.filter(a => !!a).join(" ");
@@ -48,3 +48,28 @@ export const toNotionImageUrl = (url: string) => {
4848
url.startsWith("/image") ? url : `/image/${encodeURIComponent(url)}`
4949
}`;
5050
};
51+
52+
export const getLinkTargetProps = (
53+
link: string,
54+
linkTarget: LinkTargetType = "_self"
55+
) => {
56+
const targetBlank = {
57+
target: "_blank"
58+
};
59+
60+
if (linkTarget === "_blank") {
61+
return targetBlank;
62+
}
63+
64+
if (linkTarget === "_self" || !linkTarget.host) {
65+
return;
66+
}
67+
68+
const parsedLink = new URL(link);
69+
70+
if (linkTarget.host !== parsedLink.host) {
71+
return targetBlank;
72+
}
73+
74+
return;
75+
};

0 commit comments

Comments
 (0)