ianstormtaylor / slate

A completely customizable framework for building rich text editors. (Currently in beta.)
http://slatejs.org
MIT License
29.98k stars 3.25k forks source link

Unexpected text input on latest Android Mobile #3313

Open stevez86 opened 4 years ago

stevez86 commented 4 years ago

[Edit]: After creating this issue I noticed this may be a duplicate of https://github.com/ianstormtaylor/slate/issues/3112

The following is recorded using crossbrowsertesting.com with the latest android (Android Google Pixel 3 / 9.0 Chrome Mobile 77) I've also seen similar behavior on older versions of android and chrome mobile.

ezgif-5-2291b413293d (1)

I started noticing these issues when I was getting the following errors however I couldn't reproduce these in development so I figured it was a device specific issue.

Object.toSlatePoint: Cannot resolve a DOM point from Slate point: {"path":[0,1,0],"offset":106} Object.toSlatePoint: Cannot resolve a Slate point from DOM point: [object Text],108

The video doesn't directly lead to these errors however the video's behavior is an issue in itself and I believe the errors are a result of entering text in a blank editor on those devices however clearing out the editor is nearly impossible.

Slate: 0.54 Browser: Chrome Mobile 77 OS: Android 9

May also be related: https://github.com/ianstormtaylor/slate/issues/3309

mpkelly commented 4 years ago

FYI I am also getting this issue on Mac/Chrome 79 when using 0.57.1. It's not blocking me though so just adding a note here in hope helps debug the issue.

I am rendering a small button into the corner of a table cell and then when that button is clicked I show a small popup menu. I then click an option, e.g. Add column, and this error is logged before my event handler fires:

Uncaught Error: Cannot resolve a Slate point from DOM point: [object Text],5

The stack trace is:

   at Object.toSlatePoint (index.es.js:1708)
    at Object.toSlateRange (index.es.js:1753)
    at HTMLDocument.eval (index.es.js:817)
    at later (index.js:27)

The error originates from this handler: onDOMSelectionChange. Inspecting the code, it looks like onDOMSelectionChange is expecting slate nodes only and not dynamic nodes like I am including.

My code looks like this. Note the dynamic nature of the menu which is included for the focused cell only

  return (
    <td {...attributes}>
      <Show when={active}>
        <div className="table-cell-menu" onClick={handleClick}>
          <ReactIcon icon={menuIcon} className="table-cell-menu-icon" />
        </div>
      </Show>
      {children}
      <Show when={showMenu}>
        <Popup {...position.current} onClose={handleClick}>
          <List items={listItems.current} />
        </Popup>
      </Show>
    </td>
  );

The UI:

image

arpit016 commented 4 years ago

@stevez86 Were you able to implement some workaround to prevent this as of now? I am also facing the same issue

davidcalhoun commented 4 years ago

Just got this now, and it blew up the entire editor as I was typing. I think it may be related to spellcheck and autocorrect. When I right click and accept an autocorrect suggestion, the new text gets dropped into place and I think the cursor loses focus or doesn't update properly, as it correctly does on keyUp. The error only happens when I have spellcheck="true" on the parent div.

The error:

Cannot resolve a DOM point from Slate point: {"path":[6,0],"offset":170}

Browser: Firefox 73.0 desktop, macOS 10.15.3

If folks are experiencing similar issues, I suggest turning off spellcheck/autocorrect features on a parent container and testing to see if that helps:

<div autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false">
  <Slate ... />
</div> 

To fix the issue in Slate, I think it requires tapping into a DOM event that gets fired on autocomplete. In Firefox this seems to be called DOMAutoComplete

johnpaul89 commented 4 years ago

3470

This issue is discussed here

andrew-aladev commented 4 years ago

All these issues are the same: users are trying to set new value without reseting internal selection. Slate editor have to use getDerivedStateFromProps and automatically fix or reset internal selection when new value appears (nextProps.value !== prevState.value).

These issues can be fixed by core developer of slate only, because it requires change of project design. Users can only try to reset selection in a any dirty way.

The easiest way to provide dirty hack is to find a special case which breaks internal selection and use it to recreate slate editor completely. For example:

static getDerivedStateFromProps (nextProps, prevState) {
  const result = {}

  if (nextProps.input.value !== prevState.value || ...) {
    result.value = nextProps.input.value
    result.document = getDocument(nextProps.input.value, ...)
  }

  if ((result.document == null && ...) || selectionWillBeBroken(prevState.document, result.document)) {
    result.editor = getEditor(...)
  }

  if (Object.keys(result).length !== 0) {
    return result
  }
  return null
}

render () {
  ...
  return (
    <Slate
      editor={editor}
      value={document}
      ...
  )
}