Skip to content

Commit

Permalink
feat: v6.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
surmon-china committed Jul 21, 2022
1 parent bbc8c1a commit c5ea755
Show file tree
Hide file tree
Showing 10 changed files with 255 additions and 188 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
## CHANGELOG

### v6.0.1 (2022-07-22)

- feat: add `autoDestroy` prop for [#156](https://github.com/surmon-china/vue-codemirror/pull/156).
- feat: refactoring component.
- chore: upgrade deps and upgrade vite to v3.

### v6.0.0 (2022-06-13)

**Breaking changes**
Expand Down Expand Up @@ -74,6 +80,6 @@ add props placeholder

#### project

- add brower support
- add browser support
- add test scripts
- update babel and webpack configs
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ app.use(VueCodemirror, {
| tabSize | Specify the indent when the Tab key is pressed. | `Number` | `2` |
| placeholder | Display when empty. | `String` | `''` |
| style | The CSS style object that acts on the CodeMirror itself. | `Object` | `{}` |
| autoDestroy | Auto destroy the CodeMirror instance before the component unmount. | `Boolean` | `true` |
| extensions | Passed to CodeMirror `EditorState.create({ extensions })` | `Extension` | `[]` |
| selection | Passed to CodeMirror `EditorState.create({ selection })` | `EditorSelection` | - |
| root | Passed to CodeMirror `new EditorView({ root })` | `ShadowRoot \| Document` | - |
Expand Down
10 changes: 7 additions & 3 deletions dev/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
const consoleLog = console.log
const code = shallowRef(`console.log('Hello World')`)
const cm = shallowRef()
const view = shallowRef()
const state = reactive({
disabled: false,
indentWithTab: true,
Expand All @@ -29,6 +29,10 @@
theme: 'oneDark'
})
const handleReady = (payload: any) => {
console.log('handleReady payload:', payload)
}
const extensions = computed(() => {
const result = []
result.push(languages[state.language])
Expand All @@ -39,7 +43,7 @@
})
onMounted(() => {
console.log('cm', cm)
console.log('mounted view:', view)
})
</script>

Expand Down Expand Up @@ -108,7 +112,7 @@
:style="{ backgroundColor: state.backgroundColor }"
:extensions="extensions"
v-model="code"
@ready="consoleLog('ready', $event)"
@ready="handleReady"
@change="consoleLog('change', $event)"
@focus="consoleLog('focus', $event)"
@blur="consoleLog('blur', $event)"
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "vue-codemirror",
"description": "CodeMirror code editor component for Vue",
"version": "6.0.0",
"version": "6.0.1",
"homepage": "https://github.com/surmon-china/vue-codemirror#readme",
"license": "MIT",
"keywords": [
Expand Down
131 changes: 83 additions & 48 deletions src/codemirror.ts
Original file line number Diff line number Diff line change
@@ -1,90 +1,125 @@
import * as CSS from 'csstype'
import { EditorState, EditorStateConfig, Compartment, Extension, StateEffect } from '@codemirror/state'
import { EditorView, ViewUpdate, keymap, placeholder } from '@codemirror/view'
import { EditorView, EditorViewConfig, ViewUpdate, keymap, placeholder } from '@codemirror/view'
import { indentWithTab } from '@codemirror/commands'
import { indentUnit } from '@codemirror/language'
import * as CSS from 'csstype'

// state
export interface EditorStateCreatorOptions {
config: EditorStateConfig
onUpdate(viewUpdate: ViewUpdate): void
export interface CreateStateOptions extends EditorStateConfig {
onChange(doc: string, viewUpdate: ViewUpdate): void
onUpdate(viewUpdate: ViewUpdate): void
onFocus(viewUpdate: ViewUpdate): void
onBlur(viewUpdate: ViewUpdate): void
}
export const createState = ({ config, ...events }: EditorStateCreatorOptions): EditorState => {
const extensions = Array.isArray(config.extensions) ? config.extensions : [config.extensions]

export const createEditorState = ({ onUpdate, onChange, onFocus, onBlur, ...config }: CreateStateOptions) => {
return EditorState.create({
doc: config.doc,
selection: config.selection,
extensions: [
...extensions,
...(Array.isArray(config.extensions) ? config.extensions : [config.extensions]),
EditorView.updateListener.of((viewUpdate) => {
// https://discuss.codemirror.net/t/codemirror-6-proper-way-to-listen-for-changes/2395/11
events.onUpdate(viewUpdate)
onUpdate(viewUpdate)
// doc changed
if (viewUpdate.docChanged) {
events.onChange(viewUpdate.state.doc.toString(), viewUpdate)
onChange(viewUpdate.state.doc.toString(), viewUpdate)
}
// focus state change
if (viewUpdate.focusChanged) {
viewUpdate.view.hasFocus ? events.onFocus(viewUpdate) : events.onBlur(viewUpdate)
viewUpdate.view.hasFocus ? onFocus(viewUpdate) : onBlur(viewUpdate)
}
})
]
})
}

// doc
export const getDoc = (view: EditorView) => view.state.doc.toString()
export const setDoc = (view: EditorView, newDoc: string) => {
return view.dispatch({
changes: {
from: 0,
to: view.state.doc.length,
insert: newDoc
}
})
export const destroyEditorView = (view: EditorView) => view.destroy()
export const createEditorView = (config: EditorViewConfig) => {
return new EditorView({ ...config })
}

// effects
export const destroy = (view: EditorView) => view.destroy()
export const focus = (view: EditorView) => view.focus() // TODO: focus on the last word

// https://codemirror.net/examples/config/
// https://github.com/uiwjs/react-codemirror/blob/22cc81971a/src/useCodeMirror.ts#L144
// https://gist.github.com/s-cork/e7104bace090702f6acbc3004228f2cb
const rerunCompartment = () => {
export const createEditorCompartment = (view: EditorView) => {
const compartment = new Compartment()
const run = (view: EditorView, extension: Extension) => {
if (compartment.get(view.state)) {
// reconfigure
view.dispatch({ effects: compartment.reconfigure(extension) })
} else {
// inject
view.dispatch({ effects: StateEffect.appendConfig.of(compartment.of(extension)) })
}
const run = (extension: Extension) => {
compartment.get(view.state)
? view.dispatch({ effects: compartment.reconfigure(extension) }) // reconfigure
: view.dispatch({ effects: StateEffect.appendConfig.of(compartment.of(extension)) }) // inject
}
return { compartment, run }
}

// https://codemirror.net/examples/reconfigure/
export const rerunExtension = () => rerunCompartment().run
export const toggleExtension = (extension: Extension) => {
const { compartment, run } = rerunCompartment()
return (view: EditorView, targetApply?: boolean) => {
export const createEditorExtensionToggler = (view: EditorView, extension: Extension) => {
const { compartment, run } = createEditorCompartment(view)
return (targetApply?: boolean) => {
const exExtension = compartment.get(view.state)
const apply = targetApply ?? exExtension !== extension
run(view, apply ? extension : [])
run(apply ? extension : [])
}
}

// extensions
export const extensions = {
placeholder: (string: string) => placeholder(string),
disable: () => [EditorView.editable.of(false), EditorState.readOnly.of(true)],
enable: () => [EditorView.editable.of(true), EditorState.readOnly.of(false)],
export const createEditorTools = (view: EditorView) => {
// UE state
const focus = () => view.focus()

// doc state
const getDoc = () => view.state.doc.toString()
const setDoc = (newDoc: string) => {
if (newDoc !== getDoc()) {
view.dispatch({
changes: {
from: 0,
to: view.state.doc.length,
insert: newDoc
}
})
}
}

// reconfigure extension
const { run: reExtensions } = createEditorCompartment(view)

// disabled editor
const toggleDisabled = createEditorExtensionToggler(view, [
EditorView.editable.of(false),
EditorState.readOnly.of(true)
])

// https://codemirror.net/examples/tab/
indentWithTab: () => keymap.of([indentWithTab]),
tabSize: (tabSize: number) => [EditorState.tabSize.of(tabSize), indentUnit.of(' '.repeat(tabSize))],
const toggleIndentWithTab = createEditorExtensionToggler(view, keymap.of([indentWithTab]))

// tab size
// https://gist.github.com/s-cork/e7104bace090702f6acbc3004228f2cb
const { run: reTabSize } = createEditorCompartment(view)
const setTabSize = (tabSize: number) => {
reTabSize([EditorState.tabSize.of(tabSize), indentUnit.of(' '.repeat(tabSize))])
}

// set editor's placeholder
const { run: rePlaceholder } = createEditorCompartment(view)
const setPlaceholder = (value: string) => {
rePlaceholder(placeholder(value))
}

// set style to editor element
// https://codemirror.net/examples/styling/
style: (style: CSS.Properties) => EditorView.theme({ '&': { ...style } })
const { run: reStyle } = createEditorCompartment(view)
const setStyle = (style: CSS.Properties = {}) => {
reStyle(EditorView.theme({ '&': { ...style } }))
}

return {
focus,
getDoc,
setDoc,
reExtensions,
toggleDisabled,
toggleIndentWithTab,
setTabSize,
setPlaceholder,
setStyle
}
}
Loading

0 comments on commit c5ea755

Please sign in to comment.