@docs.plus/extension-hyperlink 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,272 @@
1
+ import { Mark, markPasteRule, mergeAttributes } from "@tiptap/core";
2
+ import { Plugin } from "@tiptap/pm/state";
3
+ import { find, registerCustomProtocol, reset } from "linkifyjs";
4
+ import autoHyperlink from "./helpers/autoHyperlink";
5
+ import clickHandler from "./helpers/clickHandler";
6
+ import { pasteHandler } from "./helpers/pasteHandler";
7
+ import editHyperlinkHelper from "./helpers/editHyperlink";
8
+
9
+ export interface LinkProtocolOptions {
10
+ scheme: string;
11
+ optionalSlashes?: boolean;
12
+ }
13
+
14
+ export interface HyperlinkOptions {
15
+ /**
16
+ * If enabled, it adds links as you type.
17
+ */
18
+ autoHyperlink: boolean;
19
+ /**
20
+ * An array of custom protocols to be registered with linkifyjs.
21
+ */
22
+ protocols: Array<LinkProtocolOptions | string>;
23
+ /**
24
+ * If enabled, links will be opened on click.
25
+ */
26
+ openOnClick: boolean;
27
+ /**
28
+ * Adds a link to the current selection if the pasted content only contains an url.
29
+ */
30
+ hyperlinkOnPaste: boolean;
31
+ /**
32
+ * A list of HTML attributes to be rendered.
33
+ */
34
+ HTMLAttributes: Record<string, any>;
35
+ /**
36
+ * A list of modals to be rendered.
37
+ * @default null
38
+ * @example
39
+ */
40
+ modals: {
41
+ previewHyperlink?: ((options: any) => HTMLElement) | null;
42
+ setHyperlink?: ((options: any) => HTMLElement) | null;
43
+ };
44
+ /**
45
+ * A validation function that modifies link verification for the auto linker.
46
+ * @param url - The url to be validated.
47
+ * @returns - True if the url is valid, false otherwise.
48
+ */
49
+ validate?: (url: string) => boolean;
50
+ }
51
+
52
+ declare module "@tiptap/core" {
53
+ interface Commands<ReturnType> {
54
+ link: {
55
+ /**
56
+ * Edit the hyperlink's text
57
+ */
58
+ editHyperLinkText: (text: string) => ReturnType;
59
+
60
+ /**
61
+ * Edit the hyperlink's href value
62
+ */
63
+ editHyperLinkHref: (href: string) => ReturnType;
64
+
65
+ /**
66
+ * Edit the hyperlink's
67
+ */
68
+ editHyperlink: (attributes?: { newText?: string; newURL?: string }) => ReturnType;
69
+
70
+ /**
71
+ * Set a hyperlink
72
+ */
73
+ setHyperlink: (attributes?: { href: string; target?: string | null }) => ReturnType;
74
+
75
+ /**
76
+ * Unset a link mark
77
+ */
78
+ unsetHyperlink: () => ReturnType;
79
+ };
80
+ }
81
+ }
82
+
83
+ export const Hyperlink = Mark.create<HyperlinkOptions>({
84
+ name: "hyperlink",
85
+
86
+ priority: 1000,
87
+
88
+ keepOnSplit: false,
89
+
90
+ onCreate() {
91
+ this.options.protocols.forEach((protocol) => {
92
+ if (typeof protocol === "string") {
93
+ registerCustomProtocol(protocol);
94
+ return;
95
+ }
96
+ registerCustomProtocol(protocol.scheme, protocol.optionalSlashes);
97
+ });
98
+ },
99
+
100
+ onDestroy() {
101
+ reset();
102
+ },
103
+
104
+ inclusive() {
105
+ return this.options.autoHyperlink;
106
+ },
107
+
108
+ addOptions() {
109
+ return {
110
+ openOnClick: true,
111
+ hyperlinkOnPaste: true,
112
+ autoHyperlink: true,
113
+ protocols: [],
114
+ HTMLAttributes: {
115
+ target: "_blank",
116
+ rel: "noopener noreferrer nofollow",
117
+ class: null,
118
+ },
119
+ modals: {
120
+ previewHyperlink: null,
121
+ setHyperlink: null,
122
+ },
123
+ validate: undefined,
124
+ };
125
+ },
126
+
127
+ addAttributes() {
128
+ return {
129
+ href: {
130
+ default: null,
131
+ },
132
+ target: {
133
+ default: this.options.HTMLAttributes.target,
134
+ },
135
+ class: {
136
+ default: this.options.HTMLAttributes.class,
137
+ },
138
+ };
139
+ },
140
+
141
+ parseHTML() {
142
+ return [{ tag: 'a[href]:not([href *= "javascript:" i])' }];
143
+ },
144
+
145
+ renderHTML({ HTMLAttributes }) {
146
+ return ["a", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
147
+ },
148
+
149
+ addCommands() {
150
+ return {
151
+ setHyperlink:
152
+ (attributes) =>
153
+ ({ editor, chain }) => {
154
+ if (!this.options.modals.setHyperlink) {
155
+ return chain()
156
+ .setMark(this.name, attributes)
157
+ .setMeta("preventAutohyperlink", true)
158
+ .run();
159
+ } else {
160
+ this.options.modals.setHyperlink({
161
+ editor,
162
+ validate: this.options.validate,
163
+ extentionName: this.name,
164
+ attributes,
165
+ });
166
+ return true;
167
+ }
168
+ },
169
+
170
+ editHyperlink:
171
+ (attributes) =>
172
+ ({ editor }) => {
173
+ return editHyperlinkHelper({
174
+ ...attributes,
175
+ editor,
176
+ validate: this.options.validate,
177
+ });
178
+ },
179
+
180
+ editHyperLinkText:
181
+ (newText) =>
182
+ ({ editor }) => {
183
+ return editHyperlinkHelper({
184
+ editor,
185
+ newText,
186
+ validate: this.options.validate,
187
+ });
188
+ },
189
+
190
+ editHyperLinkHref:
191
+ (newURL) =>
192
+ ({ editor }) => {
193
+ return editHyperlinkHelper({
194
+ editor,
195
+ validate: this.options.validate,
196
+ newURL,
197
+ });
198
+ },
199
+
200
+ unsetHyperlink:
201
+ () =>
202
+ ({ chain }) => {
203
+ return chain()
204
+ .unsetMark(this.name, { extendEmptyMarkRange: true })
205
+ .setMeta("preventAutohyperlink", true)
206
+ .run();
207
+ },
208
+ };
209
+ },
210
+
211
+ addPasteRules() {
212
+ return [
213
+ markPasteRule({
214
+ find: (text) =>
215
+ find(text)
216
+ .filter((link) => {
217
+ if (this.options.validate) {
218
+ return this.options.validate(link.value);
219
+ }
220
+
221
+ return true;
222
+ })
223
+ .filter((link) => link.isLink)
224
+ .map((link) => ({
225
+ text: link.value,
226
+ index: link.start,
227
+ data: link,
228
+ })),
229
+ type: this.type,
230
+ getAttributes: (match) => ({
231
+ href: match.data?.href,
232
+ }),
233
+ }),
234
+ ];
235
+ },
236
+
237
+ addProseMirrorPlugins() {
238
+ const plugins: Plugin[] = [];
239
+
240
+ if (this.options.autoHyperlink) {
241
+ plugins.push(
242
+ autoHyperlink({
243
+ type: this.type,
244
+ validate: this.options.validate,
245
+ })
246
+ );
247
+ }
248
+
249
+ if (this.options.openOnClick) {
250
+ plugins.push(
251
+ clickHandler({
252
+ type: this.type,
253
+ editor: this.editor,
254
+ validate: this.options.validate,
255
+ view: this.editor.view,
256
+ modals: this.options.modals,
257
+ })
258
+ );
259
+ }
260
+
261
+ if (this.options.hyperlinkOnPaste) {
262
+ plugins.push(
263
+ pasteHandler({
264
+ editor: this.editor,
265
+ type: this.type,
266
+ })
267
+ );
268
+ }
269
+
270
+ return plugins;
271
+ },
272
+ });
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ import { Hyperlink } from "./hyperlink";
2
+
3
+ export * as tippy from "./helpers/tippyHelper";
4
+ export * from "./hyperlink";
5
+
6
+ export default Hyperlink;