Skip to content

Commit 2d7fc56

Browse files
committed
feat: add enableScroll props.
1 parent a5ec933 commit 2d7fc56

File tree

5 files changed

+68
-6
lines changed

5 files changed

+68
-6
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,8 @@ export interface IMarkdownEditor extends ReactCodeMirrorProps {
246246
renderPreview?: (props: MarkdownPreviewProps, initVisible: boolean) => React.ReactNode;
247247
/** Preview expanded width @default `50%` */
248248
previewWidth?: string;
249+
/** Whether to enable scrolling */
250+
enableScroll?: boolean;
249251
/** Tool display settings. */
250252
toolbars?: IToolBarProps['toolbars'];
251253
/** The tool on the right shows the settings. */

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@
4343
"dependencies": {
4444
"@codemirror/lang-markdown": "^6.0.0",
4545
"@codemirror/language-data": "^6.1.0",
46-
"@uiw/codemirror-themes": "^4.10.4",
47-
"@uiw/react-codemirror": "^4.10.4",
46+
"@uiw/codemirror-extensions-events": "^4.12.3",
47+
"@uiw/codemirror-themes": "^4.12.3",
48+
"@uiw/react-codemirror": "^4.12.3",
4849
"@uiw/react-markdown-preview": "^4.0.20"
4950
},
5051
"devDependencies": {

src/commands/todo.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,14 @@ export const todo: ICommand = {
55
keyCommand: 'todo',
66
button: { 'aria-label': 'Add todo List' },
77
icon: (
8-
<svg fill="currentColor" viewBox="0 0 512 512" height="14" width="14">
9-
<path d="M152.1 38.16c9.8 8.87 10.6 24.04 1.7 33.9L81.84 152.1c-4.41 4.8-10.63 7.7-17.21 7-6.58 1.1-12.94-1.5-17.6-7l-40.001-40c-9.372-8.5-9.372-23.7 0-33.07 9.371-9.37 24.571-9.37 33.941 0l22.11 22.07 55.12-61.16c8.8-9.85 24-10.65 33.9-1.78zm0 160.04c9.8 8.8 10.6 24 1.7 33.9l-71.96 80c-4.41 4.8-10.63 7.7-17.21 7-6.58 1.1-12.94-1.5-17.6-7l-40.001-40c-9.372-8.5-9.372-23.7 0-33.1 9.371-9.3 24.571-9.3 33.941 0l22.11 22.1 55.12-61.2c8.8-9.8 24-10.6 33.9-1.7zM224 96c0-17.67 14.3-32 32-32h224c17.7 0 32 14.33 32 32 0 17.7-14.3 32-32 32H256c-17.7 0-32-14.3-32-32zm0 160c0-17.7 14.3-32 32-32h224c17.7 0 32 14.3 32 32s-14.3 32-32 32H256c-17.7 0-32-14.3-32-32zm-64 160c0-17.7 14.3-32 32-32h288c17.7 0 32 14.3 32 32s-14.3 32-32 32H192c-17.7 0-32-14.3-32-32zM0 416c0-26.5 21.49-48 48-48s48 21.5 48 48-21.49 48-48 48-48-21.5-48-48z" />
8+
<svg viewBox="0 0 48 48" fill="none" height="15" width="15">
9+
<path
10+
d="m5 10 3 3 6-6M5 24l3 3 6-6M5 38l3 3 6-6m7-11h22M21 38h22M21 10h22"
11+
stroke="currentColor"
12+
strokeWidth="5"
13+
strokeLinecap="round"
14+
strokeLinejoin="round"
15+
/>
1016
</svg>
1117
),
1218
execute: ({ state, view }) => {

src/index.tsx

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import React, { useState, useRef, useImperativeHandle, Fragment } from 'react';
1+
import React, { useState, useRef, useImperativeHandle, Fragment, useEffect, useCallback } from 'react';
22
import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
33
import { languages } from '@codemirror/language-data';
44
import { EditorView, ViewUpdate } from '@codemirror/view';
5+
import * as events from '@uiw/codemirror-extensions-events';
56
import CodeMirror, { ReactCodeMirrorProps, ReactCodeMirrorRef } from '@uiw/react-codemirror';
67
import MarkdownPreview, { MarkdownPreviewProps } from '@uiw/react-markdown-preview';
78
import ToolBar, { IToolBarProps } from './components/ToolBar';
@@ -32,6 +33,8 @@ export interface IMarkdownEditor extends ReactCodeMirrorProps {
3233
renderPreview?: (props: MarkdownPreviewProps, initVisible: boolean) => React.ReactNode;
3334
/** Preview expanded width @default `50%` */
3435
previewWidth?: string;
36+
/** Whether to enable scrolling */
37+
enableScroll?: boolean;
3538
/** Tool display settings. */
3639
toolbars?: IToolBarProps['toolbars'];
3740
/** The tool on the right shows the settings. */
@@ -86,6 +89,7 @@ function MarkdownEditorInternal(
8689
visibleEditor = true,
8790
hideToolbar = true,
8891
toolbarBottom = false,
92+
enableScroll = true,
8993
previewProps = {},
9094
extensions = [],
9195
previewWidth = '50%',
@@ -97,6 +101,7 @@ function MarkdownEditorInternal(
97101
const container = useRef<HTMLDivElement>(null);
98102
const containerEditor = useRef<HTMLDivElement>(null);
99103
const preview = useRef<HTMLDivElement>(null);
104+
const active = useRef<'editor' | 'preview'>('editor');
100105

101106
useImperativeHandle(
102107
ref,
@@ -115,9 +120,51 @@ function MarkdownEditorInternal(
115120
editorProps: { ...props, previewWidth },
116121
};
117122
const height = typeof codemirrorProps.height === 'number' ? `${codemirrorProps.height}px` : codemirrorProps.height;
118-
const extensionsData: IMarkdownEditor['extensions'] = reExtensions
123+
124+
const previewScrollHandle = useCallback(
125+
(event: Event) => {
126+
if (!enableScroll) return;
127+
const target = event.target as HTMLDivElement;
128+
const percent = target.scrollTop / target.scrollHeight;
129+
if (active.current === 'editor' && preview.current) {
130+
const previewHeihgt = preview.current?.scrollHeight || 0;
131+
preview.current!.scrollTop = previewHeihgt * percent;
132+
} else if (codeMirror.current && codeMirror.current.view) {
133+
const editorScrollDom = codeMirror.current.view.scrollDOM;
134+
const editorScrollHeihgt = codeMirror.current.view.scrollDOM.scrollHeight || 0;
135+
editorScrollDom.scrollTop = editorScrollHeihgt * percent;
136+
}
137+
},
138+
[enableScroll],
139+
);
140+
const mouseoverHandle = () => (active.current = 'preview');
141+
const mouseleaveHandle = () => (active.current = 'editor');
142+
useEffect(() => {
143+
const $preview = preview.current;
144+
if ($preview && enableScroll) {
145+
$preview.addEventListener('mouseover', mouseoverHandle, false);
146+
$preview.addEventListener('mouseleave', mouseleaveHandle, false);
147+
$preview.addEventListener('scroll', previewScrollHandle, false);
148+
}
149+
return () => {
150+
if ($preview && enableScroll) {
151+
$preview.removeEventListener('mouseover', mouseoverHandle);
152+
$preview.removeEventListener('mouseleave', mouseoverHandle);
153+
$preview.addEventListener('mouseleave', previewScrollHandle, false);
154+
}
155+
};
156+
}, [preview, enableScroll, previewScrollHandle]);
157+
158+
const scrollExtensions = events.scroll({
159+
scroll: previewScrollHandle,
160+
});
161+
162+
let extensionsData: IMarkdownEditor['extensions'] = reExtensions
119163
? reExtensions
120164
: [markdown({ base: markdownLanguage, codeLanguages: languages }), scrollerStyle, ...extensions];
165+
if (enableScroll) {
166+
extensionsData.push(scrollExtensions);
167+
}
121168
const clsPreview = `${prefixCls}-preview`;
122169
const cls = [prefixCls, 'wmde-markdown-var', className].filter(Boolean).join(' ');
123170
previewProps['source'] = value;

website/Example.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ export function Example() {
1111
const [mdstr, setMdstr] = useState<string>(DocumentStrSource);
1212
const [hideToolbar, setHideToolbar] = useState(true);
1313
const [toolbarBottom, setToolbarBottom] = useState(false);
14+
const [enableScroll, setEnableScroll] = useState(true);
1415
return (
1516
<div className={styles.editor}>
1617
<MarkdownEditor
1718
visible={visible}
1819
height="500px"
1920
value={mdstr}
21+
enableScroll={enableScroll}
2022
hideToolbar={hideToolbar}
2123
toolbarBottom={toolbarBottom}
2224
/>
@@ -33,6 +35,10 @@ export function Example() {
3335
<input type="checkbox" checked={hideToolbar} onChange={(evn) => setHideToolbar(evn.target.checked)} />
3436
hideToolbar
3537
</label>
38+
<label>
39+
<input type="checkbox" checked={enableScroll} onChange={(evn) => setEnableScroll(evn.target.checked)} />
40+
enableScroll
41+
</label>
3642
<label>
3743
<input type="checkbox" checked={toolbarBottom} onChange={(evn) => setToolbarBottom(evn.target.checked)} />
3844
toolbarBottom

0 commit comments

Comments
 (0)