diff --git a/packages/web/src/javascripts/Components/SuperEditor/Plugins/AutoLinkPlugin/AutoLinkPlugin.tsx b/packages/web/src/javascripts/Components/SuperEditor/Plugins/AutoLinkPlugin/AutoLinkPlugin.tsx
index 23bf6583a..9fe41c9ee 100644
--- a/packages/web/src/javascripts/Components/SuperEditor/Plugins/AutoLinkPlugin/AutoLinkPlugin.tsx
+++ b/packages/web/src/javascripts/Components/SuperEditor/Plugins/AutoLinkPlugin/AutoLinkPlugin.tsx
@@ -6,14 +6,9 @@
*
*/
+import { URL_REGEX, EMAIL_REGEX } from '@/Constants/Constants'
import { AutoLinkPlugin, createLinkMatcherWithRegExp } from '@lexical/react/LexicalAutoLinkPlugin'
-const URL_REGEX =
- /((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/
-
-const EMAIL_REGEX =
- /(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/
-
const MATCHERS = [
createLinkMatcherWithRegExp(URL_REGEX, (text) => {
return text.startsWith('http') ? text : `https://${text}`
diff --git a/packages/web/src/javascripts/Components/SuperEditor/Plugins/FloatingLinkEditorPlugin/LinkEditor.tsx b/packages/web/src/javascripts/Components/SuperEditor/Plugins/FloatingLinkEditorPlugin/LinkEditor.tsx
index 7d037e1e5..1d4de9efd 100644
--- a/packages/web/src/javascripts/Components/SuperEditor/Plugins/FloatingLinkEditorPlugin/LinkEditor.tsx
+++ b/packages/web/src/javascripts/Components/SuperEditor/Plugins/FloatingLinkEditorPlugin/LinkEditor.tsx
@@ -4,7 +4,7 @@ import { KeyboardKey } from '@standardnotes/ui-services'
import { IconComponent } from '../../Lexical/Theme/IconComponent'
import { sanitizeUrl } from '../../Lexical/Utils/sanitizeUrl'
import { TOGGLE_LINK_COMMAND } from '@lexical/link'
-import { useCallback, useState, useRef } from 'react'
+import { useCallback, useState, useRef, useEffect } from 'react'
import { GridSelection, LexicalEditor, NodeSelection, RangeSelection } from 'lexical'
import { classNames } from '@standardnotes/snjs'
@@ -36,6 +36,10 @@ const LinkEditor = ({ linkUrl, isEditMode, setEditMode, editor, lastSelection, i
}
}, [])
+ useEffect(() => {
+ setEditedLinkUrl(linkUrl)
+ }, [linkUrl])
+
return isEditMode ? (
, selection: RangeSelection) => {
+ const parent = node.getParent()
+ return $isLinkNode(parent) && $isTextNode(node) && selection.anchor.getNode() === selection.focus.getNode()
+}
+
+const LinkTextEditor = ({ linkText, editor, lastSelection }: Props) => {
+ const [editedLinkText, setEditedLinkText] = useState(() => linkText)
+ const [isEditMode, setEditMode] = useState(false)
+ const editModeContainer = useRef
(null)
+
+ useEffect(() => {
+ setEditedLinkText(linkText)
+ }, [linkText])
+
+ const focusInput = useCallback((input: HTMLInputElement | null) => {
+ if (input) {
+ input.focus()
+ }
+ }, [])
+
+ const handleLinkTextSubmission = () => {
+ editor.update(() => {
+ if ($isRangeSelection(lastSelection)) {
+ const node = getSelectedNode(lastSelection)
+ if (!$isLinkTextNode(node, lastSelection)) {
+ return
+ }
+ node.setTextContent(editedLinkText)
+ }
+ })
+ setEditMode(false)
+ }
+
+ return isEditMode ? (
+
+ {
+ setEditedLinkText(event.target.value)
+ }}
+ onKeyDown={(event) => {
+ if (event.key === KeyboardKey.Enter) {
+ event.preventDefault()
+ handleLinkTextSubmission()
+ } else if (event.key === KeyboardKey.Escape) {
+ event.preventDefault()
+ setEditMode(false)
+ }
+ }}
+ onBlur={(event) => {
+ if (!editModeContainer.current?.contains(event.relatedTarget as Node)) {
+ setEditMode(false)
+ }
+ }}
+ className="flex-grow rounded-sm bg-contrast p-1 text-text sm:min-w-[20ch]"
+ />
+
+
+
+ ) : (
+
+
+
+ Link text:
+ {linkText}
+
+
+
+ )
+}
+
+export default LinkTextEditor
diff --git a/packages/web/src/javascripts/Components/SuperEditor/Plugins/FloatingTextFormatToolbarPlugin/index.tsx b/packages/web/src/javascripts/Components/SuperEditor/Plugins/FloatingTextFormatToolbarPlugin/index.tsx
index db546be5f..2439b64c5 100644
--- a/packages/web/src/javascripts/Components/SuperEditor/Plugins/FloatingTextFormatToolbarPlugin/index.tsx
+++ b/packages/web/src/javascripts/Components/SuperEditor/Plugins/FloatingTextFormatToolbarPlugin/index.tsx
@@ -23,6 +23,9 @@ import {
RangeSelection,
GridSelection,
NodeSelection,
+ KEY_MODIFIER_COMMAND,
+ COMMAND_PRIORITY_NORMAL,
+ createCommand,
} from 'lexical'
import { $isHeadingNode } from '@lexical/rich-text'
import {
@@ -49,13 +52,14 @@ import {
ListNumbered,
} from '@standardnotes/icons'
import { IconComponent } from '../../Lexical/Theme/IconComponent'
-import { sanitizeUrl } from '../../Lexical/Utils/sanitizeUrl'
import { classNames } from '@standardnotes/snjs'
import { getDOMRangeRect } from '../../Lexical/Utils/getDOMRangeRect'
import { getPositionedPopoverStyles } from '@/Components/Popover/GetPositionedPopoverStyles'
import { getAdjustedStylesForNonPortalPopover } from '@/Components/Popover/Utils/getAdjustedStylesForNonPortal'
import LinkEditor from '../FloatingLinkEditorPlugin/LinkEditor'
import { movePopoverToFitInsideRect } from '@/Components/Popover/Utils/movePopoverToFitInsideRect'
+import LinkTextEditor, { $isLinkTextNode } from '../FloatingLinkEditorPlugin/LinkTextEditor'
+import { URL_REGEX } from '@/Constants/Constants'
const blockTypeToBlockName = {
bullet: 'Bulleted List',
@@ -74,6 +78,8 @@ const blockTypeToBlockName = {
const IconSize = 15
+const TOGGLE_LINK_AND_EDIT_COMMAND = createCommand('TOGGLE_LINK_AND_EDIT_COMMAND')
+
const ToolbarButton = ({ active, ...props }: { active?: boolean } & ComponentPropsWithoutRef<'button'>) => {
return (