|
1 | 1 | import type {ReactNode} from 'react'; |
2 | 2 |
|
3 | 3 | import type {Extension as CodemirrorExtension} from '@codemirror/state'; |
| 4 | +import {EditorView as CMEditorView} from '@codemirror/view'; |
4 | 5 | import {TextSelection} from 'prosemirror-state'; |
5 | 6 | import {EditorView as PMEditorView} from 'prosemirror-view'; |
6 | 7 |
|
@@ -477,12 +478,33 @@ export class EditorImpl extends SafeEventEmitter<EventMapInt> implements EditorI |
477 | 478 | cmLine = Math.max(cmLine, 1); |
478 | 479 | cmLine = Math.min(cmLine, view.state.doc.lines); |
479 | 480 |
|
| 481 | + const yMargin = getTopOffset(); |
| 482 | + const anchor = view.state.doc.line(cmLine).from; |
480 | 483 | view.dispatch({ |
481 | 484 | scrollIntoView: true, |
482 | | - selection: {anchor: view.state.doc.line(cmLine).from}, |
| 485 | + selection: {anchor}, |
| 486 | + effects: [ |
| 487 | + CMEditorView.scrollIntoView(anchor, {y: 'start', x: 'start', yMargin}), |
| 488 | + ], |
483 | 489 | }); |
484 | 490 |
|
485 | 491 | break; |
| 492 | + |
| 493 | + // eslint-disable-next-line no-inner-declarations |
| 494 | + function getTopOffset() { |
| 495 | + const TOOLBAR_HEIGHT = 36; //px |
| 496 | + const TOOLBAR_BOTTOM_OFFSET = 8; // px |
| 497 | + const TOOLBAR_TOP_ADDITIONAL_OFFSET = 8; // px |
| 498 | + const TOOLBAR_TOP_OFFSET_VAR = '--g-md-toolbar-sticky-offset'; |
| 499 | + |
| 500 | + const topOffsetValue = window |
| 501 | + .getComputedStyle(view.dom) |
| 502 | + .getPropertyValue(TOOLBAR_TOP_OFFSET_VAR); |
| 503 | + const toolbarTopOffset = |
| 504 | + calculateCSSNumberValue(topOffsetValue) + TOOLBAR_TOP_ADDITIONAL_OFFSET; |
| 505 | + |
| 506 | + return toolbarTopOffset + TOOLBAR_HEIGHT + TOOLBAR_BOTTOM_OFFSET; |
| 507 | + } |
486 | 508 | } |
487 | 509 | case 'wysiwyg': { |
488 | 510 | const node = this.wysiwygEditor.dom.querySelector(`[data-line="${line}"]`); |
@@ -512,3 +534,17 @@ export class EditorImpl extends SafeEventEmitter<EventMapInt> implements EditorI |
512 | 534 | return serializedEditorMarkup?.trim() !== wysiwygValue.trim(); |
513 | 535 | } |
514 | 536 | } |
| 537 | + |
| 538 | +function calculateCSSNumberValue(cssValue: string): number { |
| 539 | + const tmp = document.createElement('div'); |
| 540 | + tmp.style.position = 'absolute'; |
| 541 | + tmp.style.top = '-99999px'; |
| 542 | + tmp.style.left = '-99999px'; |
| 543 | + tmp.style.width = `calc(${cssValue})`; |
| 544 | + |
| 545 | + document.body.appendChild(tmp); |
| 546 | + const value = tmp.getBoundingClientRect().width; |
| 547 | + tmp.remove(); |
| 548 | + |
| 549 | + return value; |
| 550 | +} |
0 commit comments