-
Notifications
You must be signed in to change notification settings - Fork 126
Note: Prevent programmatic selection on tap #2904
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
Note: Prevent programmatic selection on tap #2904
Conversation
I guess a self-contained solution would look something like the following:
|
Hi, thanks for getting started on this. I believe we programmatically set the selection on a non-empty note during the |
I see this in
which does not set |
Yes, I see that now. The |
Ah, existing note, not only when a new note is created. Two possible solutions occur to me:
Option 2 means introducing something into the state that maybe doesn't belong there, but I've been looking into #2837 and I'm pretty sure that the mechanics of |
Option 1 is pretty ugly, so I would say Option 2 is the one to pursue. Thanks! |
I updated the PR description to outline my new approach. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the update!
While this is an interesting approach, my overall sense is that the middleware + action extension + ministore is a bit bulky for what we need here. If I'm understanding correctly, we need a back door to block the side effect in the Note component. I would suggest either committing to using the Redux state, or to using a back door/side channel, but not mixing the two.
- Redux state - We could add
state.noteOffset: number | null
(analogous tostate.cursorOffset
) and handle it entirely in Redux state.- Note the similar semantics:
A value of null means that the caret is not forcefully set on re-render, allowing the device to set it, e.g. on click.
- With the middleware approach, "there's no danger of ephemeral data lingering in the state": sounds beneficial, but I'm not sure there is actual danger is in this case. If
noteOffset
is only used in theuseEffect
, then it is effectively inert after the initial render.
- Note the similar semantics:
- Back door - Alternatively, if the Redux state is insufficient, we can commit to a completely independent back door: either a Ref if it's contained within a component or a ministore if it is used across modules. Mixing this with middleware or extending the Action type is probably adding unnecessary complexity and coupling between different state management systems.
It might be a bit over-engineered, but my hope is that I can immediately use this same ministore for #2837 to cut down on some of the edge cases in
Editable
selections. I made a cursory attempt to strongly-type the metadata, but more work is needed there. I didn't want to get ahead of myself.
I'm hesitant to build a general system in anticipation of future specifics unless those future specifics are very known/well-defined. I usually prefer to solve the specifics, then generalize afterwards in a refactor if we notice repetition/redundancy.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as outdated.
This comment was marked as outdated.
src/@types/State.ts
Outdated
@@ -123,6 +123,7 @@ interface State { | |||
* Passed to Yjs and cleared on every action. | |||
* See: /redux-enhancers/pushQueue.ts. | |||
*/ | |||
noteOffset: number | null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add a descriptive JSDOC comment here. It should explain the unique semantics of null
.
(FYI This accidentally picked up the comment for pushQueue
.)
src/components/Note.tsx
Outdated
@@ -57,12 +59,14 @@ const Note = React.memo( | |||
useEffect(() => { | |||
// cursor must be true if note is focused | |||
if (hasFocus) { | |||
selection.set(noteRef.current!, { end: true }) | |||
if (noteOffset === null) return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's combine this with the outer if
statement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
Fixes #2839
Third time's the charm. I added a
noteOffset
property to state. If it isnull
,Note
will not attempt to programmatically set the selection. If it is anumber
, it will be used to set the selection. Currently, the only number that is used isvalue.length
which sets the caret at the end, replacing the previousselection.set(noteRef.current!, { end: true })
.