parent
d95bb4acd6
commit
3cd97a4c23
@ -0,0 +1,50 @@
|
||||
# CodeMirror 6 editor for Angular
|
||||
|
||||
## Installation
|
||||
|
||||
Use the CodeFirst NPM registry for `@sandkasten` packages in your `~/.npmrc` file:
|
||||
|
||||
```env
|
||||
@sandkasten:registry=https://codefirst.iut.uca.fr/git/api/packages/sandkasten/npm/
|
||||
```
|
||||
|
||||
```bash
|
||||
npm install @sandkasten/codemirror6-editor codemirror @codemirror/state @codemirror/view
|
||||
```
|
||||
|
||||
Install the language support you need, for example with JavaScript:
|
||||
|
||||
```bash
|
||||
npm install @codemirror/lang-javascript
|
||||
```
|
||||
|
||||
Import the component in either the `app.module.ts` file or the component:
|
||||
|
||||
```typescript
|
||||
import { CodeMirrorComponent } from 'codemirror6';
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
A code editor with JavaScript syntax highlighting:
|
||||
|
||||
```html
|
||||
<codemirror6-editor
|
||||
[(ngModel)]="editorContent"
|
||||
[extensions]="[
|
||||
basicSetup,
|
||||
javascript()
|
||||
]"
|
||||
></codemirror6-editor>
|
||||
```
|
||||
|
||||
A read-only code output:
|
||||
|
||||
```html
|
||||
<codemirror6-editor
|
||||
[(ngModel)]="editorContent"
|
||||
[extensions]="[
|
||||
EditorState.readOnly.of(true)
|
||||
]"
|
||||
></codemirror6-editor>
|
||||
```
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../dist/codemirror6-editor",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "@sandkasten/codemirror6-editor",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^17.1.0",
|
||||
"@angular/core": "^17.1.0",
|
||||
"@codemirror/state": "^6.4.0",
|
||||
"@codemirror/view": "^6.23.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"sideEffects": false
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AngularCodemirror6Component } from './codemirror6-editor.component';
|
||||
|
||||
describe('AngularCodemirror6Component', () => {
|
||||
let component: AngularCodemirror6Component;
|
||||
let fixture: ComponentFixture<AngularCodemirror6Component>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [AngularCodemirror6Component]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AngularCodemirror6Component);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,77 @@
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
ElementRef,
|
||||
Input,
|
||||
NgZone,
|
||||
OnDestroy
|
||||
} from '@angular/core';
|
||||
import { EditorState, Extension, StateEffect } from '@codemirror/state';
|
||||
import { EditorView } from '@codemirror/view';
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
|
||||
|
||||
@Component({
|
||||
selector: 'codemirror6-editor',
|
||||
standalone: true,
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: CodeMirrorComponent,
|
||||
multi: true
|
||||
},
|
||||
],
|
||||
template: `<div #host></div>`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CodeMirrorComponent implements AfterViewInit, OnDestroy, ControlValueAccessor {
|
||||
|
||||
@Input()
|
||||
set extensions(extensions: Extension[]) {
|
||||
this.editor?.dispatch({
|
||||
effects: StateEffect.reconfigure.of(extensions),
|
||||
});
|
||||
}
|
||||
|
||||
private editor: EditorView | null = null;
|
||||
private handleChange: (value: string) => void = () => {};
|
||||
|
||||
constructor(private host: ElementRef<HTMLElement>, private ngZone: NgZone) {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
const state = EditorState.create({
|
||||
extensions: [
|
||||
EditorView.updateListener.of((update) => {
|
||||
this.ngZone.run(() => {
|
||||
const value = update.state.doc.toString();
|
||||
this.handleChange(value);
|
||||
});
|
||||
}),
|
||||
],
|
||||
});
|
||||
this.editor = new EditorView({
|
||||
state,
|
||||
parent: this.host.nativeElement,
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.editor?.destroy();
|
||||
}
|
||||
|
||||
writeValue(value: string) {
|
||||
this.editor?.dispatch({
|
||||
changes: {
|
||||
from: 0,
|
||||
to: this.editor.state.doc.length,
|
||||
insert: value,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
registerOnChange(fn: (value: string) => void) {
|
||||
this.handleChange = fn;
|
||||
}
|
||||
|
||||
registerOnTouched() {}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
/*
|
||||
* Public API Surface of codemirror6-editor
|
||||
*/
|
||||
|
||||
export * from './lib/codemirror6-editor.component';
|
@ -0,0 +1,14 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../out-tsc/lib",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.lib.json",
|
||||
"compilerOptions": {
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
Loading…
Reference in new issue