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

Allow control of Slate's event handler execution in custom event handler API #4299

Merged

Conversation

georgberecz
Copy link
Contributor

Description
From the Slate Slack channel:
We noticed that our own custom dnd behavior broke with the upgrade to 0.63 due to the changes introduced in this PR. For some context: We use react-dnd to enable users, among other things, to drag Nodes next to each other to automatically set up column layouts. Thus, while we want to use Slate's internal dnd logic in some cases, we need to prevent the default logic in others.
The root cause of the issue lies within the state.isDraggingInternally property that was introduced and that is set in the onDragStart handler. Unfortunately, it is not possible to overwrite onDragStart and prevent the default logic on the Editable component without having to call preventDefault or stopPropgation on the event (which in turn would break react-dnd behavior). Otherwise, Slate's default handler is still executed.
It is limiting and confusing that the differentiator whether or not an event was handled is solely based on isDefaultPrevented or isPropagationStopped.
This PR introduces an escape hatch for custom event handlers to specify whether or not the event should be treated as handled and, therefore, further processed by Slate's own handler.

Issue
Fixes: issue described above

Example

const onClick = useCallback(event => {
  // Implement custom event logic...

  // Not returning a value resembles the current state where isEventHandled depends on
  // preventDefault and stopPropgation
}, []);

const onDrop = useCallback(event => {
  // Implement custom event logic...

  // No matter the status of the event, treat it as being handled by returning true here
  // -> Slate will skip its own event handler
  return true;
}, []);

const onDragStart = useCallback(event => {
  // Implement custom event logic...

  // No matter the status of the event, treat event as *not* being handled by returning false
  // -> Slate will continue with its own handler
  return false;
}, []);

<Editable
    renderElement={renderElement}
    renderLeaf={renderLeaf}
    onClick={onClick}
    onDrop={onDrop}
    onDragStart={onDragStart
    {/*...*/}
/>

Context
This PR suggests the following change: Optionally, all custom event handlers can return a boolean to control the execution of Slate's default handler logic:
void - Currently the only supported option and there is no change in this existing behavior. (thus, no breaking change for existing Slate editors)
true - Explicitly treat event as handled -> Do not execute Slate's default event handler
false - Explicitly do not treat event as handled -> Execute Slate's default event handler

The boolean flags will take precedence over the existing preventDefault and stopPropgation checks and will, therefore, allow for more flexibility in adjusting Slate's behavior.

Checks

  • The new code matches the existing patterns and styles.
  • The tests pass with yarn test.
  • The linter passes with yarn lint. (Fix errors with yarn fix.)
  • The relevant examples still work. (Run examples with yarn start.)
  • You've added a changeset if changing functionality. (Add one with yarn changeset add.)

@changeset-bot
Copy link

changeset-bot bot commented May 28, 2021

🦋 Changeset detected

Latest commit: 5ac9d88

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
slate-react Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Collaborator

@clauderic clauderic left a comment

Choose a reason for hiding this comment

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

Looks good overall, just a small suggestion.

Could you check if documentation needs to be updated around this change?

@@ -0,0 +1,5 @@
---
'slate-react': patch
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this should be a minor bump as it introduces new functionality rather than just a fix

packages/slate-react/src/components/editable.tsx Outdated Show resolved Hide resolved
@georgberecz
Copy link
Contributor Author

Looks good overall, just a small suggestion.

Could you check if documentation needs to be updated around this change?

Thanks a lot for the review @clauderic. There is not much documentation on the Editable component so far. I took a stab at extending the content with an event handling section that describes the behavior introduced with this PR. Let me know if that's what you had in mind.

Copy link
Collaborator

@clauderic clauderic left a comment

Choose a reason for hiding this comment

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

This is looking great, thanks for adding documentation around this! Just a few final thoughts

if (shouldTreatEventAsHandled != null) {
return shouldTreatEventAsHandled
}

return event.isDefaultPrevented() || event.isPropagationStopped()
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

Should the isDOMEventHandled method be updated as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ha, very good point! I initially thought it shouldn't, but after having another look at the code I feel like it actually should behave the same way to stay consistent and not confuse people. I will adjust it.

docs/libraries/slate-react.md Outdated Show resolved Hide resolved
docs/libraries/slate-react.md Outdated Show resolved Hide resolved
Your custom event handler can control whether or not Slate will execute its own event handler after yours depending on the return value of your event handler as described below.

```javascript
const onClick = useCallback(event => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we remove the useCallback from here and below? It's not specifically relevant to what is being explained

@georgberecz
Copy link
Contributor Author

This is looking great, thanks for adding documentation around this! Just a few final thoughts

Hey mate, thanks for the second round of feedback. I updated the PR according to your suggestions.

Copy link
Collaborator

@clauderic clauderic left a comment

Choose a reason for hiding this comment

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

Thanks for your contribution 🙏

@clauderic clauderic merged commit 2c17e2b into ianstormtaylor:main Jun 1, 2021
@github-actions github-actions bot mentioned this pull request Jun 1, 2021
dylans pushed a commit to dylans/slate that referenced this pull request Sep 13, 2021
…ler API (ianstormtaylor#4299)

Co-authored-by: Georg Berecz <gberecz@palantir.com>
Co-authored-by: Claudéric Demers <clauderic.d@gmail.com>
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.

3 participants