Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/editors/slate/elements/link/index.tsx
1698 views
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { Text } from "slate";
7
8
import { CSS } from "@cocalc/frontend/app-framework";
9
import { useFileContext } from "@cocalc/frontend/lib/file-context";
10
import { dict } from "@cocalc/util/misc";
11
import { register, SlateElement } from "../register";
12
13
export const LINK_STYLE: CSS = {
14
backgroundColor: "white",
15
padding: "1px",
16
margin: "-1px", // so the position isn't changed; important when background is white so doesn't look weird.
17
borderRadius: "2px",
18
} as const;
19
20
export interface Link extends SlateElement {
21
type: "link";
22
isInline: true;
23
url?: string;
24
title?: string;
25
}
26
27
register({
28
slateType: "link",
29
30
StaticElement: ({ attributes, children, element }) => {
31
const node = element as Link;
32
let { url, title } = node;
33
const { AnchorTagComponent, urlTransform, anchorStyle } = useFileContext();
34
const style: CSS = { ...LINK_STYLE, ...anchorStyle };
35
if (AnchorTagComponent != null) {
36
return (
37
<AnchorTagComponent
38
{...attributes}
39
href={url}
40
title={title}
41
style={style}
42
>
43
{children}
44
</AnchorTagComponent>
45
);
46
}
47
let props;
48
if (url != null) {
49
const isExternal = url.includes("://");
50
props = {
51
href: urlTransform?.(url, "a") ?? url,
52
target: isExternal ? "_blank" : undefined,
53
rel: isExternal ? "noopener" : undefined,
54
};
55
}
56
return (
57
<a {...attributes} {...props} title={title} style={style}>
58
{children}
59
{isBlank(element) && <span contentEditable={false}>(blank link)</span>}
60
</a>
61
);
62
},
63
64
toSlate: ({ type, children, state }) => {
65
const attrs = dict(state.attrs as any);
66
return {
67
type,
68
children,
69
isInline: true,
70
url: attrs.href,
71
title: attrs.title,
72
};
73
},
74
});
75
76
function isBlank(element): boolean {
77
return (
78
element.children.length == 1 &&
79
Text.isText(element.children[0]) &&
80
!element.children[0].text.trim()
81
);
82
}
83
84