Skip to content

Commit

Permalink
Add EditorView.scrollHandler
Browse files Browse the repository at this point in the history
FEATURE: The `EditorView.scrollHandler` facet can be used to override or extend
the behavior of the editor when things are scrolled into view.

Issue codemirror/dev#1355
  • Loading branch information
marijnh committed Mar 14, 2024
1 parent 1c0a088 commit 1ecb5f1
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 2 deletions.
7 changes: 6 additions & 1 deletion src/docview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {getAttrs} from "./attributes"
import {clientRectsFor, isEquivalentPosition, maxOffset, Rect, scrollRectIntoView,
getSelection, hasSelection, textRange, DOMSelectionState} from "./dom"
import {ViewUpdate, decorations as decorationsFacet, outerDecorations,
ChangedRange, ScrollTarget, getScrollMargins} from "./extension"
ChangedRange, ScrollTarget, scrollHandler, getScrollMargins, logException} from "./extension"
import {EditorView} from "./editorview"
import {Direction} from "./bidi"

Expand Down Expand Up @@ -558,6 +558,11 @@ export class DocView extends ContentView {
return
}

for (let handler of this.view.state.facet(scrollHandler)) {
try { if (handler(this.view, target.range, target)) return true }
catch(e) { logException(this.view.state, e, "scroll handler") }
}

let {range} = target
let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other
if (!rect) return
Expand Down
8 changes: 7 additions & 1 deletion src/editorview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {ViewUpdate, styleModule,
exceptionSink, updateListener, logException,
viewPlugin, ViewPlugin, PluginValue, PluginInstance, decorations, outerDecorations, atomicRanges,
scrollMargins, MeasureRequest, editable, inputHandler, focusChangeEffect, perLineTextDirection,
scrollIntoView, UpdateFlag, ScrollTarget, bidiIsolatedRanges, getIsolatedRanges} from "./extension"
scrollIntoView, UpdateFlag, ScrollTarget, bidiIsolatedRanges, getIsolatedRanges, scrollHandler} from "./extension"
import {theme, darkTheme, buildTheme, baseThemeID, baseLightID, baseDarkID, lightDarkIDs, baseTheme} from "./theme"
import {DOMObserver} from "./domobserver"
import {Attrs, updateAttrs, combineAttrs} from "./attributes"
Expand Down Expand Up @@ -945,6 +945,12 @@ export class EditorView {
/// dispatching the custom behavior as a separate transaction.
static inputHandler = inputHandler

/// Scroll handlers can override how things are scrolled into view.
/// If they return `true`, no further handling happens for the
/// scrolling. If they return false, the default scroll behavior is
/// applied. Scroll handlers should never initiate editor updates.
static scrollHandler = scrollHandler

/// This facet can be used to provide functions that create effects
/// to be dispatched when the editor's focus state changes.
static focusChangeEffect = focusChangeEffect
Expand Down
6 changes: 6 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ export const nativeSelectionHidden = Facet.define<boolean, boolean>({
combine: values => values.some(x => x)
})

export const scrollHandler = Facet.define<(
view: EditorView,
range: SelectionRange,
options: {x: ScrollStrategy, y: ScrollStrategy, xMargin: number, yMargin: number}
) => boolean>()

export class ScrollTarget {
constructor(
readonly range: SelectionRange,
Expand Down

0 comments on commit 1ecb5f1

Please sign in to comment.