|
options
|
Type : any
|
Default value : {}
|
|
|
|
insideNg
|
Type : boolean
|
Default value : false
|
|
|
|
|
|
Readonly
options
|
Type : unknown
|
Default value : computed(() =>
Object.assign({}, this.config.defaultOptions, this.optionsInput())
)
|
|
|
|
Readonly
_editorContainer
|
Type : unknown
|
Default value : viewChild.required<ElementRef>('editorContainer')
|
|
|
|
|
|
config
|
Type : unknown
|
Default value : inject<NgxMonacoEditorConfig>(NGX_MONACO_EDITOR_CONFIG)
|
|
|
|
|
import {
ChangeDetectionStrategy,
Component,
NgZone,
computed,
effect,
inject,
input,
untracked
} from '@angular/core';
import { fromEvent } from 'rxjs';
import { BaseEditor } from './base-editor';
import { DiffEditorModel } from './types';
declare let monaco: any;
@Component({
standalone: true,
selector: 'taly-monaco-diff-editor',
template: '<div class="editor-container" #editorContainer></div>',
styles: [
`
:host {
display: block;
height: 200px;
}
.editor-container {
width: 100%;
height: 98%;
}
`
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DiffEditorComponent extends BaseEditor {
private zone = inject(NgZone);
// eslint-disable-next-line @angular-eslint/no-input-rename
readonly optionsInput = input<any>({}, { alias: 'options' });
readonly options = computed(() =>
Object.assign({}, this.config.defaultOptions, this.optionsInput())
);
readonly originalModel = input<DiffEditorModel | undefined>(undefined);
readonly modifiedModel = input<DiffEditorModel | undefined>(undefined);
_originalModel: DiffEditorModel | undefined;
_modifiedModel: DiffEditorModel | undefined;
constructor() {
super();
effect((onCleanup) => {
this._options = { ...this.options() };
this._originalModel = this.originalModel();
this._modifiedModel = this.modifiedModel();
const insideNg = this.insideNg();
const monacoLoaded = this.monacoLoaded();
untracked(() => {
if (!monacoLoaded || !this._originalModel || !this._modifiedModel) {
return;
}
// `cancelled` guards against the effect re-running (stale models) or the
// component being destroyed before this microtask gets a turn.
let cancelled = false;
onCleanup(() => {
cancelled = true;
});
// Deferred: initMonaco() emits `onInit`, which can trigger change detection —
// doing that synchronously inside this effect risks NG0100.
queueMicrotask(() => {
if (cancelled) {
return;
}
if (this._editor) {
this._editor.dispose();
}
this.initMonaco(this._options, insideNg);
});
});
});
}
protected initMonaco(options: any, insideNg: boolean): void {
if (!this._originalModel || !this._modifiedModel) {
throw new Error('originalModel or modifiedModel not found for ngx-monaco-diff-editor');
}
this._originalModel.language = this._originalModel.language || options.language;
this._modifiedModel.language = this._modifiedModel.language || options.language;
const originalModel = monaco.editor.createModel(
this._originalModel.code,
this._originalModel.language
);
const modifiedModel = monaco.editor.createModel(
this._modifiedModel.code,
this._modifiedModel.language
);
this._editorContainer().nativeElement.innerHTML = '';
const theme = options.theme;
if (insideNg) {
this._editor = monaco.editor.createDiffEditor(this._editorContainer().nativeElement, options);
} else {
this.zone.runOutsideAngular(() => {
this._editor = monaco.editor.createDiffEditor(
this._editorContainer().nativeElement,
options
);
});
}
options.theme = theme;
this._editor.setModel({
original: originalModel,
modified: modifiedModel
});
// refresh layout on resize event.
if (this._windowResizeSubscription) {
this._windowResizeSubscription.unsubscribe();
}
this._windowResizeSubscription = fromEvent(window, 'resize').subscribe(() =>
this._editor.layout()
);
this.onInit.emit(this._editor);
}
}
:host {
display: block;
height: 200px;
}
.editor-container {
width: 100%;
height: 98%;
}
Legend
Html element with directive