|
| 1 | +import * as Cursors from "../Cursors" |
| 2 | +import * as Iterators from "../Iterators" |
| 3 | +import * as Spans from "../Spans" |
| 4 | +import dropCursors from "./dropCursors" |
| 5 | +import must from "lib/must" |
| 6 | + |
| 7 | +// Returns the next right-to-left (RTL) cursor for a |
| 8 | +// boundary. |
| 9 | +function nextRTLCursor(elements, { ...rtl }, boundary) { |
| 10 | + const y = must(elements.findIndex(each => each.key === rtl.key)) |
| 11 | + const substr = Spans.textContent(elements[y].props.children).slice(0, rtl.offset) |
| 12 | + if (!rtl.offset && y) { |
| 13 | + Object.assign(rtl, { |
| 14 | + key: elements[y - 1].key, |
| 15 | + offset: Spans.textContent(elements[y - 1].props.children).length, |
| 16 | + }) |
| 17 | + return rtl |
| 18 | + } |
| 19 | + const runes = Iterators.RTL[boundary](substr) |
| 20 | + rtl.offset -= runes.length |
| 21 | + return rtl |
| 22 | +} |
| 23 | + |
| 24 | +// Returns the next left-to-right (LTR) cursor. |
| 25 | +function nextLTRCursor(elements, { ...ltr }, boundary) { |
| 26 | + const y = must(elements.findIndex(each => each.key === ltr.key)) |
| 27 | + const substr = Spans.textContent(elements[y].props.children).slice(ltr.offset) |
| 28 | + if (ltr.offset === substr.length && y + 1 < elements.length) { |
| 29 | + Object.assign(ltr, { |
| 30 | + key: elements[y + 1].key, |
| 31 | + offset: Spans.textContent(elements[y + 1].props.children).length, |
| 32 | + }) |
| 33 | + return ltr |
| 34 | + } |
| 35 | + const runes = Iterators.LTR[boundary](substr) |
| 36 | + ltr.offset += runes.length |
| 37 | + return ltr |
| 38 | +} |
| 39 | + |
| 40 | +// Returns the next set of cursors for a direction and a |
| 41 | +// boundary. |
| 42 | +function nextCursors(elements, cursors, dir, boundary) { |
| 43 | + if (!cursors.collapsed) { |
| 44 | + return cursors |
| 45 | + } |
| 46 | + const next = {} |
| 47 | + if (dir === "rtl" && dir !== "ltr") { |
| 48 | + const rtl = nextRTLCursor(elements, cursors[0], boundary) |
| 49 | + Object.assign(next, { |
| 50 | + ...[rtl, cursors[0]], |
| 51 | + collapsed: Cursors.areEqual(rtl, cursors[0]), |
| 52 | + }) |
| 53 | + } else { |
| 54 | + const ltr = nextLTRCursor(elements, cursors[0], boundary) |
| 55 | + Object.assign(next, { |
| 56 | + ...[cursors[0], ltr], |
| 57 | + collapsed: Cursors.areEqual(cursors[0], ltr), |
| 58 | + }) |
| 59 | + } |
| 60 | + return next |
| 61 | +} |
| 62 | + |
| 63 | +// Backspace handler. Returns a collapsed set of cursors. |
| 64 | +// dir maps to "rtl" or "ltr" and boundary maps to "rune", |
| 65 | +// "word", or "line". |
| 66 | +function backspace(elements, cursors, dir, boundary) { |
| 67 | + const next = nextCursors(elements, cursors, dir, boundary) |
| 68 | + dropCursors(elements, next) |
| 69 | + return Cursors.collapse(next) |
| 70 | +} |
| 71 | + |
| 72 | +export default backspace |
0 commit comments