|
@@ -16,7 +16,7 @@ import {
|
|
|
type CodeBlockNavigationDelegate,
|
|
type CodeBlockNavigationDelegate,
|
|
|
CodeBlockView,
|
|
CodeBlockView,
|
|
|
} from "@/composables/useCodeBlockView"
|
|
} from "@/composables/useCodeBlockView"
|
|
|
-import type { FocusRegistry } from "@/composables/useFocusRegistry"
|
|
|
|
|
|
|
+import type { FocusPosition, FocusRegistry } from "@/composables/useFocusRegistry"
|
|
|
import {
|
|
import {
|
|
|
createMarkdownDecorationsPlugin,
|
|
createMarkdownDecorationsPlugin,
|
|
|
type MarkerVisibilityMode,
|
|
type MarkerVisibilityMode,
|
|
@@ -66,7 +66,7 @@ const content = defineModel<string>("content")
|
|
|
const props = defineProps<{
|
|
const props = defineProps<{
|
|
|
id?: string
|
|
id?: string
|
|
|
focused?: boolean
|
|
focused?: boolean
|
|
|
- cursorPosition?: "start" | "end" | number
|
|
|
|
|
|
|
+ cursorPosition?: FocusPosition
|
|
|
markerMode?: MarkerVisibilityMode
|
|
markerMode?: MarkerVisibilityMode
|
|
|
debug?: string
|
|
debug?: string
|
|
|
registry?: FocusRegistry
|
|
registry?: FocusRegistry
|
|
@@ -85,8 +85,8 @@ const emit = defineEmits<{
|
|
|
indent: []
|
|
indent: []
|
|
|
outdent: []
|
|
outdent: []
|
|
|
"delete-if-empty": []
|
|
"delete-if-empty": []
|
|
|
- "arrow-up-from-start": []
|
|
|
|
|
- "arrow-down-from-end": []
|
|
|
|
|
|
|
+ "arrow-up-from-start": [leftOffset?: number]
|
|
|
|
|
+ "arrow-down-from-end": [leftOffset?: number]
|
|
|
"pattern-open": [payload: PatternOpenPayload]
|
|
"pattern-open": [payload: PatternOpenPayload]
|
|
|
"pattern-update": [payload: PatternUpdatePayload]
|
|
"pattern-update": [payload: PatternUpdatePayload]
|
|
|
"pattern-close": [PatternClosePayload]
|
|
"pattern-close": [PatternClosePayload]
|
|
@@ -111,8 +111,8 @@ const handleKeyDown = createBlockKeyboardHandler({
|
|
|
"delete-if-empty": () => emit("delete-if-empty"),
|
|
"delete-if-empty": () => emit("delete-if-empty"),
|
|
|
indent: () => emit("indent"),
|
|
indent: () => emit("indent"),
|
|
|
outdent: () => emit("outdent"),
|
|
outdent: () => emit("outdent"),
|
|
|
- "arrow-up-from-start": () => emit("arrow-up-from-start"),
|
|
|
|
|
- "arrow-down-from-end": () => emit("arrow-down-from-end"),
|
|
|
|
|
|
|
+ "arrow-up-from-start": (leftOffset) => emit("arrow-up-from-start", leftOffset),
|
|
|
|
|
+ "arrow-down-from-end": (leftOffset) => emit("arrow-down-from-end", leftOffset),
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
function handlerWithRefocus(fn: (view: EditorView) => void) {
|
|
function handlerWithRefocus(fn: (view: EditorView) => void) {
|
|
@@ -188,7 +188,7 @@ const patternPlugin = createPatternPlugin({
|
|
|
onPatternClose: (payload) => emit("pattern-close", payload),
|
|
onPatternClose: (payload) => emit("pattern-close", payload),
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
-function focusAt(cursorPosition?: "start" | "end" | number) {
|
|
|
|
|
|
|
+function focusAt(cursorPosition?: FocusPosition) {
|
|
|
if (!view) return
|
|
if (!view) return
|
|
|
const doc = view.state.doc
|
|
const doc = view.state.doc
|
|
|
|
|
|
|
@@ -199,6 +199,28 @@ function focusAt(cursorPosition?: "start" | "end" | number) {
|
|
|
v.dispatch(v.state.tr.setSelection(safeSelection))
|
|
v.dispatch(v.state.tr.setSelection(safeSelection))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // Coordinate-based focus: resolve screen X to a document position
|
|
|
|
|
+ // for column-preserving block-to-block navigation.
|
|
|
|
|
+ if (cursorPosition && typeof cursorPosition === "object" && "left" in cursorPosition) {
|
|
|
|
|
+ v.focus()
|
|
|
|
|
+ requestAnimationFrame(() => {
|
|
|
|
|
+ if (!view) return
|
|
|
|
|
+ const rect = view.dom.getBoundingClientRect()
|
|
|
|
|
+ const targetY =
|
|
|
|
|
+ cursorPosition.edge === "top" ? rect.top + 5 : rect.bottom - 5
|
|
|
|
|
+ const pos = view.posAtCoords({
|
|
|
|
|
+ left: cursorPosition.left,
|
|
|
|
|
+ top: targetY,
|
|
|
|
|
+ })
|
|
|
|
|
+ if (pos) {
|
|
|
|
|
+ setSafeSelection(pos.pos)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setSafeSelection(cursorPosition.edge === "top" ? 1 : Math.max(1, doc.content.size - 1))
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (cursorPosition === "start") {
|
|
if (cursorPosition === "start") {
|
|
|
if (doc.content.size > 0) {
|
|
if (doc.content.size > 0) {
|
|
|
setSafeSelection(1)
|
|
setSafeSelection(1)
|