@docs.plus/extension-hyperlink 1.4.0 → 1.5.0

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.
package/README.md CHANGED
@@ -90,29 +90,25 @@ Hyperlink.configure({
90
90
  })
91
91
  ````
92
92
 
93
- ### DialogBoxs
93
+ ### Modals
94
94
 
95
- The DialogBox configuration option lets you incorporate an interactive user interface similar to Google Docs for **setting** and **previewing** hyperlinks. This provides users with a more intuitive and interactive experience;
95
+ The Modals configuration option lets you incorporate an interactive user interface similar to Google Docs for **setting** and **previewing** hyperlinks. This provides users with a more intuitive and interactive experience;
96
96
  - [Dive into the code](https://github.com/HMarzban/extension-hyperlink/blob/4f37ffa18237f10d76c316844b1c2ab20b751fe9/packages/nextjs/src/components/Tiptap.tsx#L21-L28)
97
97
  - [Demo](https://github.com/HMarzban/extension-hyperlink#test-drive-with-our-demo-)
98
98
 
99
99
  <details>
100
- <summary>The `previewHyperlinkDialogBox` function</summary>
100
+ <summary>The `previewHyperlinkModal` function</summary>
101
101
 
102
102
  ```ts
103
- type HyperlinkDialogBoxOptions = {
104
- editor: Editor;
105
- validate?: (url: string) => boolean;
106
- view: EditorView;
107
- link: HTMLAnchorElement;
108
- node?: any;
109
- nodePos: number;
110
- tippy: Tooltip;
111
- };
112
-
113
- const previewHyperlink(options: HyperlinkDialogBoxOptions): HTMLElement {
103
+ function previewHyperlinkModal(options) {
114
104
  const href = options.link.href;
115
- const hyperlinkLinkDialogBox = document.createElement("div");
105
+
106
+ const hyperlinkModal = document.createElement("div");
107
+ const removeButton = document.createElement("button");
108
+ const copyButton = document.createElement("button");
109
+
110
+ const newBubble = document.createElement("div");
111
+ newBubble.classList.add("hyperlink-preview-modal__metadata");
116
112
 
117
113
  const hrefTitle = document.createElement("a");
118
114
  hrefTitle.setAttribute("target", "_blank");
@@ -120,43 +116,60 @@ const previewHyperlink(options: HyperlinkDialogBoxOptions): HTMLElement {
120
116
  hrefTitle.setAttribute("href", href);
121
117
  hrefTitle.innerText = href;
122
118
 
123
- hyperlinkLinkDialogBox.append(hrefTitle);
119
+ newBubble.append(hrefTitle);
120
+
121
+ hyperlinkModal.classList.add("hyperlink-preview-modal");
122
+
123
+ removeButton.classList.add("hyperlink-preview-modal__remove-button");
124
+ removeButton.innerHTML = "remove";
125
+
126
+ copyButton.classList.add("hyperlink-preview-modal__copy-button");
127
+ copyButton.innerHTML = "copy";
128
+
129
+ removeButton.addEventListener("click", () => {
130
+ options.tippy.hide();
131
+ return options.editor.chain().focus().unsetHyperlink().run();
132
+ });
133
+
134
+ copyButton.addEventListener("click", () => {
135
+ options.tippy.hide();
136
+ navigator.clipboard.writeText(href);
137
+ });
138
+
139
+ hyperlinkModal.append(newBubble, copyButton, removeButton);
124
140
 
125
- return hyperlinkLinkDialogBox;
141
+ return hyperlinkModal;
126
142
  }
143
+
127
144
  ```
128
145
 
129
146
  </details>
130
147
 
131
148
  <details>
132
- <summary>The `setHyperlinks` function</summary>
149
+ <summary>The `setHyperlinkModal` function</summary>
133
150
 
134
151
  ```ts
135
- type setHyperlinkDialogOptions = {
136
- editor: Editor;
137
- validate?: (url: string) => boolean;
138
- extentionName: string;
139
- attributes: Record<string, any>;
140
- };
141
-
142
- let tooltip: Tooltip = undefined;
152
+ import { Editor } from "@tiptap/core";
153
+ import Tooltip, { TippyInitOptions } from "../helpers/tippyHelper";
154
+ import { find } from "linkifyjs";
143
155
 
144
156
 
145
- const setHyperlink(options: setHyperlinkDialogOptions): void {
157
+ let tooltip: Tooltip | undefined = undefined;
158
+ function setHyperlinkModal(options) {
146
159
  // Create the tooltip instance
147
- if (!tooltip) tooltip = new Tooltip({ ...options, view: options.editor.view });
160
+ if (!tooltip) tooltip = new options.Tooltip(options);
148
161
 
149
162
  // Initialize the tooltip
150
163
  let { tippyModal } = tooltip.init();
151
164
 
152
- const hyperlinkLinkDialog = document.createElement("div");
165
+ const hyperlinkModal = document.createElement("div");
153
166
  const buttonsWrapper = document.createElement("div");
154
167
  const inputsWrapper = document.createElement("div");
155
168
 
156
- hyperlinkLinkDialog.classList.add("hyperlinkLinkDialog");
169
+ hyperlinkModal.classList.add("hyperlink-set-modal");
157
170
 
158
- buttonsWrapper.classList.add("buttonsWrapper");
159
- inputsWrapper.classList.add("inputsWrapper");
171
+ buttonsWrapper.classList.add("hyperlink-set-modal__buttons-wrapper");
172
+ inputsWrapper.classList.add("hyperlink-set-modal__inputs-wrapper");
160
173
 
161
174
  // create a form that contain url input and a button for submit
162
175
  const form = document.createElement("form");
@@ -172,20 +185,41 @@ const setHyperlink(options: setHyperlinkDialogOptions): void {
172
185
  buttonsWrapper.append(button);
173
186
  form.append(inputsWrapper, buttonsWrapper);
174
187
 
175
- hyperlinkLinkDialog.append(form);
188
+ hyperlinkModal.append(form);
176
189
 
177
190
  tippyModal.innerHTML = "";
178
- tippyModal.append(hyperlinkLinkDialog);
191
+ tippyModal.append(hyperlinkModal);
192
+ tooltip.update(options.editor.view, {
193
+ arrow: options.roundArrow,
194
+ });
195
+
196
+ // make sure
197
+ setTimeout(() => input.focus();, 100);
179
198
 
180
- // event listenr for submit button
199
+ // event listenr for submit button
181
200
  form.addEventListener("submit", (event) => {
182
201
  event.preventDefault();
183
202
  const url = input.value;
184
- if (!url)return;
203
+
204
+ if (!url) return;
205
+
206
+ const sanitizeURL = find(url)
207
+ .filter((link) => link.isLink)
208
+ .filter((link) => {
209
+ if (options.validate) {
210
+ return options.validate(link.value);
211
+ }
212
+ return true;
213
+ })
214
+ .at(0);
215
+
216
+ if (!sanitizeURL?.href) return;
217
+
218
+ tooltip?.hide();
185
219
 
186
220
  return options.editor
187
221
  .chain()
188
- .setMark(options.extentionName, { href: url})
222
+ .setMark(options.extentionName, { href: sanitizeURL.href })
189
223
  .setMeta("preventautohyperlink", true)
190
224
  .run();
191
225
  });
@@ -197,22 +231,22 @@ const setHyperlink(options: setHyperlinkDialogOptions): void {
197
231
  ````ts
198
232
  import {
199
233
  Hyperlink,
200
- previewHyperlink,
201
- setHyperlink
234
+ previewHyperlinkModal,
235
+ setHyperlinkModal
202
236
  } from "@docs.plus/extension-hyperlink";
203
237
 
204
238
  Hyperlink.configure({
205
- dialogBoxs: {
239
+ modals: {
206
240
  previewHyperlink: (data) => {
207
- return previewHyperlink(data);
241
+ return previewHyperlinkModal(data);
208
242
  },
209
243
  setHyperlink: (data) => {
210
- return setHyperlink(data);
244
+ return setHyperlinkModal(data);
211
245
  },
212
246
  },
213
247
  })
214
248
  ````
215
- > Note: The `previewHyperlink` and `setHyperlink` dialogs are prebuilt dialog boxes. You can use them or create your own dialog boxes. To learn how to create your own dialog boxes, please check the [source code](https://github.com/HMarzban/extension-hyperlink/tree/main/packages/extension-hyperlink/src/dialogBoxs)
249
+ > Note: The `previewHyperlinkModal` and `setHyperlinkModal` modals are prebuilt modal boxes. You can use them or create your own modal boxes. To learn how to create your own modal boxes, please check the [source code](https://github.com/HMarzban/extension-hyperlink/tree/main/packages/extension-hyperlink/src/modals)
216
250
 
217
251
 
218
252
  ### Removing and overriding existing html attributes
@@ -1,13 +1,11 @@
1
1
  import { MarkType } from "@tiptap/pm/model";
2
2
  import { Plugin } from "@tiptap/pm/state";
3
3
  import { Editor } from "@tiptap/core";
4
- import { EditorView } from "@tiptap/pm/view";
5
4
  type ClickHandlerOptions = {
6
5
  type: MarkType;
7
6
  editor: Editor;
8
7
  validate?: (url: string) => boolean;
9
- view: EditorView;
10
- dialogBox?: ((options: any) => void | HTMLElement) | null;
8
+ modal?: ((options: any) => void | HTMLElement) | null;
11
9
  };
12
10
  export default function clickHandler(options: ClickHandlerOptions): Plugin;
13
11
  export {};
@@ -1,10 +1,9 @@
1
1
  import { Instance, Props } from "tippy.js";
2
2
  import { Editor } from "@tiptap/core";
3
3
  import { EditorView } from "@tiptap/pm/view";
4
- interface TippyInitOptions {
4
+ export interface TippyInitOptions {
5
5
  editor: Editor;
6
6
  validate?: (url: string) => boolean;
7
- view: EditorView;
8
7
  }
9
8
  declare class Tooltip {
10
9
  private tippyInstance?;
@@ -1,4 +1,6 @@
1
1
  import { Mark } from "@tiptap/core";
2
+ import { TSetHyperlinkModalOptions } from "./modals/setHyperlink";
3
+ import { THyperlinkPreviewModalOptions } from "./modals/previewHyperlink";
2
4
  export interface LinkProtocolOptions {
3
5
  scheme: string;
4
6
  optionalSlashes?: boolean;
@@ -25,13 +27,13 @@ export interface HyperlinkOptions {
25
27
  */
26
28
  HTMLAttributes: Record<string, any>;
27
29
  /**
28
- * A list of dialogBoxs to be rendered.
30
+ * A list of modals to be rendered.
29
31
  * @default null
30
32
  * @example
31
33
  */
32
- dialogBoxs: {
33
- previewHyperlink?: ((options: any) => void | HTMLElement) | null;
34
- setHyperlink?: ((options: any) => void | HTMLElement) | null;
34
+ modals: {
35
+ previewHyperlink?: ((options: THyperlinkPreviewModalOptions) => void | HTMLElement) | null;
36
+ setHyperlink?: ((options: TSetHyperlinkModalOptions) => void | HTMLElement) | null;
35
37
  };
36
38
  /**
37
39
  * A validation function that modifies link verification for the auto linker.
package/dist/index.cjs CHANGED
@@ -128,7 +128,7 @@ class Tooltip {
128
128
  this.blurHandler({ event });
129
129
  };
130
130
  this.editor = options.editor;
131
- this.view = options.view;
131
+ this.view = this.editor.view;
132
132
  this.tippyWrapper = document.createElement("div");
133
133
  this.tippyWrapper.addEventListener("mousedown", this.mousedownHandler, {
134
134
  capture: true,
@@ -227,8 +227,8 @@ function clickHandler(options) {
227
227
  // Extract href and target attributes from the link element or the state
228
228
  const href = (_a = link === null || link === void 0 ? void 0 : link.href) !== null && _a !== void 0 ? _a : attrs.href;
229
229
  const target = (_b = link === null || link === void 0 ? void 0 : link.target) !== null && _b !== void 0 ? _b : attrs.target;
230
- // If there is no previewHyperlink dialogBox provided, then open the link in new window
231
- if (!options.dialogBox) {
230
+ // If there is no previewHyperlink modal provided, then open the link in new window
231
+ if (!options.modal) {
232
232
  if (link && href) {
233
233
  window.open(href, target);
234
234
  }
@@ -238,22 +238,22 @@ function clickHandler(options) {
238
238
  if (!(link === null || link === void 0 ? void 0 : link.href))
239
239
  return tooltip.hide();
240
240
  // Create a preview of the hyperlink
241
- const hyperlinkPreview = options.dialogBox({
241
+ const hyperlinkPreview = options.modal({
242
242
  link,
243
243
  nodePos,
244
244
  tippy: tooltip,
245
245
  ...options,
246
246
  });
247
- // If there is no hyperlink preview, hide the dialogBox
247
+ // If there is no hyperlink preview, hide the modal
248
248
  if (!hyperlinkPreview)
249
249
  return tooltip.hide();
250
- // Empty the dialogBox and append the hyperlink preview box
250
+ // Empty the modal and append the hyperlink preview box
251
251
  while (tippyModal.firstChild) {
252
252
  tippyModal.removeChild(tippyModal.firstChild);
253
253
  }
254
254
  tippyModal.append(hyperlinkPreview);
255
- // Update the dialogBox position
256
- tooltip.update(options.view);
255
+ // Update the modal position
256
+ tooltip.update(options.editor.view);
257
257
  return false;
258
258
  },
259
259
  },
@@ -360,7 +360,7 @@ const Hyperlink = core.Mark.create({
360
360
  rel: "noopener noreferrer nofollow",
361
361
  class: null,
362
362
  },
363
- dialogBoxs: {
363
+ modals: {
364
364
  previewHyperlink: null,
365
365
  setHyperlink: null,
366
366
  },
@@ -389,18 +389,20 @@ const Hyperlink = core.Mark.create({
389
389
  addCommands() {
390
390
  return {
391
391
  setHyperlink: (attributes) => ({ editor, chain }) => {
392
- if (!this.options.dialogBoxs.setHyperlink) {
392
+ if (!this.options.modals.setHyperlink) {
393
393
  return chain()
394
394
  .setMark(this.name, attributes)
395
395
  .setMeta("preventAutohyperlink", true)
396
396
  .run();
397
397
  }
398
398
  else {
399
- this.options.dialogBoxs.setHyperlink({
399
+ this.options.modals.setHyperlink({
400
400
  editor,
401
401
  validate: this.options.validate,
402
402
  extentionName: this.name,
403
403
  attributes,
404
+ Tooltip,
405
+ roundArrow: tippy.roundArrow,
404
406
  });
405
407
  return true;
406
408
  }
@@ -473,8 +475,7 @@ const Hyperlink = core.Mark.create({
473
475
  type: this.type,
474
476
  editor: this.editor,
475
477
  validate: this.options.validate,
476
- view: this.editor.view,
477
- dialogBox: this.options.dialogBoxs.previewHyperlink,
478
+ modal: this.options.modals.previewHyperlink,
478
479
  }));
479
480
  }
480
481
  if (this.options.hyperlinkOnPaste) {
@@ -487,7 +488,7 @@ const Hyperlink = core.Mark.create({
487
488
  },
488
489
  });
489
490
 
490
- const editeHyperlinkHandler = (options) => {
491
+ const editHyperlinkHandler = (options) => {
491
492
  var _a;
492
493
  // Create the form
493
494
  const form = document.createElement("form");
@@ -496,8 +497,8 @@ const editeHyperlinkHandler = (options) => {
496
497
  const linkTextInput = document.createElement("input");
497
498
  const hrefInput = document.createElement("input");
498
499
  const applyButton = document.createElement("button");
499
- buttonsWrapper.classList.add("buttonsWrapper");
500
- inputsWrapper.classList.add("inputsWrapper");
500
+ buttonsWrapper.classList.add("hyperlink-edit-modal__buttons-wrapper");
501
+ inputsWrapper.classList.add("hyperlink-edit-modal__inputs-wrapper");
501
502
  linkTextInput.type = "text";
502
503
  linkTextInput.value = ((_a = options.link) === null || _a === void 0 ? void 0 : _a.innerText) || "";
503
504
  linkTextInput.placeholder = "Enter link text";
@@ -505,14 +506,14 @@ const editeHyperlinkHandler = (options) => {
505
506
  hrefInput.value = options.link.href;
506
507
  hrefInput.placeholder = "Enter href";
507
508
  applyButton.type = "submit";
508
- applyButton.classList.add("btn_applyModal");
509
+ applyButton.classList.add("hyperlink-edit-modal__apply-button");
509
510
  applyButton.innerText = "Apply";
510
511
  buttonsWrapper.append(applyButton);
511
512
  inputsWrapper.append(linkTextInput, hrefInput);
512
513
  // Append to form
513
514
  form.append(inputsWrapper, buttonsWrapper);
514
- options.hyperlinkLinkModal.innerHTML = "";
515
- options.hyperlinkLinkModal.appendChild(form);
515
+ options.hyperlinkModal.innerHTML = "";
516
+ options.hyperlinkModal.appendChild(form);
516
517
  hrefInput.addEventListener("keydown", () => {
517
518
  hrefInput.style.outlineColor = " #dadce0";
518
519
  });
@@ -551,7 +552,7 @@ const editeHyperlinkHandler = (options) => {
551
552
  options.tippy.hide();
552
553
  });
553
554
  // Show tooltip
554
- options.tippy.update(options.view, {
555
+ options.tippy.update(options.editor.view, {
555
556
  arrow: tippy.roundArrow,
556
557
  });
557
558
  setTimeout(() => linkTextInput.focus());
@@ -580,14 +581,14 @@ const Pencil = ({ size = 24, fill = "rgb(104, 81, 255)", } = {}) => {
580
581
  `;
581
582
  };
582
583
 
583
- function previewHyperlink(options) {
584
+ function previewHyperlinkModal(options) {
584
585
  const href = options.link.href;
585
- const hyperlinkLinkModal = document.createElement("div");
586
+ const hyperlinkModal = document.createElement("div");
586
587
  const removeButton = document.createElement("button");
587
588
  const copyButton = document.createElement("button");
588
589
  const editButton = document.createElement("button");
589
590
  const newBubble = document.createElement("div");
590
- newBubble.classList.add("metadata");
591
+ newBubble.classList.add("hyperlink-preview-modal__metadata");
591
592
  const hrefTitle = document.createElement("a");
592
593
  hrefTitle.setAttribute("target", "_blank");
593
594
  hrefTitle.setAttribute("rel", "noreferrer");
@@ -616,39 +617,39 @@ function previewHyperlink(options) {
616
617
  .catch((error) => {
617
618
  console.error("Error fetching metadata:", error);
618
619
  });
619
- hyperlinkLinkModal.classList.add("hyperlinkLinkModal");
620
- removeButton.classList.add("remove");
620
+ hyperlinkModal.classList.add("hyperlink-preview-modal");
621
+ removeButton.classList.add("hyperlink-preview-modal__remove-button");
621
622
  removeButton.innerHTML = LinkSlash();
622
- editButton.classList.add("edit");
623
+ editButton.classList.add("hyperlink-preview-modal__edit-button");
623
624
  editButton.innerHTML = Pencil();
624
- copyButton.classList.add("copy");
625
+ copyButton.classList.add("hyperlink-preview-modal__copy-button");
625
626
  copyButton.innerHTML = Copy();
626
627
  removeButton.addEventListener("click", () => {
627
628
  options.tippy.hide();
628
629
  return options.editor.chain().focus().unsetHyperlink().run();
629
630
  });
630
- editButton.addEventListener("click", () => editeHyperlinkHandler({ ...options, hyperlinkLinkModal }));
631
+ editButton.addEventListener("click", () => editHyperlinkHandler({ ...options, hyperlinkModal }));
631
632
  copyButton.addEventListener("click", () => {
632
633
  options.tippy.hide();
633
634
  navigator.clipboard.writeText(href);
634
635
  });
635
- hyperlinkLinkModal.append(newBubble, copyButton, editButton, removeButton);
636
- return hyperlinkLinkModal;
636
+ hyperlinkModal.append(newBubble, copyButton, editButton, removeButton);
637
+ return hyperlinkModal;
637
638
  }
638
639
 
639
640
  let tooltip = undefined;
640
- function setHyperlink(options) {
641
+ function setHyperlinkModal(options) {
641
642
  // Create the tooltip instance
642
643
  if (!tooltip)
643
- tooltip = new Tooltip({ ...options, view: options.editor.view });
644
+ tooltip = new options.Tooltip(options);
644
645
  // Initialize the tooltip
645
646
  let { tippyModal } = tooltip.init();
646
- const hyperlinkLinkModal = document.createElement("div");
647
+ const hyperlinkModal = document.createElement("div");
647
648
  const buttonsWrapper = document.createElement("div");
648
649
  const inputsWrapper = document.createElement("div");
649
- hyperlinkLinkModal.classList.add("hyperlinkLinkModal");
650
- buttonsWrapper.classList.add("buttonsWrapper");
651
- inputsWrapper.classList.add("inputsWrapper");
650
+ hyperlinkModal.classList.add("hyperlink-set-modal");
651
+ buttonsWrapper.classList.add("hyperlink-set-modal__buttons-wrapper");
652
+ inputsWrapper.classList.add("hyperlink-set-modal__inputs-wrapper");
652
653
  // create a form that contain url input and a button for submit
653
654
  const form = document.createElement("form");
654
655
  const input = document.createElement("input");
@@ -660,11 +661,11 @@ function setHyperlink(options) {
660
661
  inputsWrapper.append(input);
661
662
  buttonsWrapper.append(button);
662
663
  form.append(inputsWrapper, buttonsWrapper);
663
- hyperlinkLinkModal.append(form);
664
+ hyperlinkModal.append(form);
664
665
  tippyModal.innerHTML = "";
665
- tippyModal.append(hyperlinkLinkModal);
666
+ tippyModal.append(hyperlinkModal);
666
667
  tooltip.update(options.editor.view, {
667
- arrow: tippy.roundArrow,
668
+ arrow: options.roundArrow,
668
669
  });
669
670
  // make sure
670
671
  setTimeout(() => {
@@ -706,6 +707,6 @@ function setHyperlink(options) {
706
707
 
707
708
  exports.Hyperlink = Hyperlink;
708
709
  exports.Tooltip = Tooltip;
709
- exports.previewHyperlink = previewHyperlink;
710
- exports.setHyperlink = setHyperlink;
710
+ exports.previewHyperlinkModal = previewHyperlinkModal;
711
+ exports.setHyperlinkModal = setHyperlinkModal;
711
712
  //# sourceMappingURL=index.cjs.map