Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revised Selection Behavior #151

Merged
merged 24 commits into from
Oct 3, 2024
Merged

Revised Selection Behavior #151

merged 24 commits into from
Oct 3, 2024

Conversation

rsimon
Copy link
Member

@rsimon rsimon commented Oct 2, 2024

In this PR

This PR revises the selection behavior fundamentally. Instead of creating an annotation immediately, the SelectionHandler now waits until the (native browser text-)selection is 'complete'. Because there is not actually a 'complete' event, there are different approaches, depending on platform and interaction mode:

  • For mouse interaction a complete selection is determined by a pointerup event.
  • For keyboard interaction a complete selection is determined by the keyup event of the Shift key. (Note that selection remains editable - unless popup intervenes.)
  • Ctrl + A (or Cmd + A) is handled separately, as a single operation.
  • iOS/iPad: complete selection is determined by pointerup or contextmenu event.
  • Android: complete selection is determined by the contextmenu event.

Note: in all cases, the selection remains editable after "completion", either by using Shift+Arrow keys (desktop) or by dragging the handlebars (on mobile/touch).

React Popup

I also modified the React TextAnnotatorPopup with the following behaviors:

  • On mobile, the popup is oriented below the annotation (instead of the default above), since it would otherwise be obstructed by the default system context menu on iOS and Android.
  • On mobile, the popup does not receive initial focus. The user must explicitly tap into it. This way, the selection handlebars remain activated, and it is still possible to alter the selection after the popup has opened.

Warning: mobile mode is detected through navigator.userAgent. It appears that Firefox currently does not include sufficient information to determine whether it is running on iOS. Therefore, FF/iOS currently behaves like on the desktop, which also means it will lose the selection handlebars as soon as the <TextAnnotatorPopup> opens.

@rsimon
Copy link
Member Author

rsimon commented Oct 2, 2024

Hi @oleksandr-danylchenko,

I'm about to merge this into main soon. But wanted to give you a heads-up and chance to look over the changes. I think this should work well on all platforms. But do let me know if you have any doubts, or find something that I missed.

I so far tested this on FF + Chrome (Mac, iPad, Android) and will do another round of testing on FF/Chrome/Edge on Linux tomorrow, with a hybrid desktop/touch computer.

@oleksandr-danylchenko
Copy link
Contributor

Thank you 🙌🏻🙌🏻🙌🏻
I'll take a look tomorrow

@rsimon
Copy link
Member Author

rsimon commented Oct 3, 2024

Update: I added a few more tweaks. Bad news first: I could not find a perfect solution for CTRL/CMD-A, unfortunately. (There's a timeout involved, which might presumably lead to timing issues if large texts are involved. Not sure if CTRL-A on large texts is such a big use case though?)

Other than that, however, everything seems to work as it should!

I tested with the standard test page from packages/text-annotator-react (which includes the dummy popup with a text input field). On the following devices/browsers:

  • Mac (desktop, mouse/touchpad): Chrome, Firefox, Safari
  • Mac (desktop, keyboard): Chrome, Firefox
  • Ubuntu (desktop, mouse/touchpad): Chrome, Firefox, Edge
  • Ubuntu (desktop, keyboard): Chrome, Firefox, Edge
  • Ubuntu (desktop, hybrid notebook with touch interaction): Chrome, Firefox, Edge *
  • iPad: Chrome, Firefox, Safari
  • Android: Chrome, Firefox, Samsung Internet (for whatever the hell that is :-)

* The hybrid Ubuntu notebook had some issues when used with touch. But I think none of these are dealbreakers, and tolerable:

  • Chrome maintains the selection handlebars after the annotation is created. But as soon as you try to drag, focus goes away and the selection is no longer editable. However: turns out this happens on all pages, and seems to be a general Chrome bug, not related to the Text Annotator.
  • Likewise: no editable selection on Firefox because it shifts the focus to the popup immediately. The reason is that, despite touch interaction, it reports pointerup events not contextmenu events, thus switching the Text Annotator into normal desktop behavior.
  • Interestingly, it was Edge that worked perfectly in hybrid mode. (Not sure if that's an expertise advantage from the MS Surface notebooks? :-)

rsimon and others added 2 commits October 3, 2024 13:14
Co-authored-by: Oleksandr Danylchenko <68850090+oleksandr-danylchenko@users.noreply.github.com>
Co-authored-by: Oleksandr Danylchenko <68850090+oleksandr-danylchenko@users.noreply.github.com>
Copy link
Contributor

@oleksandr-danylchenko oleksandr-danylchenko left a comment

Choose a reason for hiding this comment

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

The changes look great and clear. I tested them locally and they seem to work nicely. Thank you 🔥

The only feasible concern I have is losing the focus-out speedbump for the popup.

Comment on lines -147 to -149
} else {
// Proper lifecycle management: clear selection first...
selection.clear();
Copy link
Contributor

@oleksandr-danylchenko oleksandr-danylchenko Oct 10, 2024

Choose a reason for hiding this comment

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

I think that we may need to restore the selection.clear() call if there's nothing to update. Because now the previous, "discarded selection" unexpectedly stays up until you create a brand-new one.

unselect.mp4

*in my testing env, the annotations that don't have either a highlight or a note assigned get automatically garbage collected when they get unselected

Copy link
Contributor

Choose a reason for hiding this comment

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

UPD: Submitted a PR - #155

Comment on lines +232 to +233
} else if (currentTarget && currentTarget.selector.length > 0) {
selection.clear();
Copy link
Contributor

@oleksandr-danylchenko oleksandr-danylchenko Oct 10, 2024

Choose a reason for hiding this comment

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

Also... I'm not entirely sure why the current selection gets cleared and then immediately reselected back 🤔. I believe that discarding the previous selection in the selectionchanged handler should be enough, isn't it?

Comment on lines 160 to +161
const onPointerDown = (evt: PointerEvent) => {
if (isContextMenuOpen) return;
Copy link
Contributor

@oleksandr-danylchenko oleksandr-danylchenko Oct 29, 2024

Choose a reason for hiding this comment

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

Hello, @rsimon 👋🏻

Could you please clarify why the context menu guard was added for the pointer event handlers? With it in place, it takes 2 taps to dismiss the annotation selection. The first tap is needed to dismiss the context menu and the second one is to dismiss the annotation itself.
That makes the annotation selection look like it's lagging behind 🤔

Record_2024-10-29-17-40-29.mp4

Copy link
Contributor

Choose a reason for hiding this comment

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

I see that it was added under the Minor fix commit fb3d70b. However, it doesn't carry enough context 😅

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