Files
simple-react-app-kit/packages/lexical/src/plugins/selection-anchor.ts
T
Maofeng 0d817537be feat(lexical): add declarative rich text editor
Introduce @workspace/lexical with composable actions, toolbars, embeds, rich-text nodes, media uploads, selection utilities, HTML serialization, and theme styling.\n\nLocalize built-in controls through MessageDescriptor catalogs for English and Simplified Chinese, while providing an English I18nProvider fallback for standalone editor use. Include focused unit coverage for actions, controls, serialization, plugins, public API, and catalogs.
2026-07-31 15:07:09 +08:00

79 lines
2.0 KiB
TypeScript

import type { LexicalEditor } from "lexical"
export interface SelectionAnchor {
contextElement: HTMLElement
getBoundingClientRect: () => DOMRect
}
export function runWithEditorFocus(
editor: LexicalEditor,
callback: VoidFunction
) {
const rootElement = editor.getRootElement()
if (!rootElement) return
const document = rootElement.ownerDocument
const selection = document.defaultView?.getSelection()
const selectionIsInside =
selection?.focusNode != null && rootElement.contains(selection.focusNode)
const focusIsInside =
document.activeElement != null &&
rootElement.contains(document.activeElement)
if (selectionIsInside && focusIsInside) {
callback()
return
}
editor.focus(callback)
}
export function createSelectionAnchor(
rootElement: HTMLElement
): HTMLElement | SelectionAnchor {
const document = rootElement.ownerDocument
const domSelection = document.defaultView?.getSelection()
const focusNode = domSelection?.focusNode
let range: Range | null = null
if (focusNode && rootElement.contains(focusNode)) {
try {
range = document.createRange()
range.setStart(focusNode, domSelection.focusOffset)
range.collapse(true)
} catch {
range = null
}
}
if (!range) return rootElement
const selectionRange = range
return {
contextElement: rootElement,
getBoundingClientRect: () => {
const rangeRect =
typeof selectionRange.getBoundingClientRect === "function"
? selectionRange.getBoundingClientRect()
: null
if (
rangeRect &&
(rangeRect.width > 0 ||
rangeRect.height > 0 ||
rangeRect.x !== 0 ||
rangeRect.y !== 0)
) {
return rangeRect
}
const clientRects =
typeof selectionRange.getClientRects === "function"
? Array.from(selectionRange.getClientRects())
: []
return clientRects.at(-1) ?? rootElement.getBoundingClientRect()
},
}
}