Skip to content

Commit 73a7643

Browse files
committed
feat: Update codemirror 6.
1 parent e3c6cef commit 73a7643

32 files changed

+621
-979
lines changed

.github/workflows/ci.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ jobs:
77
build-deploy:
88
runs-on: ubuntu-18.04
99
steps:
10-
- uses: actions/checkout@v2
11-
- uses: actions/setup-node@v2
10+
- uses: actions/checkout@v3
11+
- uses: actions/setup-node@v3
1212
with:
13-
node-version: 14
13+
node-version: 16
1414

1515
- run: npm install
1616
- run: npm run build
@@ -25,13 +25,13 @@ jobs:
2525

2626
- name: Create Tag
2727
id: create_tag
28-
uses: jaywcjlove/[email protected].6
28+
uses: jaywcjlove/[email protected].7
2929
with:
3030
package-path: ./package.json
3131

3232
- name: get tag version
3333
id: tag_version
34-
uses: jaywcjlove/[email protected].0
34+
uses: jaywcjlove/[email protected].7
3535

3636
- name: Deploy
3737
uses: peaceiris/actions-gh-pages@v3
@@ -42,7 +42,7 @@ jobs:
4242

4343
- name: Generate Changelog
4444
id: changelog
45-
uses: jaywcjlove/[email protected].0
45+
uses: jaywcjlove/[email protected].7
4646
with:
4747
head-ref: ${{steps.create_tag.outputs.version}}
4848
filter-author: (小弟调调™)

README.md

Lines changed: 94 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,17 +83,36 @@ import MarkdownEditor from '@uiw/react-markdown-editor';
8383
const title2 = {
8484
name: 'title2',
8585
keyCommand: 'title2',
86+
button: { 'aria-label': 'Add title text' },
8687
icon: (
8788
<svg width="12" height="12" viewBox="0 0 512 512">
8889
<path fill="currentColor" d="M496 80V48c0-8.837-7.163-16-16-16H320c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h37.621v128H154.379V96H192c8.837 0 16-7.163 16-16V48c0-8.837-7.163-16-16-16H32c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h37.275v320H32c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h160c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16h-37.621V288H357.62v128H320c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h160c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16h-37.275V96H480c8.837 0 16-7.163 16-16z" />
8990
</svg>
9091
),
91-
execute: (editor, selection, position) => {
92-
const value = selection ? `## ${selection}` : '## ';
93-
editor.replaceSelection(value);
94-
position.ch = !!selection ? position.ch : position.ch + 3;
95-
editor.setCursor(position.line, position.ch);
96-
editor.focus();
92+
execute: ({ state, view }) => {
93+
if (!state || !view) return;
94+
const lineInfo = view.state.doc.lineAt(view.state.selection.main.from);
95+
let mark = '#';
96+
const matchMark = lineInfo.text.match(/^#+/)
97+
if (matchMark && matchMark[0]) {
98+
const txt = matchMark[0];
99+
if (txt.length < 6) {
100+
mark = txt + '#';
101+
}
102+
}
103+
if (mark.length > 6) {
104+
mark = '#';
105+
}
106+
const title = lineInfo.text.replace(/^#+/, '')
107+
view.dispatch({
108+
changes: {
109+
from: lineInfo.from,
110+
to: lineInfo.to,
111+
insert: `${mark}${title}`
112+
},
113+
// selection: EditorSelection.range(lineInfo.from + mark.length, lineInfo.to),
114+
selection: { anchor: lineInfo.from + mark.length },
115+
});
97116
},
98117
};
99118

@@ -183,14 +202,80 @@ const Demo = () => {
183202
- `onBlur?: function(editor: IInstance, event: Event)` - event occurs when an object loses focus
184203
- `previewProps` - [react-markdown options](https://github.com/uiwjs/react-markdown-preview/tree/v2.1.0#options-props)
185204

186-
> [Other Props Options](https://github.com/uiwjs/react-markdown-editor/blob/812937bf90abadd5f795d06d97ead9f59cd35954/src/index.tsx#L11-L21)
205+
```ts
206+
import { ReactCodeMirrorProps } from '@uiw/react-codemirror';
207+
export interface IMarkdownEditor extends ReactCodeMirrorProps {
208+
className?: string;
209+
prefixCls?: string;
210+
/** The raw markdown that will be converted to html (**required**) */
211+
value?: string;
212+
/** Shows a preview that will be converted to html. */
213+
visible?: boolean;
214+
visibleEditor?: boolean;
215+
/** Tool display settings. */
216+
toolbars?: IToolBarProps['toolbars'];
217+
/** Tool display settings. */
218+
toolbarsMode?: IToolBarProps['toolbars'];
219+
/** [@uiw/react-markdown-preview](https://github.com/uiwjs/react-markdown-preview#options-props) options */
220+
previewProps?: MarkdownPreviewProps;
221+
}
222+
```
187223

224+
```ts
225+
import React from 'react';
226+
import { ReactCodeMirrorRef } from '@uiw/react-codemirror';
227+
import { MarkdownPreviewProps, MarkdownPreviewRef } from '@uiw/react-markdown-preview';
228+
export interface ToolBarProps {
229+
editor?: ReactCodeMirrorRef;
230+
preview: React.RefObject<MarkdownPreviewRef>;
231+
container: React.RefObject<HTMLDivElement>;
232+
containerEditor: React.RefObject<HTMLDivElement>;
233+
editorProps: IMarkdownEditor;
234+
}
235+
export interface MarkdownEditorRef {
236+
editor: React.RefObject<ReactCodeMirrorRef> | null;
237+
preview?: React.RefObject<MarkdownPreviewRef> | null;
238+
}
239+
export interface IToolBarProps<T = keyof typeof defaultCommands | ICommand> extends ToolBarProps {
240+
className?: string;
241+
editorProps: IMarkdownEditor;
242+
mode?: boolean;
243+
prefixCls?: string;
244+
toolbars?: T[];
245+
onClick?: (type: string) => void;
246+
}
247+
export declare type ButtonHandle = (command: ICommand, props: IMarkdownEditor, options: ToolBarProps) => JSX.Element;
248+
export declare type ICommand = {
249+
icon?: React.ReactElement;
250+
name?: string;
251+
keyCommand?: string;
252+
button?: ButtonHandle | React.ButtonHTMLAttributes<HTMLButtonElement>;
253+
execute?: (editor: ReactCodeMirrorRef) => void;
254+
};
255+
export declare const defaultCommands: {
256+
bold: ICommand;
257+
italic: ICommand;
258+
header: ICommand;
259+
strike: ICommand;
260+
underline: ICommand;
261+
olist: ICommand;
262+
ulist: ICommand;
263+
link: ICommand;
264+
todo: ICommand;
265+
image: ICommand;
266+
fullscreen: ICommand;
267+
preview: ICommand;
268+
};
269+
export declare const getCommands: () => ICommand[];
270+
export declare const getModeCommands: () => ICommand[];
271+
```
188272

189273
### Development
190274

191275
```bash
192-
npm run dev
193-
npm run type-check:watch
276+
npm run watch # Listen create type and .tsx files.
277+
npm run start # Preview code example.
278+
194279
npm run doc
195280
```
196281

package.json

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@
2929
"react-dom": ">=16.8.0"
3030
},
3131
"files": [
32+
"src/**/*.{ts,tsx,less}",
3233
"markdown-editor.css",
3334
"cjs",
34-
"esm",
35-
"src"
35+
"esm"
3636
],
3737
"eslintConfig": {
3838
"extends": [
@@ -41,27 +41,29 @@
4141
]
4242
},
4343
"dependencies": {
44-
"@uiw/react-markdown-preview": "~4.0.3",
45-
"codemirror": "~5.65.2"
44+
"@codemirror/lang-markdown": "^6.0.0",
45+
"@codemirror/language-data": "^6.1.0",
46+
"@uiw/codemirror-themes": "^4.10.4",
47+
"@uiw/react-codemirror": "^4.10.4",
48+
"@uiw/react-markdown-preview": "^4.0.20"
4649
},
4750
"devDependencies": {
48-
"@kkt/less-modules": "~7.1.1",
49-
"@kkt/raw-modules": "~7.1.1",
50-
"@kkt/scope-plugin-options": "~7.1.1",
51-
"@types/codemirror": "~5.60.5",
52-
"@types/react": "~18.0.5",
53-
"@types/react-dom": "~18.0.1",
54-
"@uiw/react-github-corners": "~1.5.3",
55-
"@uiw/reset.css": "~1.0.6",
56-
"@wcj/dark-mode": "~1.0.10",
57-
"compile-less-cli": "~1.8.11",
58-
"kkt": "~7.1.5",
59-
"prettier": "~2.5.1",
51+
"@kkt/less-modules": "^7.2.0",
52+
"@kkt/raw-modules": "^7.2.0",
53+
"@kkt/scope-plugin-options": "^7.2.0",
54+
"@types/react": "^18.0.14",
55+
"@types/react-dom": "^18.0.5",
56+
"@uiw/react-github-corners": "^1.5.14",
57+
"@uiw/reset.css": "^1.0.6",
58+
"@wcj/dark-mode": "^1.0.14",
59+
"compile-less-cli": "^1.8.13",
60+
"kkt": "^7.2.0",
61+
"prettier": "^2.7.1",
6062
"pretty-quick": "~3.1.3",
61-
"react": "~18.0.0",
62-
"react-dom": "~18.0.0",
63-
"tsbb": "~3.7.2",
64-
"husky": "~7.0.4"
63+
"react": "^18.2.0",
64+
"react-dom": "^18.2.0",
65+
"tsbb": "^3.7.6",
66+
"husky": "^8.0.1"
6567
},
6668
"browserslist": {
6769
"production": [

src/commands/bold.tsx

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
1-
import React from 'react';
2-
import { ICommand } from './'
1+
import { EditorSelection } from '@codemirror/state';
2+
import { ICommand } from './';
33

44
export const bold: ICommand = {
55
name: 'bold',
66
keyCommand: 'bold',
77
button: { 'aria-label': 'Add bold text' },
88
icon: (
99
<svg width="13" height="13" viewBox="0 0 384 512">
10-
<path fill="currentColor" d="M304.793 243.891c33.639-18.537 53.657-54.16 53.657-95.693 0-48.236-26.25-87.626-68.626-104.179C265.138 34.01 240.849 32 209.661 32H24c-8.837 0-16 7.163-16 16v33.049c0 8.837 7.163 16 16 16h33.113v318.53H24c-8.837 0-16 7.163-16 16V464c0 8.837 7.163 16 16 16h195.69c24.203 0 44.834-1.289 66.866-7.584C337.52 457.193 376 410.647 376 350.014c0-52.168-26.573-91.684-71.207-106.123zM142.217 100.809h67.444c16.294 0 27.536 2.019 37.525 6.717 15.828 8.479 24.906 26.502 24.906 49.446 0 35.029-20.32 56.79-53.029 56.79h-76.846V100.809zm112.642 305.475c-10.14 4.056-22.677 4.907-31.409 4.907h-81.233V281.943h84.367c39.645 0 63.057 25.38 63.057 63.057.001 28.425-13.66 52.483-34.782 61.284z" />
10+
<path
11+
fill="currentColor"
12+
d="M304.793 243.891c33.639-18.537 53.657-54.16 53.657-95.693 0-48.236-26.25-87.626-68.626-104.179C265.138 34.01 240.849 32 209.661 32H24c-8.837 0-16 7.163-16 16v33.049c0 8.837 7.163 16 16 16h33.113v318.53H24c-8.837 0-16 7.163-16 16V464c0 8.837 7.163 16 16 16h195.69c24.203 0 44.834-1.289 66.866-7.584C337.52 457.193 376 410.647 376 350.014c0-52.168-26.573-91.684-71.207-106.123zM142.217 100.809h67.444c16.294 0 27.536 2.019 37.525 6.717 15.828 8.479 24.906 26.502 24.906 49.446 0 35.029-20.32 56.79-53.029 56.79h-76.846V100.809zm112.642 305.475c-10.14 4.056-22.677 4.907-31.409 4.907h-81.233V281.943h84.367c39.645 0 63.057 25.38 63.057 63.057.001 28.425-13.66 52.483-34.782 61.284z"
13+
/>
1114
</svg>
1215
),
13-
execute: (editor, selection, position) => {
14-
const value = selection ? `**${selection}**` : `****`;
15-
editor.replaceSelection(value);
16-
position.ch = !!selection ? position.ch : position.ch + 2;
17-
editor.setCursor(position.line, position.ch);
18-
editor.focus();
16+
execute: ({ state, view }) => {
17+
if (!state || !view) return;
18+
view.dispatch(
19+
view.state.changeByRange((range) => ({
20+
changes: [
21+
{ from: range.from, insert: '**' },
22+
{ from: range.to, insert: '**' },
23+
],
24+
range: EditorSelection.range(range.from + 2, range.to + 2),
25+
})),
26+
);
1927
},
20-
};
28+
};

src/commands/fullscreen.tsx

Lines changed: 45 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,58 @@
11
import React, { useEffect, useRef, useState } from 'react';
22
import { ICommand } from './';
3-
import { IMarkdownEditor } from '../';
3+
import { IMarkdownEditor, ToolBarProps } from '../';
44

5-
type Options = {
6-
preview?: HTMLDivElement | null | undefined;
7-
container?: HTMLDivElement | null | undefined;
8-
editor?: CodeMirror.Editor;
9-
};
10-
11-
const Fullscreen: React.FC<{ command: ICommand; editorProps: IMarkdownEditor & Options }> = (props) => {
12-
const {
13-
editorProps: { container, preview, editor },
14-
} = props;
5+
const Fullscreen: React.FC<{ command: ICommand; editorProps: IMarkdownEditor & ToolBarProps }> = (props) => {
6+
const { editorProps } = props;
7+
const $height = useRef<number>(0);
158
const [full, setFull] = useState(false);
16-
const initEditorHeight = useRef(0);
17-
const containerRef = useRef<HTMLDivElement | null>();
18-
const editorRef = useRef<CodeMirror.Editor>();
19-
function handleResize() {
20-
if (containerRef.current && editorRef.current && editorRef.current.setSize) {
21-
editorRef.current.setSize('initial', containerRef.current.clientHeight - 35);
22-
}
23-
}
24-
useEffect(() => {
25-
window && window.addEventListener('resize', handleResize, true);
26-
return () => {
27-
window && window.removeEventListener('resize', handleResize, true);
28-
};
29-
}, []);
309
useEffect(() => {
31-
if (editor) {
32-
editorRef.current = editor;
33-
const { clientHeight } = editor.getScrollInfo();
34-
initEditorHeight.current = clientHeight;
10+
if (
11+
editorProps.containerEditor &&
12+
editorProps.containerEditor.current &&
13+
editorProps.containerEditor.current.parentElement
14+
) {
15+
const parentElement = editorProps.containerEditor.current.parentElement;
16+
const robserver = new ResizeObserver((entries) => {
17+
for (const entry of entries) {
18+
if (!$height.current) {
19+
$height.current = entry.target.clientHeight;
20+
}
21+
if (editorProps.editor && editorProps.editor.view?.dom) {
22+
if (full) {
23+
editorProps.editor.view.dom.style.height = `${entry.target.clientHeight}px`;
24+
} else {
25+
editorProps.editor.view.dom.removeAttribute('style');
26+
}
27+
}
28+
}
29+
});
30+
robserver.observe(parentElement);
3531
}
36-
}, [editor]);
32+
}, [editorProps.containerEditor, editorProps.editor, full]);
33+
3734
useEffect(() => {
3835
if (!document) return;
39-
containerRef.current = container;
40-
document.body.style.overflow = full ? 'hidden' : 'initial';
41-
if (container && full) {
42-
container.style.zIndex = '999';
43-
container.style.position = 'fixed';
44-
container.style.top = '0px';
45-
container.style.bottom = '0px';
46-
container.style.left = '0px';
47-
container.style.right = '0px';
48-
if (editor) {
49-
editor.setSize('initial', container.clientHeight - 35);
50-
}
51-
} else if (container) {
52-
container.style.position = 'initial';
53-
container.style.top = 'initial';
54-
container.style.bottom = 'initial';
55-
container.style.left = 'initial';
56-
container.style.right = 'initial';
57-
if (editor) {
58-
editor.setSize('initial', initEditorHeight.current);
36+
if (editorProps && editorProps.container && editorProps.container.current && editorProps.editor) {
37+
const container = editorProps.container.current;
38+
document.body.style.overflow = full ? 'hidden' : 'initial';
39+
if (container && full) {
40+
container.style.zIndex = '999';
41+
container.style.position = 'fixed';
42+
container.style.top = '0px';
43+
container.style.bottom = '0px';
44+
container.style.left = '0px';
45+
container.style.right = '0px';
46+
} else if (container) {
47+
container.style.position = 'initial';
48+
container.style.top = 'initial';
49+
container.style.bottom = 'initial';
50+
container.style.left = 'initial';
51+
container.style.right = 'initial';
5952
}
6053
}
61-
}, [full, container, preview, editor]);
54+
}, [full, editorProps]);
55+
6256
return (
6357
<button onClick={() => setFull(!full)} type="button" className={full ? 'active' : ''}>
6458
{props.command.icon}

0 commit comments

Comments
 (0)