fix(editor): add remove button and fix cursor positioning for event embeds

- Add X button on hover to NostrEventPreviewRich (same pattern as BlobAttachmentRich)
- Fix cursor positioning after pasting nevent/naddr by tracking node sizes correctly
- Import TextSelection from prosemirror-state to properly set cursor position
- Change from `tr.insert(from + index, node)` to `tr.insert(insertPos, node)` with cumulative position tracking

Previously, cursor would stay behind the event embed node after pasting.
Now it correctly positions after the inserted content.
This commit is contained in:
Claude
2026-01-21 09:00:20 +00:00
parent 05f28ca4ee
commit b25bbc402f
2 changed files with 24 additions and 6 deletions

View File

@@ -1,5 +1,5 @@
import { Extension } from "@tiptap/core";
import { Plugin, PluginKey } from "@tiptap/pm/state";
import { Plugin, PluginKey, TextSelection } from "@tiptap/pm/state";
import { nip19 } from "nostr-tools";
import eventStore from "@/services/event-store";
import { getProfileContent } from "applesauce-core/helpers";
@@ -152,11 +152,16 @@ export const NostrPasteHandler = Extension.create({
const { tr } = view.state;
const { from } = view.state.selection;
// Insert content
nodes.forEach((node, index) => {
tr.insert(from + index, node);
// Insert content and track position
let insertPos = from;
nodes.forEach((node) => {
tr.insert(insertPos, node);
insertPos += node.nodeSize;
});
// Move cursor to end of inserted content
tr.setSelection(TextSelection.near(tr.doc.resolve(insertPos)));
view.dispatch(tr);
return true; // Prevent default paste
}

View File

@@ -1,4 +1,5 @@
import { NodeViewWrapper, type ReactNodeViewProps } from "@tiptap/react";
import { X } from "lucide-react";
import { useNostrEvent } from "@/hooks/useNostrEvent";
import { KindRenderer } from "@/components/nostr/kinds";
import type { EventPointer, AddressPointer } from "nostr-tools/nip19";
@@ -9,7 +10,10 @@ import { EventCardSkeleton } from "@/components/ui/skeleton";
*
* Uses the feed KindRenderer to show event content inline
*/
export function NostrEventPreviewRich({ node }: ReactNodeViewProps) {
export function NostrEventPreviewRich({
node,
deleteNode,
}: ReactNodeViewProps) {
const { type, data } = node.attrs as {
type: "note" | "nevent" | "naddr";
data: any;
@@ -40,7 +44,7 @@ export function NostrEventPreviewRich({ node }: ReactNodeViewProps) {
const event = useNostrEvent(pointer || undefined);
return (
<NodeViewWrapper className="my-2">
<NodeViewWrapper className="my-2 relative group">
<div className="rounded-lg border border-border bg-muted/30 p-3 pointer-events-none">
{!event ? (
<EventCardSkeleton className="py-2" />
@@ -48,6 +52,15 @@ export function NostrEventPreviewRich({ node }: ReactNodeViewProps) {
<KindRenderer event={event} depth={0} />
)}
</div>
{deleteNode && (
<button
onClick={deleteNode}
className="absolute top-2 right-2 p-1.5 rounded-full bg-background/90 hover:bg-background border border-border opacity-0 group-hover:opacity-100 transition-opacity"
contentEditable={false}
>
<X className="size-4" />
</button>
)}
</NodeViewWrapper>
);
}