Skip to content

Instantly share code, notes, and snippets.

@mhr
Last active February 21, 2021 23:13
Show Gist options
  • Save mhr/48cae869c0a3f7154e99a80175f09c20 to your computer and use it in GitHub Desktop.
Save mhr/48cae869c0a3f7154e99a80175f09c20 to your computer and use it in GitHub Desktop.
Focusing after click on margin in Slate.js editor
import React, { useMemo, useState } from "react";
import { createEditor, Transforms, Editor } from "slate";
import { Slate, Editable, withReact, ReactEditor } from "slate-react";
import { Box } from "@chakra-ui/react";
const App = () => {
const editor = useMemo(() => withReact(createEditor()), []);
const [value, setValue] = useState([
{
type: "paragraph",
children: [{ text: "A line of text in a paragraph." }],
},
{
type: "paragraph",
children: [{ text: "A line of text in a paragraph." }],
},
{
type: "paragraph",
children: [{ text: "A line of text in a paragraph." }],
},
{
type: "paragraph",
children: [{ text: "A line of text in a paragraph." }],
},
]);
// https://stackoverflow.com/a/31877959/1024501
function closestIndex(list, x) {
var min, chosen = 0;
for (var i in list) {
min = Math.abs(list[chosen] - x);
if (Math.abs(list[i] - x) < min) {
chosen = i;
}
}
return chosen;
}
return (
<Box margin="5px" padding="25px" w="500px" h="1000px" backgroundColor="tomato" cursor="text" onClick={
e => {
e.preventDefault();
if (!ReactEditor.isFocused(editor)) {
const [x, y] = [e.pageX, e.pageY];
let rects = [];
for (const child of editor.children) {
const el = ReactEditor.toDOMNode(editor, child);
const rect = el.getBoundingClientRect();
rects.push(rect);
}
let index = closestIndex(rects.map(rect => rect.top + rect.height/2), y);
let xDiff = Math.max(0, x - rects[index].left);
let domEditor = ReactEditor.toDOMNode(editor, editor)
let domEditorRect = domEditor.getBoundingClientRect();
let caretPositionX = Math.min(rects[index].left + xDiff + 1, domEditorRect.left + domEditorRect.width);
let caretPositionY = rects[index].top + rects[index].height/2;
let domRange;
let offset;
if (document.caretPositionFromPoint) {
domRange = document.caretPositionFromPoint(caretPositionX, caretPositionY);
offset = domRange.offset;
} else if (document.caretRangeFromPoint) {
domRange = document.caretRangeFromPoint(caretPositionX, caretPositionY);
offset = domRange.startOffset;
}
const range = ReactEditor.toSlateRange(editor, domRange);
ReactEditor.focus(editor);
Transforms.select(editor, range);
}
}>
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
<Editable />
</Slate>
</Box>
)
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment