Documentation Index
Fetch the complete documentation index at: https://mintlify.com/euclidesseg/euclides-workspace/llms.txt
Use this file to discover all available pages before exploring further.
Your First Editor
This guide will walk you through creating a functional rich text editor with all the core features in just a few minutes.
Create a new component
Create a component that will host the editor:ng generate component editor-demo --standalone
Or create a file manually:src/app/editor-demo/editor-demo.component.ts
import { Component } from '@angular/core';
import { EuclidesRichEditorComponent } from 'euclides-rich-editor';
@Component({
selector: 'app-editor-demo',
standalone: true,
imports: [EuclidesRichEditorComponent],
templateUrl: './editor-demo.component.html',
styleUrls: ['./editor-demo.component.css']
})
export class EditorDemoComponent {}
Add the editor to your template
The simplest way to use the editor is to add it directly to your template:src/app/editor-demo/editor-demo.component.html
<div class="editor-container">
<h1>My Rich Text Editor</h1>
<euclides-rich-editor />
</div>
The editor component includes a built-in toolbar with all formatting options.
Add basic styling
Style the editor container for a better appearance:src/app/editor-demo/editor-demo.component.css
.editor-container {
max-width: 900px;
margin: 2rem auto;
padding: 1rem;
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
h1 {
margin-bottom: 1rem;
color: #333;
}
Try the editor
Start your development server and test the editor:Navigate to your component and try these features:
- Bold: Click the B button or press
Ctrl/Cmd + B
- Italic: Click the I button or press
Ctrl/Cmd + I
- Lists: Click the bullet or numbered list buttons
- Links: Select text and click the link button
- Text Alignment: Use the alignment buttons (left, center, right, justify)
- Undo/Redo: Use the arrow buttons or
Ctrl/Cmd + Z and Ctrl/Cmd + Shift + Z
Understanding the Editor Component
Let’s explore what’s happening inside the EuclidesRichEditorComponent:
Component Structure
The editor consists of two main parts:
import { Component, ElementRef, ViewChild, AfterViewInit, OnDestroy } from '@angular/core';
import { EditorView } from 'prosemirror-view';
import { EditorEngine } from '../../engine/editor-engine';
import { EditorCommandsService } from '../../core/editor-commands.service';
import { EditorStateService } from '../../core/editor-state.service';
@Component({
selector: 'euclides-rich-editor',
standalone: true,
templateUrl: './euclides-editor.component.html'
})
export class EuclidesRichEditorComponent implements AfterViewInit, OnDestroy {
@ViewChild('editor', { static: true })
editorRef!: ElementRef<HTMLDivElement>;
view!: EditorView;
ngAfterViewInit() {
// Initialize the ProseMirror view
this.view = EditorEngine.create(
this.editorRef.nativeElement,
this.editorStateService
);
}
ngOnDestroy() {
this.view.destroy();
}
}
Key Features Explained
Text Formatting
Lists
Text Alignment
Links
History
Text formatting is handled through the EditorCommandsService:toggleBold() {
if (this.editorCommandsService.toggleBold(this.view)) {
this.view.focus();
}
}
toggleItalic() {
if (this.editorCommandsService.toggleItalic(this.view)) {
this.view.focus();
}
}
toggleStrike() {
if (this.editorCommandsService.toggleStrike(this.view)) {
this.view.focus();
}
}
The service uses ProseMirror’s toggleMark command:src/lib/core/editor-commands.service.ts
toggleBold(view: EditorView): boolean {
const command = toggleMark(EuclidesEditorSchema.marks['strong']);
return command(view.state, view.dispatch);
}
Lists are created using specialized commands:toggleList(type: 'bullet_list' | 'ordered_list') {
if (this.editorCommandsService.toggleList(type, this.view)) {
this.view.focus();
}
}
<button (click)="toggleList('bullet_list')">Bullet List</button>
<button (click)="toggleList('ordered_list')">Numbered List</button>
The editor supports:
- Bullet lists (
<ul>)
- Ordered lists (
<ol>)
- Proper nesting
- Enter key to create new items
- Tab/Shift+Tab for indentation
Text alignment modifies paragraph node attributes:toggleAlign(align: 'left' | 'center' | 'right' | 'justify') {
if (this.editorCommandsService.setTextAlign(align, this.view)) {
this.view.focus();
}
}
This works because the paragraph node includes a textAlign attribute:src/lib/engine/schema/euclides-schema.ts
const paragraph: NodeSpec = {
attrs: {
textAlign: { default: 'left' }
},
parseDOM: [{
tag: "p",
getAttrs: (dom: HTMLElement) => ({
textAlign: dom.style.textAlign || "left"
})
}],
toDOM(node: Node) {
return [
"p",
{ style: `text-align:${node.attrs['textAlign']}` },
0
];
}
};
Link management includes insertion, editing, and removal:applyLink(url: string) {
const { state, dispatch } = this.view;
const href = url.startsWith('http') ? url : 'https://' + url;
const linkInfo = getLinkRange(state);
if (linkInfo) {
// Update existing link
const { start, end } = linkInfo;
dispatch(
state.tr
.removeMark(start, end, state.schema.marks['link'])
.addMark(
start,
end,
state.schema.marks['link'].create({ href })
)
);
} else {
// Insert new link
const from = state.selection.from;
const tr = state.tr.insertText(href, from);
tr.addMark(
from,
from + href.length,
state.schema.marks['link'].create({ href })
);
dispatch(tr);
}
this.view.focus();
}
The editor includes a link popover component for a better UX. Undo/redo functionality is built-in using ProseMirror’s history plugin:import { undo, redo } from 'prosemirror-history';
undo() {
if (undo(this.view.state, this.view.dispatch)) {
this.view.focus();
}
}
redo() {
if (redo(this.view.state, this.view.dispatch)) {
this.view.focus();
}
}
The EditorStateService tracks whether undo/redo is available:<button [disabled]="!editorStateService.canUndo()" (click)="undo()">
Undo
</button>
<button [disabled]="!editorStateService.canRedo()" (click)="redo()">
Redo
</button>
Advanced Example
Here’s a more complete example showing how to integrate the editor into a form:
src/app/document-editor/document-editor.component.ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { EuclidesRichEditorComponent } from 'euclides-rich-editor';
@Component({
selector: 'app-document-editor',
standalone: true,
imports: [EuclidesRichEditorComponent, FormsModule],
template: `
<div class="document-form">
<div class="form-group">
<label for="title">Document Title</label>
<input
id="title"
type="text"
[(ngModel)]="title"
placeholder="Enter document title"
/>
</div>
<div class="form-group">
<label>Content</label>
<euclides-rich-editor />
</div>
<div class="form-actions">
<button (click)="save()">Save Document</button>
<button (click)="cancel()">Cancel</button>
</div>
</div>
`,
styles: [`
.document-form {
max-width: 1000px;
margin: 2rem auto;
padding: 2rem;
}
.form-group {
margin-bottom: 1.5rem;
}
label {
display: block;
margin-bottom: 0.5rem;
font-weight: 600;
color: #333;
}
input[type="text"] {
width: 100%;
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 1rem;
}
.form-actions {
display: flex;
gap: 1rem;
margin-top: 2rem;
}
button {
padding: 0.75rem 1.5rem;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
}
button:first-child {
background: #007bff;
color: white;
}
button:last-child {
background: #6c757d;
color: white;
}
`]
})
export class DocumentEditorComponent {
title: string = '';
save() {
console.log('Saving document:', this.title);
// Implement save logic
}
cancel() {
console.log('Cancelling edit');
// Implement cancel logic
}
}
Keyboard Shortcuts
The editor supports standard keyboard shortcuts:
| Shortcut | Action |
|---|
Ctrl/Cmd + B | Toggle bold |
Ctrl/Cmd + I | Toggle italic |
Ctrl/Cmd + Z | Undo |
Ctrl/Cmd + Shift + Z | Redo |
Ctrl/Cmd + Y | Redo (alternative) |
Enter | Create new paragraph or list item |
Shift + Enter | Hard line break |
Tab (in list) | Increase indentation |
Shift + Tab (in list) | Decrease indentation |
The keyboard shortcuts are defined in src/lib/engine/keymaps/euclides-keymaps.ts and can be customized if needed.
What’s Next?
Now that you have a working editor, explore these topics:
- Customization - Learn how to customize the editor’s appearance and behavior
- Schema Extension - Add custom nodes and marks to the editor
- Content Management - Extract and load editor content
- Plugins - Extend functionality with custom plugins
- API Reference - Explore all available methods and properties