Tutorial: Custom Editor
In diesem Tutorial erstellen Sie einen eigenen Editor-Dokumenttyp mit Model und Renderer — die Grundlage für jeden spezialisierten Editor im Studio.
Was Sie lernen
- EditorDocumentModel implementieren (Datenschicht)
- React-Renderer erstellen (UI-Schicht)
- Dokumenttyp registrieren
- Undo/Redo implementieren
- Dokument öffnen und speichern
Architektur
Jeder Editor-Dokumenttyp besteht aus drei Teilen:
Projektstruktur
- index.ts
- MeinEditorModel.ts
- MeinEditorRenderer.tsx
- package.json
Schritt 1: Model erstellen
Das Model erbt von EditorDocumentModel und verwaltet die Daten:
// MeinEditorModel.ts
import { EditorDocumentModel } from '@5minds/processcube_studio_sdk';
export class MeinEditorModel extends EditorDocumentModel {
private text: string = '';
// Lifecycle: Wird aufgerufen, wenn das Model registriert wird
onEditorDocumentModelDidRegister(): void {
const initialData = this.getInitialData();
if (initialData) {
this.text = initialData;
}
this.updateOriginalAndCurrentData(this.text, this.text);
}
// Getter für den aktuellen Text
getValue(): string {
return this.text;
}
// Setter — aktualisiert den State und markiert als "geändert"
setValue(newText: string): void {
this.text = newText;
this.updateCurrentData(this.text);
this.emit('change', this.text);
}
// Lifecycle: Vor dem Speichern
onEditorDocumentWillSave(): void {
// Hier können Daten vor dem Speichern transformiert werden
}
// Lifecycle: Nach dem Speichern
onEditorDocumentDidSave(): void {
// Original-Daten aktualisieren (kein "unsaved"-Indikator mehr)
this.updateOriginalAndCurrentData(this.text, this.text);
}
}Wichtige Model-Methoden:
updateCurrentData(data)— Setzt die aktuellen Daten (zeigt unsaved-Indikator)updateOriginalAndCurrentData(original, current)— Setzt beide (entfernt unsaved-Indikator)emit(event, data)— Benachrichtigt den Renderer über ÄnderungengetInitialData()— Gibt die beim Erstellen übergebenen Daten zurück
Schritt 2: Renderer erstellen
Der Renderer ist eine React-Komponente, die das Model anzeigt und bearbeitbar macht:
// MeinEditorRenderer.tsx
import React, { useState, useEffect } from 'react';
import { EditorDocumentRendererProps } from '@5minds/processcube_studio_sdk';
import { MeinEditorModel } from './MeinEditorModel';
export function MeinEditorRenderer(props: EditorDocumentRendererProps): JSX.Element {
const model = props.editorDocumentModel as MeinEditorModel;
const [text, setText] = useState(model.getValue());
useEffect(() => {
// Auf Änderungen vom Model hören
const handler = (newText: string) => setText(newText);
model.on('change', handler);
return () => { model.off('change', handler); };
}, [model]);
const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
model.setValue(event.target.value);
};
return (
<div style={{ padding: '16px', height: '100%' }}>
<textarea
value={text}
onChange={handleChange}
style={{
width: '100%',
height: '100%',
fontFamily: 'monospace',
fontSize: '14px',
backgroundColor: 'var(--background)',
color: 'var(--foreground)',
border: '1px solid var(--border)',
padding: '8px',
resize: 'none',
}}
/>
</div>
);
}Schritt 3: Dokumenttyp registrieren
Im Entry-Point wird alles zusammengebracht:
// index.ts
import { Studio } from '@5minds/processcube_studio_sdk';
import { MeinEditorModel } from './MeinEditorModel';
import { MeinEditorRenderer } from './MeinEditorRenderer';
export function onLoad(studio: Studio): void {
// Icon registrieren
studio.icons.registerIcons({
'meinEditor/icon': 'fad fa-file-alt',
});
// Dokumenttyp registrieren
studio.editors.registerDocumentType('mein-editor', {
uriMatch: /meinEditor:/, // URI-Pattern für diesen Typ
modelKey: 'MeinEditorModel',
modelConstructor: MeinEditorModel,
rendererKey: 'MeinEditorRenderer',
rendererConstructor: MeinEditorRenderer,
icon: 'meinEditor/icon',
});
// Command zum Erstellen eines neuen Dokuments
studio.commands.registerInCommandSearch(
'meinEditor.neu',
'Mein Editor: Neues Dokument erstellen',
() => {
const uri = `meinEditor:Neues-Dokument-${studio.getGuid()}`;
studio.editors.createNewEditorDocumentAsBuffer('mein-editor', 'Hier Text eingeben...');
},
);
}URI-Patterns
Das uriMatch-Feld bestimmt, welche URIs von diesem Editor geöffnet werden. Es ist ein regulärer Ausdruck:
// Eigenes Protokoll (für Buffer-Dokumente)
uriMatch: /meinEditor:/
// Datei-Endung (für Datei-basierte Editoren)
uriMatch: /\.myext$/
// Spezifisches Muster
uriMatch: /^custom:\/\/mein-editor\//Lifecycle-Übersicht
Optional: Inspector-Pane
Sie können zusätzlich einen Inspector registrieren, der rechts neben dem Editor angezeigt wird:
studio.editors.registerDocumentType('mein-editor', {
uriMatch: /meinEditor:/,
modelConstructor: MeinEditorModel,
rendererConstructor: MeinEditorRenderer,
// Inspector hinzufügen:
inspectorKey: 'MeinEditorInspector',
inspectorConstructor: MeinEditorInspector,
});Der Inspector ist ebenfalls eine React-Komponente, die dasselbe Model erhält und z.B. Metadaten oder Eigenschaften anzeigt.
Nächste Schritte
- Datei-Editor — Editor für Dateitypen (
.json,.csv, etc.) - BPMN Custom Properties — BPMN-Elemente erweitern