Fix emoji bug on the demo website
This commit is contained in:
parent
c566eb7ef6
commit
55e8177255
3 changed files with 37 additions and 10 deletions
|
|
@ -128,6 +128,24 @@ console.log(result.cursors); // [{ id: 2, position: 0 }, { id: 1, position: 3 }]
|
|||
|
||||
> The `cursors` list is sorted by character position (not IDs).
|
||||
|
||||
Input and output cursor positions count Unicode scalars (code points), starting
|
||||
at zero and allowing a position just after the last scalar. They do not count
|
||||
UTF-16 code units or grapheme clusters. For example, the position after `😀` is
|
||||
`1`, although JavaScript's `'😀'.length` is `2`.
|
||||
|
||||
DOM `selectionStart` and `selectionEnd` use UTF-16 code units. Convert both
|
||||
endpoints before passing a textarea selection to the library:
|
||||
|
||||
```typescript
|
||||
const edited = {
|
||||
text: textarea.value,
|
||||
cursors: [
|
||||
{ id: 1, position: [...textarea.value.slice(0, textarea.selectionStart)].length },
|
||||
{ id: 2, position: [...textarea.value.slice(0, textarea.selectionEnd)].length },
|
||||
],
|
||||
} satisfies TextWithOptionalCursors;
|
||||
```
|
||||
|
||||
## Generic Helpers and Inference
|
||||
|
||||
The exported merge functions are intentionally small: they merge strings, or
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { reconcileWithHistory } from 'reconcile-text';
|
||||
import type { BuiltinTokenizer } from 'reconcile-text';
|
||||
import type { BuiltinTokenizer, CursorPosition } from 'reconcile-text';
|
||||
import './style.scss';
|
||||
|
||||
const originalTextArea = document.getElementById('original') as HTMLTextAreaElement;
|
||||
|
|
@ -157,19 +157,22 @@ function getCursorsFromActiveTextArea() {
|
|||
let rightCursors = undefined;
|
||||
|
||||
if (activeElement === leftTextArea) {
|
||||
leftCursors = [
|
||||
{ id: 1, position: leftTextArea.selectionStart },
|
||||
{ id: 2, position: leftTextArea.selectionEnd },
|
||||
];
|
||||
leftCursors = getSelectionCursors(leftTextArea);
|
||||
} else if (activeElement === rightTextArea) {
|
||||
rightCursors = [
|
||||
{ id: 1, position: rightTextArea.selectionStart },
|
||||
{ id: 2, position: rightTextArea.selectionEnd },
|
||||
];
|
||||
rightCursors = getSelectionCursors(rightTextArea);
|
||||
}
|
||||
return { leftCursors, rightCursors };
|
||||
}
|
||||
|
||||
function getSelectionCursors(textarea: HTMLTextAreaElement): CursorPosition[] {
|
||||
const text = textarea.value;
|
||||
// DOM selections count UTF-16 code units; reconcile counts Unicode scalars.
|
||||
return [
|
||||
{ id: 1, position: [...text.slice(0, textarea.selectionStart)].length },
|
||||
{ id: 2, position: [...text.slice(0, textarea.selectionEnd)].length },
|
||||
];
|
||||
}
|
||||
|
||||
function createSelectionOverlay(isLeft: boolean, isSelection: boolean): HTMLSpanElement {
|
||||
const caretSpan = document.createElement('span');
|
||||
caretSpan.className = `selection-caret selection-caret-${isLeft ? 'left' : 'right'}`;
|
||||
|
|
|
|||
|
|
@ -136,7 +136,13 @@ export interface CursorPosition {
|
|||
/** Unique identifier for the cursor (can be any number, must be unique within the document) */
|
||||
id: number;
|
||||
|
||||
/** Character position in the text, 0-based index from the beginning of the document */
|
||||
/**
|
||||
* Zero-based offset in Unicode scalars (code points), from 0 through
|
||||
* `[...text].length` inclusive. Applies to both input and output cursors.
|
||||
* These are not UTF-16 code units or grapheme clusters: `😀` counts as one.
|
||||
* Convert DOM selectionStart/selectionEnd offsets before passing them in:
|
||||
* `[...text.slice(0, offset)].length`.
|
||||
*/
|
||||
position: number;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue