{
+ if (!instance.isEditable) return false
+ const { selection } = state
+ // Node selections (images, math, diagrams) have their own affordances.
+ if (selection instanceof NodeSelection) return false
+ if (instance.isActive('codeBlock')) return false
+ if (!selection.empty) return true
+ return instance.isActive('link')
+ }}
+ className="flex items-center gap-0.5 rounded-lg border border-stone-200 dark:border-stone-600 bg-white dark:bg-stone-800 p-1 shadow-lg"
+ >
+ {linkMode ? (
+
+ setLinkDraft(e.target.value)}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter') {
+ e.preventDefault()
+ applyLink()
+ } else if (e.key === 'Escape') {
+ e.preventDefault()
+ setLinkMode(false)
+ editor.commands.focus()
+ }
+ }}
+ placeholder="https://…"
+ className="w-56 rounded border border-stone-200 dark:border-stone-600 bg-white dark:bg-stone-900 px-2 py-1 text-xs text-stone-900 dark:text-white placeholder-stone-400 focus:outline-none focus:ring-1 focus:ring-stone-900 dark:focus:ring-stone-100"
+ aria-label="Link URL"
+ />
+
+ {editor.isActive('link') && (
+
+ )}
+
+ ) : (
+ <>
+ {marks.map((mark) => {
+ const IconComponent = mark.icon
+ const active = mark.active()
+ return (
+
+ )
+ })}
+
+ >
+ )}
+
+ )
+}
diff --git a/package.json b/package.json
index 8f491c9..4a424c7 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
"@react-router/node": "7.15.0",
"@react-router/serve": "7.15.0",
"@tiptap/core": "3.28.0",
+ "@tiptap/extension-bubble-menu": "3.28.0",
"@tiptap/extension-code": "3.28.0",
"@tiptap/extension-code-block": "3.28.0",
"@tiptap/extension-code-block-lowlight": "3.28.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7b0a11f..5376bf4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -59,6 +59,9 @@ importers:
'@tiptap/core':
specifier: 3.28.0
version: 3.28.0(@tiptap/pm@3.28.0)
+ '@tiptap/extension-bubble-menu':
+ specifier: 3.28.0
+ version: 3.28.0(@tiptap/core@3.28.0(@tiptap/pm@3.28.0))(@tiptap/pm@3.28.0)
'@tiptap/extension-code':
specifier: 3.28.0
version: 3.28.0(@tiptap/core@3.28.0(@tiptap/pm@3.28.0))
@@ -2655,6 +2658,12 @@ packages:
peerDependencies:
'@tiptap/core': 3.29.2
+ '@tiptap/extension-bubble-menu@3.28.0':
+ resolution: {integrity: sha512-7AUNoHj2K4XLKCgW4uspeD/ENejPu2BeHvLTsiOoIO+XXDNSi2j0bbaIS8f2s/qnFirscwp/sbznp1qph/76qg==}
+ peerDependencies:
+ '@tiptap/core': 3.28.0
+ '@tiptap/pm': 3.28.0
+
'@tiptap/extension-bubble-menu@3.29.2':
resolution: {integrity: sha512-kzcWarcpr031rZu+R3Hzut5uxb3Qj/xxMDEYZIQ3uiq1yb5vEMXj8/SIyWautk6Nu8Rr1leV3rGdR4NzhzyFAA==}
peerDependencies:
@@ -8907,6 +8916,12 @@ snapshots:
dependencies:
'@tiptap/core': 3.28.0(@tiptap/pm@3.28.0)
+ '@tiptap/extension-bubble-menu@3.28.0(@tiptap/core@3.28.0(@tiptap/pm@3.28.0))(@tiptap/pm@3.28.0)':
+ dependencies:
+ '@floating-ui/dom': 1.8.0
+ '@tiptap/core': 3.28.0(@tiptap/pm@3.28.0)
+ '@tiptap/pm': 3.28.0
+
'@tiptap/extension-bubble-menu@3.29.2(@tiptap/core@3.28.0(@tiptap/pm@3.28.0))(@tiptap/pm@3.28.0)':
dependencies:
'@floating-ui/dom': 1.8.0