[英]Keeping caret position in a visible position in text input - firefox misbehaves
[英]Cant select text, cant position caret in Firefox - Slatejs
描述
僅在 Firefox 中的 Slatejs 編輯器因文本選擇和插入符號定位(通過鼠標)而失敗。 它總是在第一個字符之前選擇位置(路徑 [0] 偏移 [0])。 您仍然可以使用鍵盤來選擇文本和位置插入符號。
記錄
期待
它應該像在其他瀏覽器中一樣選擇文本並定位插入符號。
環境
編輯器實現供參考
import React, { useCallback, useMemo, useState } from "react";
import {
BaseEditor,
createEditor,
Descendant,
Editor,
Element as SlateElement,
Node,
Text,
Transforms
} from "slate";
import { Slate, Editable, ReactEditor, withReact } from "slate-react";
import { HistoryEditor, withHistory } from "slate-history";
export type CustomEditor = BaseEditor & ReactEditor & HistoryEditor
export type ParagraphElement = {
type: 'paragraph'
children: CustomText[]
}
export type TitleElement = {
type: "title"
children: CustomText[]
}
type CustomElement = ParagraphElement | TitleElement;
type FormattedText = { text: string, bold?: true };
type CustomText = FormattedText;
declare module "slate" {
interface CustomTypes {
Editor: CustomEditor
Element: CustomElement
Text: FormattedText
}
}
////////////////////////////////////
// Custom helpers
////////////////////////////////////
const customEditor = {
isBoldMarkActive(editor: CustomEditor) {
const [match] = Editor.nodes(editor, {
match: (n: any) => n.bold === true,
universal: true,
})
return !!match
},
isTitleActive(editor: CustomEditor) {
const [match] = Editor.nodes(editor, {
match: (n: any) => n.type === "title",
})
return !!match
},
toggleBoldMark(editor: CustomEditor) {
const isActive = customEditor.isBoldMarkActive(editor)
Transforms.setNodes(
editor,
{ bold: isActive ? undefined : true },
{ match: n => Text.isText(n), split: true }
)
},
toggleTitle(editor: CustomEditor) {
const isActive = customEditor.isTitleActive(editor)
Transforms.setNodes(
editor,
{ type: isActive ? undefined : "title" },
{ match: n => Editor.isBlock(editor, n) }
)
},
}
////////////////////////////////////
// Forced layout setup - title + paragraph
////////////////////////////////////
const withLayout = (editor: CustomEditor) => {
const { normalizeNode } = editor
editor.normalizeNode = ([node, path]) => {
if (path.length === 0) {
if (editor.children.length < 1) {
const title: TitleElement = {
type: "title",
children: [{ text: 'Untitled' }],
}
Transforms.insertNodes(editor, title, { at: path.concat(0) })
}
if (editor.children.length < 2) {
const paragraph: ParagraphElement = {
type: 'paragraph',
children: [{ text: '' }],
}
Transforms.insertNodes(editor, paragraph, { at: path.concat(1) })
}
for (const [child, childPath] of Node.children(editor, path)) {
const type = childPath[0] === 0 ? "title" : 'paragraph'
if (SlateElement.isElement(child) && child.type !== type) {
const newProperties: Partial<SlateElement> = { type }
Transforms.setNodes(editor, newProperties, { at: childPath })
}
}
}
return normalizeNode([node, path]);
}
return editor;
}
////////////////////////////////////
const TextEditor = () => {
const initialValue: Descendant[] = [
{
type: 'title',
children: [{ text: 'Enter a title...' }],
},
{
type: 'paragraph',
children: [{ text: 'Enter your question'}]
}
];
const editor = useMemo(() => withLayout(withHistory(withReact(createEditor()))), []);
Transforms.deselect(editor);
const [value, setValue] = useState<Descendant[]>(initialValue);
const renderElement = useCallback((props) => <Element {...props} />, [])
// Define a leaf rendering function that is memoized with `useCallback`.
const renderLeaf = useCallback((props) => {
return <Leaf {...props} />
}, []);
return (
// Add the editable component inside the context.
<Slate
editor={editor}
value={value}
onChange={(value) => setValue(value)}
>
<div>
<button
onMouseDown={event => {
event.preventDefault()
customEditor.toggleBoldMark(editor)
}}
>
B
</button>
<button
onMouseDown={event => {
event.preventDefault()
customEditor.toggleTitle(editor)
}}
>
H2
</button>
</div>
<Editable
renderElement={renderElement}
autoFocus
renderLeaf={renderLeaf}
/>
</Slate>
)
}
export default TextEditor
// Define a React component to render leaves with bold text.
const Leaf = (props: any) => {
return (
<span
{...props.attributes}
style={{ fontWeight: props.leaf.bold ? 'bold' : 'normal' }}
>
{props.children}
</span>
)
}
const Element = ({ attributes, children, element }: any) => {
switch (element.type) {
case 'title':
return <h2 {...attributes}>{children}</h2>
case 'paragraph':
return <p {...attributes}>{children}</p>
default:
return <p {...attributes}>{children}</p>
}
}
任何想法可能導致它?
愚蠢的錯誤。 我的 CSS 重置文件包含:“用戶選擇:無”,Chrome 以某種方式忽略了該文件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.