Skip to content

Commit db7288b

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

File tree

6 files changed

+84
-8
lines changed

6 files changed

+84
-8
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"@types/prismjs": "^1.16.0",
5050
"@types/react": "^16.9.34",
5151
"@types/react-dom": "^16.9.6",
52+
"@types/url-parse": "^1.4.3",
5253
"husky": "^4.2.5",
5354
"react": "^16.13.1",
5455
"react-dom": "^16.13.1",
@@ -58,6 +59,7 @@
5859
"typescript": "^3.8.3"
5960
},
6061
"dependencies": {
61-
"prismjs": "^1.20.0"
62+
"prismjs": "^1.20.0",
63+
"url-parse": "^1.4.7"
6264
}
6365
}

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: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { DecorationType, BlockMapType } from "./types";
1+
import parse from "url-parse";
2+
import { DecorationType, BlockMapType, LinkTargetType } from "./types";
23

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

yarn.lock

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,11 @@
11721172
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
11731173
integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==
11741174

1175+
"@types/url-parse@^1.4.3":
1176+
version "1.4.3"
1177+
resolved "https://registry.yarnpkg.com/@types/url-parse/-/url-parse-1.4.3.tgz#fba49d90f834951cb000a674efee3d6f20968329"
1178+
integrity sha512-4kHAkbV/OfW2kb5BLVUuUMoumB3CP8rHqlw48aHvFy5tf9ER0AfOonBlX29l/DD68G70DmyhRlSYfQPSYpC5Vw==
1179+
11751180
"@types/yargs-parser@*":
11761181
version "15.0.0"
11771182
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
@@ -4794,6 +4799,11 @@ qs@~6.5.2:
47944799
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
47954800
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
47964801

4802+
querystringify@^2.1.1:
4803+
version "2.1.1"
4804+
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e"
4805+
integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==
4806+
47974807
react-dom@^16.13.1:
47984808
version "16.13.1"
47994809
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f"
@@ -5013,6 +5023,11 @@ require-main-filename@^2.0.0:
50135023
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
50145024
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
50155025

5026+
requires-port@^1.0.0:
5027+
version "1.0.0"
5028+
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
5029+
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
5030+
50165031
resolve-cwd@^2.0.0:
50175032
version "2.0.0"
50185033
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
@@ -6000,6 +6015,14 @@ urix@^0.1.0:
60006015
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
60016016
integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
60026017

6018+
url-parse@^1.4.7:
6019+
version "1.4.7"
6020+
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278"
6021+
integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==
6022+
dependencies:
6023+
querystringify "^2.1.1"
6024+
requires-port "^1.0.0"
6025+
60036026
use@^3.1.0:
60046027
version "3.1.1"
60056028
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"

0 commit comments

Comments
 (0)