Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/super-editor/src/editors/v1/core/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,9 @@ export class Editor extends EventEmitter<EditorEventMap> {
onCommentsLoaded: () => null,
onCommentClicked: () => null,
onCommentLocationsUpdate: () => null,
onPointerDown: () => null,
onPointerUp: () => null,
onRightClick: () => null,
onDocumentLocked: () => null,
onFirstRender: () => null,
onCollaborationReady: () => null,
Expand Down Expand Up @@ -761,6 +764,9 @@ export class Editor extends EventEmitter<EditorEventMap> {
this.on('list-definitions-change', this.options.onListDefinitionsChange!);
this.on('fonts-resolved', this.options.onFontsResolved!);
this.on('exception', this.options.onException!);
this.on('pointerDown', this.options.onPointerDown!);
this.on('pointerUp', this.options.onPointerUp!);
this.on('rightClick', this.options.onRightClick!);
}

/**
Expand Down Expand Up @@ -1159,6 +1165,9 @@ export class Editor extends EventEmitter<EditorEventMap> {
this.on('list-definitions-change', this.options.onListDefinitionsChange!);
this.on('fonts-resolved', this.options.onFontsResolved!);
this.on('exception', this.options.onException!);
this.on('pointerDown', this.options.onPointerDown!);
this.on('pointerUp', this.options.onPointerUp!);
this.on('rightClick', this.options.onRightClick!);

if (!shouldMountRenderer) {
this.#emitCreateAsync();
Expand Down Expand Up @@ -1235,6 +1244,9 @@ export class Editor extends EventEmitter<EditorEventMap> {
this.on('commentClick', this.options.onCommentClicked!);
this.on('locked', this.options.onDocumentLocked!);
this.on('list-definitions-change', this.options.onListDefinitionsChange!);
this.on('pointerDown', this.options.onPointerDown!);
this.on('pointerUp', this.options.onPointerUp!);
this.on('rightClick', this.options.onRightClick!);

if (!shouldMountRenderer) {
this.#emitCreateAsync();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,16 @@ export class EditorInputManager {
#handlePointerDown(event: PointerEvent): void {
if (!this.#deps) return;

// Emit local-only pointer events for external consumers (e.g. debugging trackpad issues)
// Emit directly on the Editor instance so consumers can use editor.on('pointerDown', ...)
const editor = this.#deps.getEditor();
editor.emit?.('pointerDown', { editor, event });

// Emit rightClick for secondary button (button 2) or Ctrl+Click on Mac
if (event.button === 2 || (event.ctrlKey && navigator.platform.includes('Mac'))) {
editor.emit?.('rightClick', { editor, event });
}

// Return early for non-left clicks
if (event.button !== 0) return;

Expand Down Expand Up @@ -1038,7 +1048,6 @@ export class EditorInputManager {
return;
}

const editor = this.#deps.getEditor();
if (this.#handleSingleCommentHighlightClick(event, target, editor)) {
return;
}
Expand Down Expand Up @@ -1325,6 +1334,11 @@ export class EditorInputManager {
#handlePointerUp(event: PointerEvent): void {
if (!this.#deps) return;

// Emit local-only pointer event for external consumers (e.g. debugging trackpad issues)
// Emit directly on the Editor instance so consumers can use editor.on('pointerUp', ...)
const editor = this.#deps.getEditor();
editor.emit?.('pointerUp', { editor, event });

this.#suppressFocusInFromDraggable = false;

if (!this.#isDragging) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,15 @@ export interface EditorOptions {
/** Host-provided permission hook */
permissionResolver?: ((params: PermissionParams) => boolean | undefined) | null;

/** Called on pointer down events (local only, not broadcast via collaboration) */
onPointerDown?: (params: { editor: Editor; event: PointerEvent }) => void;

/** Called on pointer up events (local only, not broadcast via collaboration) */
onPointerUp?: (params: { editor: Editor; event: PointerEvent }) => void;

/** Called on right-click (local only, not broadcast via collaboration) */
onRightClick?: (params: { editor: Editor; event: MouseEvent }) => void;

/**
* Custom resolver for the link click popover.
* Called when a user clicks a link to determine which popover to show.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,13 @@ export interface EditorEventMap extends DefaultEventMap {

/** Called when document protection state changes (init, local mutation, or remote sync). */
protectionChanged: [{ editor: Editor; state: DocumentProtectionState; source: ProtectionChangeSource }];

/** Called on pointer down (local only, not broadcast via collaboration) */
pointerDown: [{ editor: Editor; event: PointerEvent }];

/** Called on pointer up (local only, not broadcast via collaboration) */
pointerUp: [{ editor: Editor; event: PointerEvent }];

/** Called on right-click (local only, not broadcast via collaboration) */
rightClick: [{ editor: Editor; event: MouseEvent }];
}
13 changes: 13 additions & 0 deletions packages/superdoc/src/dev/components/SuperdocDev.vue
Original file line number Diff line number Diff line change
Expand Up @@ -1096,6 +1096,19 @@ const onEditorCreate = ({ editor }) => {
editor.on('fieldAnnotationDoubleClicked', (params) => {
console.log('fieldAnnotationDoubleClicked', { params });
});

// SD-2494: Pointer event observability for debugging trackpad/right-click selection issues
editor.on('pointerDown', (params) => {
console.log('pointerDown', { params });
});

editor.on('pointerUp', (params) => {
console.log('pointerUp', { params });
});

editor.on('rightClick', (params) => {
console.log('rightClick', { params });
});
};

watch(
Expand Down
Loading