@lobehub/editor 1.19.0 → 1.20.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.
Files changed (52) hide show
  1. package/es/index.d.ts +2 -0
  2. package/es/index.js +4 -0
  3. package/es/plugins/code/node/code.d.ts +1 -1
  4. package/es/plugins/code/node/code.js +1 -1
  5. package/es/plugins/code/react/CodeReactPlugin.js +1 -1
  6. package/es/plugins/codeblock/plugin/index.js +1 -1
  7. package/es/plugins/codeblock/react/ReactCodeblockPlugin.js +1 -1
  8. package/es/plugins/common/plugin/index.js +2 -1
  9. package/es/plugins/common/plugin/mdReader.d.ts +1 -1
  10. package/es/plugins/common/react/ReactPlainText.js +1 -1
  11. package/es/plugins/file/plugin/index.js +1 -1
  12. package/es/plugins/hr/plugin/index.js +1 -1
  13. package/es/plugins/hr/react/ReactHRPlugin.js +1 -1
  14. package/es/plugins/link/plugin/index.js +1 -1
  15. package/es/plugins/link/react/ReactLinkPlugin.js +1 -1
  16. package/es/plugins/link-highlight/command/index.d.ts +3 -0
  17. package/es/plugins/link-highlight/command/index.js +46 -0
  18. package/es/plugins/link-highlight/index.d.ts +4 -0
  19. package/es/plugins/link-highlight/index.js +5 -0
  20. package/es/plugins/link-highlight/node/link-highlight.d.ts +29 -0
  21. package/es/plugins/link-highlight/node/link-highlight.js +223 -0
  22. package/es/plugins/link-highlight/plugin/index.d.ts +15 -0
  23. package/es/plugins/link-highlight/plugin/index.js +187 -0
  24. package/es/plugins/link-highlight/plugin/registry.d.ts +6 -0
  25. package/es/plugins/link-highlight/plugin/registry.js +61 -0
  26. package/es/plugins/link-highlight/react/ReactLinkHighlightPlugin.d.ts +4 -0
  27. package/es/plugins/link-highlight/react/ReactLinkHighlightPlugin.js +35 -0
  28. package/es/plugins/link-highlight/react/index.d.ts +1 -0
  29. package/es/plugins/link-highlight/react/index.js +1 -0
  30. package/es/plugins/link-highlight/react/style.d.ts +3 -0
  31. package/es/plugins/link-highlight/react/style.js +10 -0
  32. package/es/plugins/link-highlight/react/type.d.ts +13 -0
  33. package/es/plugins/link-highlight/react/type.js +1 -0
  34. package/es/plugins/link-highlight/utils/index.d.ts +17 -0
  35. package/es/plugins/link-highlight/utils/index.js +43 -0
  36. package/es/plugins/list/plugin/index.js +1 -1
  37. package/es/plugins/list/react/ReactListPlugin.js +1 -1
  38. package/es/plugins/markdown/index.d.ts +1 -0
  39. package/es/plugins/markdown/index.js +2 -1
  40. package/es/plugins/markdown/plugin/index.js +57 -3
  41. package/es/plugins/markdown/utils/url-validator.d.ts +4 -0
  42. package/es/plugins/markdown/utils/url-validator.js +6 -0
  43. package/es/plugins/math/plugin/index.js +1 -1
  44. package/es/plugins/math/react/index.js +1 -1
  45. package/es/plugins/mention/plugin/index.js +1 -1
  46. package/es/plugins/mention/react/ReactMentionPlugin.js +1 -1
  47. package/es/plugins/table/plugin/index.js +1 -1
  48. package/es/react/Editor/Editor.js +1 -1
  49. package/es/react/hooks/useEditorState/index.js +46 -6
  50. package/es/utils/url.d.ts +15 -0
  51. package/es/utils/url.js +51 -0
  52. package/package.json +1 -1
@@ -15,6 +15,8 @@ import { INSERT_CODEINLINE_COMMAND } from "../../../plugins/code";
15
15
  import { $isSelectionInCodeInline } from "../../../plugins/code/node/code";
16
16
  import { UPDATE_CODEBLOCK_LANG } from "../../../plugins/codeblock";
17
17
  import { $isRootTextContentEmpty } from "../../../plugins/common/utils";
18
+ import { INSERT_LINK_HIGHLIGHT_COMMAND } from "../../../plugins/link-highlight/command";
19
+ import { $isLinkHighlightNode } from "../../../plugins/link-highlight/node/link-highlight";
18
20
  import { $isLinkNode, TOGGLE_LINK_COMMAND, formatUrl } from "../../../plugins/link/node/LinkNode";
19
21
  import { extractUrlFromText, sanitizeUrl, validateUrl } from "../../../plugins/link/utils";
20
22
  import { INSERT_CHECK_LIST_COMMAND } from "../../../plugins/list";
@@ -124,7 +126,8 @@ export function useEditorState(editor) {
124
126
  var elementDOM = editor === null || editor === void 0 || (_editor$getLexicalEdi = editor.getLexicalEditor()) === null || _editor$getLexicalEdi === void 0 ? void 0 : _editor$getLexicalEdi.getElementByKey(elementKey);
125
127
  var node = getSelectedNode(selection);
126
128
  var parent = node.getParent();
127
- setIsLink($isLinkNode(parent) || $isLinkNode(node));
129
+ // Check for both Link and LinkHighlight nodes
130
+ setIsLink($isLinkNode(parent) || $isLinkNode(node) || $isLinkHighlightNode(parent) || $isLinkHighlightNode(node));
128
131
  var isCodeBlock = $isCodeNode(element) && $isCodeNode(focusElement) && elementKey === focusElement.getKey();
129
132
  setIsInCodeblok(isCodeBlock);
130
133
  setCodeblockLang(isCodeBlock ? element.getLanguage() : '');
@@ -258,7 +261,49 @@ export function useEditorState(editor) {
258
261
  var insertLink = useCallback(function () {
259
262
  var lexical = editor === null || editor === void 0 ? void 0 : editor.getLexicalEditor();
260
263
  if (!lexical) return;
264
+
265
+ // Detect which link type we're currently in
266
+ var inLinkNode = false;
267
+ var inLinkHighlightNode = false;
268
+ lexical.getEditorState().read(function () {
269
+ var selection = $getSelection();
270
+ if ($isRangeSelection(selection)) {
271
+ var node = getSelectedNode(selection);
272
+ var parent = node.getParent();
273
+ if ($isLinkNode(parent) || $isLinkNode(node)) {
274
+ inLinkNode = true;
275
+ }
276
+ if ($isLinkHighlightNode(parent) || $isLinkHighlightNode(node)) {
277
+ inLinkHighlightNode = true;
278
+ }
279
+ }
280
+ });
281
+
282
+ // If inside LinkHighlightNode, toggle it
283
+ if (inLinkHighlightNode) {
284
+ lexical.dispatchCommand(INSERT_LINK_HIGHLIGHT_COMMAND, undefined);
285
+ setIsLink(false);
286
+ return;
287
+ }
288
+
289
+ // If inside LinkNode, toggle it with standard Link plugin
290
+ if (inLinkNode) {
291
+ setIsLink(false);
292
+ lexical.dispatchCommand(TOGGLE_LINK_COMMAND, null);
293
+ return;
294
+ }
295
+
296
+ // Not in any link - try to insert new link
297
+ // Try LinkHighlight first, then fall back to standard Link if not handled
261
298
  if (!isLink) {
299
+ // First try INSERT_LINK_HIGHLIGHT_COMMAND
300
+ var linkHighlightHandled = lexical.dispatchCommand(INSERT_LINK_HIGHLIGHT_COMMAND, undefined);
301
+ if (linkHighlightHandled) {
302
+ setIsLink(true);
303
+ return;
304
+ }
305
+
306
+ // Fall back to standard Link plugin
262
307
  var nextUrl = sanitizeUrl('https://');
263
308
  var expandTo = null;
264
309
  lexical.getEditorState().read(function () {
@@ -283,7 +328,6 @@ export function useEditorState(editor) {
283
328
  }
284
329
  });
285
330
  setIsLink(true);
286
- console.log(nextUrl);
287
331
  lexical.update(function () {
288
332
  if (expandTo) {
289
333
  var selection = $getSelection();
@@ -294,12 +338,8 @@ export function useEditorState(editor) {
294
338
  selection.focus.set(anchorNode.getKey(), expandTo.index + expandTo.length, 'text');
295
339
  }
296
340
  }
297
- console.log(nextUrl);
298
341
  lexical.dispatchCommand(TOGGLE_LINK_COMMAND, validateUrl(nextUrl) ? nextUrl : sanitizeUrl('https://'));
299
342
  });
300
- } else {
301
- setIsLink(false);
302
- lexical.dispatchCommand(TOGGLE_LINK_COMMAND, null);
303
343
  }
304
344
  }, [editor, isLink]);
305
345
  var insertMath = useCallback(function () {
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Shared URL validation utilities
3
+ */
4
+ /**
5
+ * Validates if a string is a valid URL
6
+ * @param url - The URL to validate
7
+ * @returns true if the URL is valid, false otherwise
8
+ */
9
+ export declare function isValidUrl(url: string): boolean;
10
+ /**
11
+ * Checks if text is a pure URL (single URL without other text)
12
+ * @param text - The text to check
13
+ * @returns true if text is a pure URL, false otherwise
14
+ */
15
+ export declare function isPureUrl(text: string): boolean;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Shared URL validation utilities
3
+ */
4
+
5
+ // URL validation regex that matches common URL patterns
6
+ var URL_REGEX = new RegExp(/^(?:(?:https?|ftp):\/\/)?(?:www\.)?[\dA-Za-z][\w#%+./:=?@~-]*[\w#%+/=@~-]$/);
7
+
8
+ /**
9
+ * Validates if a string is a valid URL
10
+ * @param url - The URL to validate
11
+ * @returns true if the URL is valid, false otherwise
12
+ */
13
+ export function isValidUrl(url) {
14
+ if (!url || typeof url !== 'string') return false;
15
+ var trimmed = url.trim();
16
+
17
+ // Check if it matches URL pattern
18
+ if (URL_REGEX.test(trimmed)) {
19
+ return true;
20
+ }
21
+
22
+ // Check if it's a valid URL with protocol
23
+ try {
24
+ var urlObj = new URL(trimmed);
25
+ return !!urlObj.protocol && !!urlObj.hostname;
26
+ } catch (_unused) {
27
+ // Not a valid URL
28
+ }
29
+
30
+ // Check if it looks like a domain (e.g., "google.com")
31
+ if (/^[\da-z][\w#%+./:=?@~-]*\.[\w#%+/:=?@~-]+$/i.test(trimmed)) {
32
+ return true;
33
+ }
34
+ return false;
35
+ }
36
+
37
+ /**
38
+ * Checks if text is a pure URL (single URL without other text)
39
+ * @param text - The text to check
40
+ * @returns true if text is a pure URL, false otherwise
41
+ */
42
+ export function isPureUrl(text) {
43
+ if (!text || typeof text !== 'string') return false;
44
+ var trimmed = text.trim();
45
+
46
+ // Check if it's a single line
47
+ if (trimmed.includes('\n')) return false;
48
+
49
+ // Check if it's a valid URL
50
+ return isValidUrl(trimmed);
51
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/editor",
3
- "version": "1.19.0",
3
+ "version": "1.20.0",
4
4
  "description": "A powerful and extensible rich text editor built on Meta's Lexical framework, providing a modern editing experience with React integration.",
5
5
  "keywords": [
6
6
  "lobehub",