Skip to content

Commit dd56733

Browse files
authored
fix(bundle): scroll to current line after moving cursor in markup mode (#313)
1 parent b904704 commit dd56733

File tree

3 files changed

+123
-65
lines changed

3 files changed

+123
-65
lines changed

demo/Playground.scss

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,18 @@
4242
top: 8px;
4343
left: 8px;
4444
}
45+
46+
&__actions {
47+
display: flex;
48+
gap: 8px;
49+
}
50+
51+
&__move-to-line {
52+
display: flex;
53+
column-gap: 4px;
54+
}
55+
56+
&__move-to-line-input {
57+
width: 56px;
58+
}
4559
}

demo/Playground.tsx

Lines changed: 90 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {CSSProperties, useCallback, useEffect} from 'react';
1+
import React, {CSSProperties, useCallback, useEffect, useState} from 'react';
22

33
import sanitize from '@diplodoc/transform/lib/sanitize';
44
import {Button, DropdownMenu} from '@gravity-ui/uikit';
@@ -8,6 +8,7 @@ import {
88
MarkdownEditorMode,
99
MarkdownEditorView,
1010
MarkupString,
11+
NumberInput,
1112
RenderPreview,
1213
logger,
1314
markupToolbarConfigs,
@@ -220,64 +221,75 @@ export const Playground = React.memo<PlaygroundProps>((props) => {
220221
Markdown Editor Playground
221222
<span className={b('version')}>{VERSION}</span>
222223
</div>
223-
<DropdownMenu
224-
size="s"
225-
switcher={
226-
<Button size="s" view="flat">
227-
isEmpty: {String(mdEditor.isEmpty())}
228-
</Button>
229-
}
230-
>
231-
<DropdownMenu.Item
232-
text="Clear"
233-
action={() => {
234-
mdEditor.clear();
235-
mdEditor.focus();
236-
}}
237-
/>
238-
<DropdownMenu.Item
239-
text="Append"
240-
action={() => {
241-
mdEditor.append('> append');
242-
mdEditor.focus();
243-
}}
244-
/>
245-
<DropdownMenu.Item
246-
text="Prepend"
247-
action={() => {
248-
mdEditor.prepend('> prepend');
249-
mdEditor.focus();
250-
}}
251-
/>
252-
<DropdownMenu.Item
253-
text="Replace"
254-
action={() => {
255-
mdEditor.replace('> replace');
256-
mdEditor.focus();
257-
}}
258-
/>
259-
<DropdownMenu.Item
260-
text="Move cursor to start"
261-
action={() => {
262-
mdEditor.moveCursor('start');
263-
mdEditor.focus();
264-
}}
265-
/>
266-
<DropdownMenu.Item
267-
text="Move cursor to end"
268-
action={() => {
269-
mdEditor.moveCursor('end');
270-
mdEditor.focus();
271-
}}
272-
/>
273-
<DropdownMenu.Item
274-
text="Move to line"
275-
action={() => {
276-
mdEditor.moveCursor({line: 115});
277-
mdEditor.focus();
278-
}}
279-
/>
280-
</DropdownMenu>
224+
<div className={b('actions')}>
225+
<DropdownMenu
226+
size="s"
227+
switcher={
228+
<Button size="s" view="flat">
229+
isEmpty: {String(mdEditor.isEmpty())}
230+
</Button>
231+
}
232+
>
233+
<DropdownMenu.Item
234+
text="Clear"
235+
action={() => {
236+
mdEditor.clear();
237+
mdEditor.focus();
238+
}}
239+
/>
240+
<DropdownMenu.Item
241+
text="Append"
242+
action={() => {
243+
mdEditor.append('> append');
244+
mdEditor.focus();
245+
}}
246+
/>
247+
<DropdownMenu.Item
248+
text="Prepend"
249+
action={() => {
250+
mdEditor.prepend('> prepend');
251+
mdEditor.focus();
252+
}}
253+
/>
254+
<DropdownMenu.Item
255+
text="Replace"
256+
action={() => {
257+
mdEditor.replace('> replace');
258+
mdEditor.focus();
259+
}}
260+
/>
261+
<DropdownMenu.Item
262+
text="Move cursor to start"
263+
action={() => {
264+
mdEditor.moveCursor('start');
265+
mdEditor.focus();
266+
}}
267+
/>
268+
<DropdownMenu.Item
269+
text="Move cursor to end"
270+
action={() => {
271+
mdEditor.moveCursor('end');
272+
mdEditor.focus();
273+
}}
274+
/>
275+
<DropdownMenu.Item
276+
text="Move to line"
277+
action={() => {
278+
mdEditor.moveCursor({line: 115});
279+
mdEditor.focus();
280+
}}
281+
/>
282+
</DropdownMenu>
283+
{mdEditor.currentMode === 'markup' && (
284+
<MoveToLine
285+
onClick={(line) => {
286+
if (typeof line !== 'number' || Number.isNaN(line)) return;
287+
mdEditor.moveCursor({line});
288+
mdEditor.focus();
289+
}}
290+
/>
291+
)}
292+
</div>
281293
<hr />
282294
<React.StrictMode>
283295
<div className={b('editor')} style={{height: height ?? 'initial'}}>
@@ -306,3 +318,22 @@ export const Playground = React.memo<PlaygroundProps>((props) => {
306318
});
307319

308320
Playground.displayName = 'Playground';
321+
322+
function MoveToLine({onClick}: {onClick: (value: number | undefined) => void}) {
323+
const [line, setLine] = useState<number | undefined>(0);
324+
325+
return (
326+
<div className={b('move-to-line')}>
327+
<NumberInput
328+
size="s"
329+
value={line}
330+
onUpdate={setLine}
331+
min={0}
332+
className={b('move-to-line-input')}
333+
/>
334+
<Button size="s" onClick={() => onClick(line)}>
335+
Move to line
336+
</Button>
337+
</div>
338+
);
339+
}

src/bundle/Editor.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -401,24 +401,37 @@ export class EditorImpl extends SafeEventEmitter<EventMapInt> implements EditorI
401401
return this.currentEditor.append(markup);
402402
}
403403

404-
moveCursor(position: 'start' | 'end' | {line: number}): void {
404+
moveCursor(
405+
position:
406+
| 'start'
407+
| 'end'
408+
| {
409+
/** 0-based line number */
410+
line: number;
411+
},
412+
): void {
405413
if (typeof position === 'object') {
406414
return this.moveCursorToLine(position.line);
407415
}
408416

409417
return this.currentEditor.moveCursor(position);
410418
}
411419

412-
private moveCursorToLine(line: number): void {
420+
private moveCursorToLine(/** 0-based line number */ line: number): void {
413421
const mode = this.currentMode;
414422

415423
switch (mode) {
416424
case 'markup': {
417-
const lineNumber = line + 1;
418425
const view = this.markupEditor.cm;
419-
if (lineNumber > 0 && lineNumber <= view.state.doc.lines) {
420-
view.dispatch({selection: {anchor: view.state.doc.line(lineNumber).from}});
421-
}
426+
427+
let cmLine = line + 1; // lines in codemirror is 1-based
428+
cmLine = Math.max(cmLine, 1);
429+
cmLine = Math.min(cmLine, view.state.doc.lines);
430+
431+
view.dispatch({
432+
scrollIntoView: true,
433+
selection: {anchor: view.state.doc.line(cmLine).from},
434+
});
422435

423436
break;
424437
}

0 commit comments

Comments
 (0)