update codemirror

This commit is contained in:
2025-06-03 19:14:50 +08:00
parent 43980ae43c
commit 737014b90f
6 changed files with 144 additions and 26 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@kevisual/codemirror",
"version": "0.0.8",
"version": "0.0.12",
"description": "",
"main": "dist/editor.js",
"private": false,
@@ -27,6 +27,7 @@
"@codemirror/state": "^6.5.2",
"@codemirror/view": "^6.36.7",
"codemirror": "^6.0.1",
"eventemitter3": "^5.0.1",
"prettier": "^3.5.3"
},
"devDependencies": {
@@ -52,6 +53,10 @@
"./json": {
"import": "./dist/editor.json.js",
"types": "./dist/editor.json.d.ts"
},
"./utils": {
"import": "./dist/editor.utils.js",
"types": "./dist/editor.utils.d.ts"
}
}
}

View File

@@ -1,7 +1,7 @@
import { nodeResolve } from '@rollup/plugin-node-resolve';
import typescript from '@rollup/plugin-typescript';
const entrys = ['editor', 'editor.json', 'editor.base'];
const entrys = ['editor', 'editor.json', 'editor.base', 'editor.utils'];
const configs = entrys.map((entry) => ({
input: `./src/${entry}.ts`, // 修改输入文件为 TypeScript 文件
output: {

View File

@@ -1,10 +1,18 @@
import { EditorView, basicSetup } from 'codemirror';
import { basicSetup } from 'codemirror';
import { EditorView } from '@codemirror/view';
import { StateEffect } from '@codemirror/state';
import { ViewUpdate } from '@codemirror/view';
import { formatKeymap } from './extensions/tab';
let editor: EditorView = null;
import EventEmitter from 'eventemitter3';
export type CodeEditor = EditorView & {
emitter?: EventEmitter;
};
let editor: CodeEditor = null;
export type EditorOptions = {
extensions?: any[];
hasBasicSetup?: boolean;
onChange?: (content: string) => void;
};
/**
* 创建单例
@@ -24,12 +32,15 @@ const createEditorInstance = (el?: HTMLDivElement, opts?: EditorOptions) => {
if (hasBaseicSetup) {
extensions.unshift(basicSetup);
}
const emitter = new EventEmitter();
createOnChangeListener(emitter, opts.onChange).appendTo(extensions);
editor = new EditorView({
extensions: extensions,
parent: el || document.body,
});
editor.emitter = emitter;
editor.dom.style.height = '100%';
return editor;
return editor as CodeEditor;
};
/**
@@ -44,13 +55,38 @@ export const createEditor = (el: HTMLDivElement, opts?: EditorOptions) => {
extensions.unshift(basicSetup);
}
extensions.push(formatKeymap);
const emitter = new EventEmitter();
createOnChangeListener(emitter, opts.onChange).appendTo(extensions);
const editor = new EditorView({
extensions,
parent: el || document.body,
});
}) as CodeEditor;
editor.emitter = emitter;
editor.dom.style.height = '100%';
return editor;
return editor as CodeEditor;
};
export const getEditor = () => editor;
export { editor, createEditorInstance };
export const createOnChangeListener = (emitter: EventEmitter, callback?: (content: string) => void) => {
const listener = EditorView.updateListener.of((update: ViewUpdate) => {
if (update.docChanged) {
const editor = update.view;
if (callback) {
callback(editor.state.doc.toString());
}
// 触发自定义事件
emitter.emit('change', editor.state.doc.toString());
}
});
// 返回监听器配置,而不是直接应用它
return {
extension: listener,
appendTo: (ext: any[]) => {
ext.push(listener);
},
};
};

View File

@@ -1,11 +1,18 @@
import { EditorView, basicSetup } from 'codemirror';
import { basicSetup } from 'codemirror';
import { EditorView } from '@codemirror/view';
import { javascript } from '@codemirror/lang-javascript';
import { json } from '@codemirror/lang-json';
import { html } from '@codemirror/lang-html';
import { markdown } from '@codemirror/lang-markdown';
import { css } from '@codemirror/lang-css';
import { formatKeymap } from './extensions/tab';
let editor: EditorView = null;
import { createOnChangeListener } from './editor.base';
import EventEmitter from 'eventemitter3';
export type CodeEditor = EditorView & {
emitter?: EventEmitter;
};
let editor: CodeEditor = null;
type CreateOpts = {
jsx?: boolean;
@@ -14,6 +21,7 @@ type CreateOpts = {
hasBasicSetup?: boolean;
extensions?: any[];
hasKeymap?: boolean;
onChange?: (content: string) => void;
};
/**
* 创建单例
@@ -54,12 +62,15 @@ const createEditorInstance = (el?: HTMLDivElement, opts?: CreateOpts) => {
extensions.push(markdown());
break;
}
const emitter = new EventEmitter();
createOnChangeListener(emitter, opts.onChange).appendTo(extensions);
editor = new EditorView({
extensions: extensions,
parent: el || document.body,
});
editor.dom.style.height = '100%';
return editor;
editor.emitter = emitter;
return editor as CodeEditor;
};
/**
@@ -95,12 +106,15 @@ export const createEditor = (el: HTMLDivElement, opts?: CreateOpts) => {
extensions.push(markdown());
break;
}
const emitter = new EventEmitter();
createOnChangeListener(emitter, opts.onChange).appendTo(extensions);
const editor = new EditorView({
extensions: extensions,
parent: el || document.body,
});
}) as CodeEditor;
editor.dom.style.height = '100%';
return editor;
editor.emitter = emitter;
return editor as CodeEditor;
};
export { editor, createEditorInstance };

View File

@@ -0,0 +1,59 @@
import { EditorView } from '@codemirror/view';
import { CodeEditor } from './editor.base';
type ChainOpts = {
editor?: CodeEditor;
};
export class Chain {
editor: CodeEditor | EditorView;
constructor(opts?: ChainOpts) {
this.editor = opts?.editor;
}
getEditor() {
return this.editor;
}
getContent() {
return this.editor?.state.doc.toString() || '';
}
setContent(content: string) {
if (this.editor) {
this.editor.dispatch({
changes: { from: 0, to: this.editor.state.doc.length, insert: content },
});
}
return this;
}
setEditor(editor: EditorView) {
this.editor = editor;
return this;
}
clearEditor() {
if (this.editor) {
this.editor.dispatch({
changes: { from: 0, to: this.editor.state.doc.length, insert: '' },
});
}
return this;
}
destroy() {
if (this.editor) {
this.editor.destroy();
this.editor = null;
}
return this;
}
static create(opts?: ChainOpts) {
return new Chain(opts);
}
setOnChange(callback: (content: string) => void) {
if (this.editor) {
const editor = this.editor as CodeEditor;
if (editor.emitter) {
editor.emitter.on('change', callback);
return () => {
editor.emitter.off('change', callback);
};
}
}
return () => {};
}
}