Repository: ianstormtaylor/slate
File: packages/slate/src/transforms/general.ts (TypeScript)

Code before:
      const parent = Node.parent(editor, path)
      parent.children.splice(index, 1)

      // Transform all of the points in the value, but if the point was in the
      // node that was removed we need to update the range or remove it.
      if (selection) {
        for (const [point, key] of Range.points(selection)) {
          const result = Point.transform(point, op)

          if (selection != null && result != null) {
            selection[key] = result
          } else {
            let prev: NodeEntry<Text> | undefined
            let next: NodeEntry<Text> | undefined

            for (const [n, p] of Node.texts(editor)) {
              if (Path.compare(p, path) === -1) {
                prev = [n, p]
              } else {
                next = [n, p]
                break
              }
            }

            const preferNext =
              prev && next && Path.common(prev[1], path).length === 0

            if (prev && !preferNext) {
              point.path = prev[1]
              point.offset = prev[0].text.length
            } else if (next) {
              point.path = next[1]
              point.offset = 0
            } else {
              selection = null
            }
          }
        }
      }

      break
    }

    case 'remove_text': {
      const { path, offset, text } = op
      if (text.length === 0) break
      const node = Node.leaf(editor, path)
      const before = node.text.slice(0, offset)
      const after = node.text.slice(offset + text.length)
      node.text = before + after


Review comment (bug):
this seems too conservative; it works only when there is no common ancestor. So e.g. if you wrap another `block` around the test cases they fail; it doesn't seem like this is what you are trying to achieve.

I tried to generalize `preferNext` in a few different ways to produce the desired behavior deeper in the tree, but it caused some other tests to fail for various reasons.

I wonder if this is too low-level a place to implement selection behavior. Higher-level functions have more information about what's happening and can do a better job of leaving the selection in the expected place.

Maybe you could try to fix it in `mergeNodes`, since that's the original problem you're trying to solve?

Code after:
      const parent = Node.parent(editor, path)
      parent.children.splice(index, 1)

      // Transform all of the points in the value, but if the point was in the
      // node that was removed we need to update the range or remove it.
      if (selection) {
        for (const [point, key] of Range.points(selection)) {
          const result = Point.transform(point, op)

          if (selection != null && result != null) {
            selection[key] = result
          } else {
            let prev: NodeEntry<Text> | undefined
            let next: NodeEntry<Text> | undefined

            for (const [n, p] of Node.texts(editor)) {
              if (Path.compare(p, path) === -1) {
                prev = [n, p]
              } else {
                next = [n, p]
                break
              }
            }

            let preferNext = false
            if (prev && next) {
              if (Path.equals(next[1], path)) {
                preferNext = !Path.hasPrevious(next[1])
              } else {
                preferNext =
                  Path.common(prev[1], path).length <
                  Path.common(next[1], path).length
              }
            }

            if (prev && !preferNext) {
              point.path = prev[1]
              point.offset = prev[0].text.length
            } else if (next) {
              point.path = next[1]
              point.offset = 0
            } else {
              selection = null
            }
          }
        }
      }

      break
    }