Skip to content

Enable tap exclusion for inline widgets in SuperReader#3

Merged
mack-at-pieces merged 3 commits into
mainfrom
feat/content-tap-exclusion
Aug 8, 2025
Merged

Enable tap exclusion for inline widgets in SuperReader#3
mack-at-pieces merged 3 commits into
mainfrom
feat/content-tap-exclusion

Conversation

@mack-at-pieces

Copy link
Copy Markdown

This pull request introduces improvements to gesture handling in the SuperEditor package, specifically enabling inline widgets (such as placeholders) to independently handle tap gestures without interference from SuperReader's gesture recognizers. The changes include a new exclusion widget, updates to gesture recognizers, and platform-specific logic to allow inline widgets to receive taps directly.

Gesture Handling Enhancements

  • Added the new ContentTapExclusion widget and its render object (RenderContentTapExclusion) to mark subtrees that should be excluded from SuperReader's internal tap gesture handling, enabling inline widgets to handle taps independently. (super_editor/lib/src/infrastructure/content_tap_exclusion.dart)
  • Updated TapSequenceGestureRecognizer to support an isPointerAllowedPredicate, allowing custom logic to decide whether a tap gesture should be handled by SuperReader or passed to child widgets. (super_editor/lib/src/infrastructure/multi_tap_gesture.dart) [1] [2]

Platform-Specific Tap Handling

  • Implemented _isPointerAllowedForTap logic in Android, iOS, and mouse document interactors to check if a tap occurs over a placeholder; if so, the tap is excluded from SuperReader handling and passed to the inline widget. (super_editor/lib/src/super_reader/read_only_document_android_touch_interactor.dart, super_editor/lib/src/super_reader/read_only_document_ios_touch_interactor.dart, super_editor/lib/src/super_reader/read_only_document_mouse_interactor.dart) [1] [2] [3]

API and Export Updates

  • Exported the new content_tap_exclusion.dart from the main super_editor.dart library, making the exclusion widget available for public use. (super_editor/lib/super_editor.dart)

Hit Testing Improvements

  • Refactored hit testing logic in _RenderSliverHybridStack to correctly aggregate hit results from child render objects, improving gesture detection reliability for complex layouts. (super_editor/lib/src/infrastructure/sliver_hybrid_stack.dart) [1] [2] [3]

These changes collectively improve the flexibility and reliability of tap gesture handling in SuperEditor, especially for documents containing interactive inline widgets.

Introduces ContentTapExclusion to allow subtree widgets to bypass SuperReader's tap gesture handling, enabling direct tap handling for inline widgets such as placeholders. Updates gesture recognizers to consult a pointer predicate, preventing tap interception when over inline placeholders. Refactors hit testing in sliver hybrid stack for correct child hit aggregation.
Copilot AI review requested due to automatic review settings August 8, 2025 00:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR enables inline widgets (such as placeholders) in SuperReader to handle tap gestures independently without interference from SuperReader's gesture recognizers. The implementation adds exclusion mechanisms and platform-specific logic to detect when taps occur over placeholders and allow them to be handled by the inline widgets directly.

  • Added ContentTapExclusion widget and render object to mark subtrees for exclusion from SuperReader's tap handling
  • Enhanced TapSequenceGestureRecognizer with isPointerAllowedPredicate for custom tap exclusion logic
  • Implemented platform-specific pointer allowance checking in Android, iOS, and mouse interactors

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
super_editor.dart Exports the new content tap exclusion widget
content_tap_exclusion.dart Implements the exclusion widget and render object
multi_tap_gesture.dart Adds predicate support to gesture recognizer
read_only_document_*_interactor.dart Implements placeholder detection logic for each platform
sliver_hybrid_stack.dart Improves hit testing aggregation logic
text.dart Contains formatting changes to class properties

bool hitTest(BoxHitTestResult result, {required Offset position}) {
final hit = super.hitTest(result, position: position);
return hit;
}

Copilot AI Aug 8, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hitTest method doesn't add any functionality beyond calling super.hitTest(). Consider adding documentation to explain why this override is necessary or remove it if it serves no purpose.

Suggested change
}

Copilot uses AI. Check for mistakes.
if (node is! TextNode) {
return true;
}
final offset = (docPosition.nodePosition as TextPosition).offset;

Copilot AI Aug 8, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check uses TextPosition but should use TextNodePosition to match the TextNode type check. This inconsistency could cause incorrect type checking.

Suggested change
final offset = (docPosition.nodePosition as TextPosition).offset;
if (docPosition.nodePosition is! TextNodePosition) {
return true;
}
final node = widget.readerContext.document.getNodeById(docPosition.nodeId);
if (node is! TextNode) {
return true;
}
final offset = (docPosition.nodePosition as TextNodePosition).offset;

Copilot uses AI. Check for mistakes.
if (docPosition == null) {
return true;
}
if (docPosition.nodePosition is! TextPosition) {

Copilot AI Aug 8, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check uses TextPosition but should use TextNodePosition to match the TextNode type check. This inconsistency could cause incorrect type checking.

Suggested change
if (docPosition.nodePosition is! TextPosition) {
if (docPosition.nodePosition is! TextNodePosition) {

Copilot uses AI. Check for mistakes.
if (node is! TextNode) {
return true;
}
final offset = (docPosition.nodePosition as TextPosition).offset;

Copilot AI Aug 8, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cast to TextPosition should be TextNodePosition to match the type returned by getDocumentPositionNearestToOffset for text nodes.

Suggested change
final offset = (docPosition.nodePosition as TextPosition).offset;
final offset = (docPosition.nodePosition as TextNodePosition).offset;

Copilot uses AI. Check for mistakes.
if (node is! TextNode) {
return true;
}
final offset = (docPosition.nodePosition as TextPosition).offset;

Copilot AI Aug 8, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cast to TextPosition should be TextNodePosition to match the type returned by getDocumentPositionNearestToOffset for text nodes.

Suggested change
final offset = (docPosition.nodePosition as TextPosition).offset;
final offset = (docPosition.nodePosition as TextNodePosition).offset;

Copilot uses AI. Check for mistakes.
if (node is! TextNode) {
return true;
}
final offset = (docPosition.nodePosition as TextPosition).offset;

Copilot AI Aug 8, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cast to TextPosition should be TextNodePosition to match the type returned by getDocumentPositionNearestToOffset for text nodes.

Suggested change
final offset = (docPosition.nodePosition as TextPosition).offset;
final offset = (docPosition.nodePosition as TextNodePosition).offset;

Copilot uses AI. Check for mistakes.
Moved tap exclusion logic for inline placeholders to a shared function, isTapAllowedAtDocumentPosition, in content_tap_exclusion.dart. Updated Android, iOS, and mouse interactors to use this function for consistent tap handling over inline widgets.
Introduces a markdown document explaining the rationale, implementation, and usage of tap exclusion for inline widgets in SuperEditor. Details the ContentTapExclusion marker, shared tap-allowance utility, and updates to interactors for consistent tap handling across platforms.
@mack-at-pieces mack-at-pieces merged commit a7ab5bd into main Aug 8, 2025
21 of 25 checks passed
@mack-at-pieces mack-at-pieces deleted the feat/content-tap-exclusion branch August 8, 2025 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants