Skip to content

Commit

Permalink
fix: prevent a bug for node views when pressing enter on iOS, fix #1214
Browse files Browse the repository at this point in the history
  • Loading branch information
philippkuehn committed Apr 27, 2021
1 parent fb3990d commit 234d238
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 8 deletions.
45 changes: 37 additions & 8 deletions packages/core/src/NodeView.ts
Expand Up @@ -3,6 +3,7 @@ import { NodeSelection } from 'prosemirror-state'
import { Node as ProseMirrorNode } from 'prosemirror-model'
import { Editor as CoreEditor } from './Editor'
import { Node } from './Node'
import isiOS from './utilities/isiOS'
import { NodeViewRendererProps } from './types'

interface NodeViewRendererOptions {
Expand Down Expand Up @@ -176,22 +177,50 @@ export class NodeView<Component, Editor extends CoreEditor = CoreEditor> impleme
}

ignoreMutation(mutation: MutationRecord | { type: 'selection', target: Element }) {
if (mutation.type === 'selection') {
if (this.node.isLeaf) {
return true
}
if (!this.dom || !this.contentDOM) {
return true
}

// a leaf/atom node is like a black box for ProseMirror
// and should be fully handled by the node view
if (this.node.isLeaf) {
return true
}

// ProseMirror should handle any selections
if (mutation.type === 'selection') {
return false
}

if (!this.contentDOM) {
// try to prevent a bug on iOS that will break node views on enter
// this is because ProseMirror can’t preventDispatch on enter
// this will lead to a re-render of the node view on enter
// see: https://github.com/ueberdosis/tiptap/issues/1214
if (this.dom.contains(mutation.target) && mutation.type === 'childList' && isiOS()) {
const changedNodes = [
...Array.from(mutation.addedNodes),
...Array.from(mutation.removedNodes),
] as HTMLElement[]

// we’ll check if every changed node is contentEditable
// to make sure it’s probably mutated by ProseMirror
if (changedNodes.every(node => node.isContentEditable)) {
return false
}
}

// we will allow mutation contentDOM with attributes
// so we can for example adding classes within our node view
if (this.contentDOM === mutation.target && mutation.type === 'attributes') {
return true
}

const contentDOMHasChanged = !this.contentDOM.contains(mutation.target)
|| (this.contentDOM === mutation.target && mutation.type === 'attributes')
// ProseMirror should handle any changes within contentDOM
if (this.contentDOM.contains(mutation.target)) {
return false
}

return contentDOMHasChanged
return true
}

updateAttributes(attributes: {}) {
Expand Down
12 changes: 12 additions & 0 deletions packages/core/src/utilities/isiOS.ts
@@ -0,0 +1,12 @@
export default function isiOS(): boolean {
return [
'iPad Simulator',
'iPhone Simulator',
'iPod Simulator',
'iPad',
'iPhone',
'iPod',
].includes(navigator.platform)
// iPad on iOS 13 detection
|| (navigator.userAgent.includes('Mac') && 'ontouchend' in document)
}

0 comments on commit 234d238

Please sign in to comment.