@notectl/angular 0.0.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,58 +1,55 @@
1
1
  {
2
2
  "name": "@notectl/angular",
3
- "version": "0.0.4",
4
- "description": "Angular adapter for NotectlEditor",
5
- "main": "./dist/index.js",
6
- "module": "./dist/index.mjs",
7
- "types": "./dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.mjs",
12
- "require": "./dist/index.js"
13
- }
14
- },
3
+ "version": "1.0.0",
4
+ "description": "Angular integration for the notectl rich text editor. Provides a standalone component, reactive forms support, and DI service.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "module": "fesm2022/notectl-angular.mjs",
8
+ "typings": "types/notectl-angular.d.ts",
9
+ "sideEffects": false,
15
10
  "files": [
16
11
  "dist",
17
- "src",
18
12
  "README.md"
19
13
  ],
20
- "scripts": {
21
- "build": "ng-packagr -p ng-package.json",
22
- "test": "echo \"No tests yet\"",
23
- "lint": "eslint src --ext .ts",
24
- "typecheck": "tsc --noEmit"
25
- },
26
14
  "keywords": [
15
+ "angular",
16
+ "rich-text-editor",
27
17
  "notectl",
18
+ "web-component",
28
19
  "editor",
29
- "angular",
30
- "rich-text",
31
- "wysiwyg"
20
+ "wysiwyg",
21
+ "reactive-forms",
22
+ "signals"
32
23
  ],
33
- "author": "Samuel Abramov",
34
- "license": "MIT",
35
- "peerDependencies": {
36
- "@angular/common": ">=14.0.0",
37
- "@angular/core": ">=14.0.0",
38
- "@angular/forms": ">=14.0.0",
39
- "@notectl/core": "*"
40
- },
41
- "devDependencies": {
42
- "@angular/common": "^17.0.0",
43
- "@angular/compiler": "^17.0.0",
44
- "@angular/compiler-cli": "^17.0.0",
45
- "@angular/core": "^17.0.0",
46
- "@angular/forms": "^17.0.0",
47
- "ng-packagr": "^17.0.0",
48
- "typescript": "^5.3.0"
49
- },
50
24
  "repository": {
51
25
  "type": "git",
52
- "url": "git+https://github.com/Samyssmile/notectl.git",
53
- "directory": "packages/adapters/angular"
26
+ "url": "https://github.com/Samyssmile/notectl.git",
27
+ "directory": "packages/angular"
28
+ },
29
+ "homepage": "https://github.com/Samyssmile/notectl",
30
+ "bugs": {
31
+ "url": "https://github.com/Samyssmile/notectl/issues"
54
32
  },
55
- "publishConfig": {
56
- "access": "public"
33
+ "dependencies": {
34
+ "tslib": "^2.3.0"
35
+ },
36
+ "peerDependencies": {
37
+ "@angular/core": ">=21.0.0",
38
+ "@angular/forms": ">=21.0.0",
39
+ "@notectl/core": "^1.0.0",
40
+ "rxjs": ">=7.0.0"
41
+ },
42
+ "exports": {
43
+ "./package.json": {
44
+ "default": "./package.json"
45
+ },
46
+ ".": {
47
+ "types": "./types/notectl-angular.d.ts",
48
+ "default": "./fesm2022/notectl-angular.mjs"
49
+ },
50
+ "./testing": {
51
+ "types": "./types/notectl-angular-testing.d.ts",
52
+ "default": "./fesm2022/notectl-angular-testing.mjs"
53
+ }
57
54
  }
58
- }
55
+ }
package/README.md DELETED
@@ -1,141 +0,0 @@
1
- # @notectl/angular
2
-
3
- Angular adapter for NotectlEditor - a framework-agnostic rich text editor built on Web Components.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install @notectl/angular @notectl/core
9
- ```
10
-
11
- ## Usage
12
-
13
- ### Import Module
14
-
15
- ```typescript
16
- import { NgModule } from '@angular/core';
17
- import { BrowserModule } from '@angular/platform-browser';
18
- import { NotectlEditorModule } from '@notectl/angular';
19
- import { AppComponent } from './app.component';
20
-
21
- @NgModule({
22
- declarations: [AppComponent],
23
- imports: [
24
- BrowserModule,
25
- NotectlEditorModule
26
- ],
27
- providers: [],
28
- bootstrap: [AppComponent]
29
- })
30
- export class AppModule { }
31
- ```
32
-
33
- ### Component Usage
34
-
35
- ```typescript
36
- import { Component } from '@angular/core';
37
- import type { EditorAPI } from '@notectl/core';
38
-
39
- @Component({
40
- selector: 'app-root',
41
- template: `
42
- <notectl-editor
43
- [content]="content"
44
- [placeholder]="'Start writing...'"
45
- [readOnly]="false"
46
- (contentChange)="onContentChange($event)"
47
- (ready)="onReady($event)"
48
- ></notectl-editor>
49
- `
50
- })
51
- export class AppComponent {
52
- content = { type: 'doc', content: [] };
53
-
54
- onContentChange(content: unknown): void {
55
- console.log('Content changed:', content);
56
- }
57
-
58
- onReady(editor: EditorAPI): void {
59
- console.log('Editor ready:', editor);
60
- }
61
- }
62
- ```
63
-
64
- ### Reactive Forms Integration
65
-
66
- ```typescript
67
- import { Component } from '@angular/core';
68
- import { FormControl, FormGroup } from '@angular/forms';
69
-
70
- @Component({
71
- selector: 'app-editor-form',
72
- template: `
73
- <form [formGroup]="form">
74
- <notectl-editor formControlName="content"></notectl-editor>
75
- </form>
76
- `
77
- })
78
- export class EditorFormComponent {
79
- form = new FormGroup({
80
- content: new FormControl(null)
81
- });
82
- }
83
- ```
84
-
85
- ### Directive Usage
86
-
87
- ```typescript
88
- import { Component } from '@angular/core';
89
-
90
- @Component({
91
- selector: 'app-editor',
92
- template: `
93
- <div
94
- notectl-editor
95
- [content]="content"
96
- (contentChange)="onContentChange($event)"
97
- ></div>
98
- `
99
- })
100
- export class EditorComponent {
101
- content = { type: 'doc', content: [] };
102
-
103
- onContentChange(content: unknown): void {
104
- console.log('Content changed:', content);
105
- }
106
- }
107
- ```
108
-
109
- ## API
110
-
111
- ### Component Props
112
-
113
- - `debug?: boolean` - Enable debug mode
114
- - `content?: string | object` - Initial editor content
115
- - `placeholder?: string` - Placeholder text
116
- - `readOnly?: boolean` - Read-only mode
117
- - `accessibility?: object` - Accessibility configuration
118
- - `i18n?: object` - Internationalization settings
119
- - `theme?: object` - Theme configuration
120
-
121
- ### Component Events
122
-
123
- - `contentChange: EventEmitter<unknown>` - Emitted when content changes
124
- - `selectionChange: EventEmitter<unknown>` - Emitted when selection changes
125
- - `editorFocus: EventEmitter<void>` - Emitted when editor gains focus
126
- - `editorBlur: EventEmitter<void>` - Emitted when editor loses focus
127
- - `ready: EventEmitter<EditorAPI>` - Emitted when editor is ready
128
- - `error: EventEmitter<Error>` - Emitted when an error occurs
129
-
130
- ### Component Methods
131
-
132
- - `getContent(): unknown` - Get current content
133
- - `setContent(content: unknown): void` - Set content
134
- - `getState(): unknown` - Get editor state
135
- - `executeCommand(command: string, ...args: unknown[]): void` - Execute command
136
- - `registerPlugin(plugin: unknown): void` - Register a plugin
137
- - `unregisterPlugin(pluginId: string): void` - Unregister a plugin
138
-
139
- ## License
140
-
141
- MIT
package/src/index.ts DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * @notectl/angular - Angular adapter for NotectlEditor
3
- * @packageDocumentation
4
- */
5
-
6
- export * from './public-api';
@@ -1,261 +0,0 @@
1
- /**
2
- * Angular component wrapper for NotectlEditor
3
- */
4
-
5
- import {
6
- Component,
7
- ElementRef,
8
- EventEmitter,
9
- Input,
10
- OnDestroy,
11
- OnInit,
12
- Output,
13
- ViewChild,
14
- ViewEncapsulation,
15
- forwardRef,
16
- } from '@angular/core';
17
- import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
18
- import { NotectlEditor as NotectlEditorCore } from '@notectl/core';
19
- import type { EditorConfig, EditorAPI } from '@notectl/core';
20
-
21
- /**
22
- * NotectlEditor Angular component
23
- */
24
- @Component({
25
- selector: 'notectl-editor',
26
- template: '<div #container [attr.data-notectl-angular-wrapper]="true"></div>',
27
- styles: [':host { display: block; }'],
28
- encapsulation: ViewEncapsulation.None,
29
- providers: [
30
- {
31
- provide: NG_VALUE_ACCESSOR,
32
- useExisting: forwardRef(() => NotectlEditorComponent),
33
- multi: true,
34
- },
35
- ],
36
- })
37
- export class NotectlEditorComponent implements OnInit, OnDestroy, ControlValueAccessor {
38
- @ViewChild('container', { static: true }) containerRef!: ElementRef<HTMLDivElement>;
39
-
40
- /** Debug mode */
41
- @Input() debug?: boolean;
42
-
43
- /** Initial content */
44
- @Input() content?: string | object;
45
-
46
- /** Placeholder text */
47
- @Input() placeholder?: string;
48
-
49
- /** Read-only mode */
50
- @Input() readOnly?: boolean;
51
-
52
- /** Accessibility configuration */
53
- @Input() accessibility?: EditorConfig['accessibility'];
54
-
55
- /** Internationalization configuration */
56
- @Input() i18n?: EditorConfig['i18n'];
57
-
58
- /** Theme configuration */
59
- @Input() theme?: EditorConfig['theme'];
60
-
61
- /** Custom class name */
62
- @Input() className?: string;
63
-
64
- /** Emitted when content changes */
65
- @Output() contentChange = new EventEmitter<unknown>();
66
-
67
- /** Emitted when selection changes */
68
- @Output() selectionChange = new EventEmitter<unknown>();
69
-
70
- /** Emitted when editor gains focus */
71
- @Output() editorFocus = new EventEmitter<void>();
72
-
73
- /** Emitted when editor loses focus */
74
- @Output() editorBlur = new EventEmitter<void>();
75
-
76
- /** Emitted when editor is ready */
77
- @Output() ready = new EventEmitter<EditorAPI>();
78
-
79
- /** Emitted when an error occurs */
80
- @Output() error = new EventEmitter<Error>();
81
-
82
- private editor: NotectlEditorCore | null = null;
83
- private onChange: (value: unknown) => void = () => {};
84
- private onTouched: () => void = () => {};
85
-
86
- ngOnInit(): void {
87
- this.initEditor();
88
- }
89
-
90
- ngOnDestroy(): void {
91
- this.destroyEditor();
92
- }
93
-
94
- /**
95
- * Initialize the editor instance
96
- */
97
- private initEditor(): void {
98
- if (!this.containerRef?.nativeElement) {
99
- console.error('NotectlEditor: Container element not found');
100
- return;
101
- }
102
-
103
- // Create editor instance
104
- this.editor = document.createElement('notectl-editor') as NotectlEditorCore;
105
-
106
- // Configure editor
107
- const config: EditorConfig = {
108
- debug: this.debug,
109
- content: this.content,
110
- placeholder: this.placeholder,
111
- readOnly: this.readOnly,
112
- accessibility: this.accessibility,
113
- i18n: this.i18n,
114
- theme: this.theme,
115
- };
116
- this.editor.configure(config);
117
-
118
- // Attach event listeners
119
- this.editor.on('content-change', (data) => {
120
- const eventData = data as { content?: unknown };
121
- const content = eventData.content;
122
- this.contentChange.emit(content);
123
- this.onChange(content);
124
- });
125
-
126
- this.editor.on('selection-change', (data) => {
127
- const eventData = data as { selection?: unknown };
128
- this.selectionChange.emit(eventData.selection);
129
- });
130
-
131
- this.editor.on('focus', () => {
132
- this.editorFocus.emit();
133
- this.onTouched();
134
- });
135
-
136
- this.editor.on('blur', () => {
137
- this.editorBlur.emit();
138
- });
139
-
140
- this.editor.on('ready', () => {
141
- this.ready.emit(this.getEditorAPI());
142
- });
143
-
144
- this.editor.on('error', (data) => {
145
- const eventData = data as { error?: Error };
146
- if (eventData.error) {
147
- this.error.emit(eventData.error);
148
- }
149
- });
150
-
151
- // Mount editor
152
- this.containerRef.nativeElement.appendChild(this.editor);
153
- }
154
-
155
- /**
156
- * Destroy the editor instance
157
- */
158
- private destroyEditor(): void {
159
- if (this.editor) {
160
- this.editor.destroy();
161
- if (this.containerRef?.nativeElement?.contains(this.editor)) {
162
- this.containerRef.nativeElement.removeChild(this.editor);
163
- }
164
- this.editor = null;
165
- }
166
- }
167
-
168
- /**
169
- * Update editor configuration
170
- */
171
- private updateConfig(): void {
172
- if (!this.editor) return;
173
-
174
- const config: EditorConfig = {
175
- debug: this.debug,
176
- content: this.content,
177
- placeholder: this.placeholder,
178
- readOnly: this.readOnly,
179
- accessibility: this.accessibility,
180
- i18n: this.i18n,
181
- theme: this.theme,
182
- };
183
- this.editor.configure(config);
184
- }
185
-
186
- /**
187
- * Get editor API
188
- */
189
- private getEditorAPI(): EditorAPI {
190
- if (!this.editor) {
191
- throw new Error('Editor not initialized');
192
- }
193
- return this.editor as EditorAPI;
194
- }
195
-
196
- // ControlValueAccessor implementation
197
- writeValue(value: unknown): void {
198
- if (this.editor && typeof value === 'string') {
199
- this.editor.setContent(value);
200
- }
201
- }
202
-
203
- registerOnChange(fn: (value: unknown) => void): void {
204
- this.onChange = fn;
205
- }
206
-
207
- registerOnTouched(fn: () => void): void {
208
- this.onTouched = fn;
209
- }
210
-
211
- setDisabledState(isDisabled: boolean): void {
212
- if (this.editor) {
213
- this.editor.configure({ readOnly: isDisabled });
214
- }
215
- }
216
-
217
- // Public API methods
218
- /**
219
- * Get current editor content
220
- */
221
- public getContent(): unknown {
222
- return this.editor?.getContent();
223
- }
224
-
225
- /**
226
- * Set editor content
227
- */
228
- public setContent(content: unknown): void {
229
- if (this.editor && typeof content === 'string') {
230
- this.editor.setContent(content);
231
- }
232
- }
233
-
234
- /**
235
- * Get current editor state
236
- */
237
- public getState(): unknown {
238
- return this.editor?.getState();
239
- }
240
-
241
- /**
242
- * Execute an editor command
243
- */
244
- public executeCommand(command: string, ...args: unknown[]): void {
245
- this.editor?.executeCommand(command, ...args);
246
- }
247
-
248
- /**
249
- * Register a plugin
250
- */
251
- public registerPlugin(plugin: unknown): void {
252
- this.editor?.registerPlugin(plugin as any);
253
- }
254
-
255
- /**
256
- * Unregister a plugin
257
- */
258
- public unregisterPlugin(pluginId: string): void {
259
- this.editor?.unregisterPlugin(pluginId);
260
- }
261
- }
@@ -1,156 +0,0 @@
1
- /**
2
- * Angular directive for NotectlEditor (optional alternative to component)
3
- */
4
-
5
- import {
6
- Directive,
7
- ElementRef,
8
- EventEmitter,
9
- Input,
10
- OnDestroy,
11
- OnInit,
12
- Output,
13
- forwardRef,
14
- } from '@angular/core';
15
- import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
16
- import { NotectlEditor as NotectlEditorCore } from '@notectl/core';
17
- import type { EditorConfig, EditorAPI } from '@notectl/core';
18
-
19
- /**
20
- * Directive to use NotectlEditor on any element
21
- * Usage: <div notectl-editor [content]="content"></div>
22
- */
23
- @Directive({
24
- selector: '[notectl-editor]',
25
- providers: [
26
- {
27
- provide: NG_VALUE_ACCESSOR,
28
- useExisting: forwardRef(() => NotectlEditorDirective),
29
- multi: true,
30
- },
31
- ],
32
- })
33
- export class NotectlEditorDirective implements OnInit, OnDestroy, ControlValueAccessor {
34
- @Input() debug?: boolean;
35
- @Input() content?: string | object;
36
- @Input() placeholder?: string;
37
- @Input() readOnly?: boolean;
38
- @Input() accessibility?: EditorConfig['accessibility'];
39
- @Input() i18n?: EditorConfig['i18n'];
40
- @Input() theme?: EditorConfig['theme'];
41
-
42
- @Output() contentChange = new EventEmitter<unknown>();
43
- @Output() selectionChange = new EventEmitter<unknown>();
44
- @Output() editorFocus = new EventEmitter<void>();
45
- @Output() editorBlur = new EventEmitter<void>();
46
- @Output() ready = new EventEmitter<EditorAPI>();
47
- @Output() error = new EventEmitter<Error>();
48
-
49
- private editor: NotectlEditorCore | null = null;
50
- private onChange: (value: unknown) => void = () => {};
51
- private onTouched: () => void = () => {};
52
-
53
- constructor(private elementRef: ElementRef<HTMLElement>) {}
54
-
55
- ngOnInit(): void {
56
- this.initEditor();
57
- }
58
-
59
- ngOnDestroy(): void {
60
- this.destroyEditor();
61
- }
62
-
63
- private initEditor(): void {
64
- const hostElement = this.elementRef.nativeElement;
65
-
66
- // Create editor instance
67
- this.editor = document.createElement('notectl-editor') as NotectlEditorCore;
68
-
69
- // Configure editor
70
- const config: EditorConfig = {
71
- debug: this.debug,
72
- content: this.content,
73
- placeholder: this.placeholder,
74
- readOnly: this.readOnly,
75
- accessibility: this.accessibility,
76
- i18n: this.i18n,
77
- theme: this.theme,
78
- };
79
- this.editor.configure(config);
80
-
81
- // Attach event listeners
82
- this.editor.on('content-change', (data) => {
83
- const eventData = data as { content?: unknown };
84
- const content = eventData.content;
85
- this.contentChange.emit(content);
86
- this.onChange(content);
87
- });
88
-
89
- this.editor.on('selection-change', (data) => {
90
- const eventData = data as { selection?: unknown };
91
- this.selectionChange.emit(eventData.selection);
92
- });
93
-
94
- this.editor.on('focus', () => {
95
- this.editorFocus.emit();
96
- this.onTouched();
97
- });
98
-
99
- this.editor.on('blur', () => {
100
- this.editorBlur.emit();
101
- });
102
-
103
- this.editor.on('ready', () => {
104
- this.ready.emit(this.getEditorAPI());
105
- });
106
-
107
- this.editor.on('error', (data) => {
108
- const eventData = data as { error?: Error };
109
- if (eventData.error) {
110
- this.error.emit(eventData.error);
111
- }
112
- });
113
-
114
- // Mount editor
115
- hostElement.appendChild(this.editor);
116
- }
117
-
118
- private destroyEditor(): void {
119
- if (this.editor) {
120
- this.editor.destroy();
121
- const hostElement = this.elementRef.nativeElement;
122
- if (hostElement.contains(this.editor)) {
123
- hostElement.removeChild(this.editor);
124
- }
125
- this.editor = null;
126
- }
127
- }
128
-
129
- private getEditorAPI(): EditorAPI {
130
- if (!this.editor) {
131
- throw new Error('Editor not initialized');
132
- }
133
- return this.editor as EditorAPI;
134
- }
135
-
136
- // ControlValueAccessor implementation
137
- writeValue(value: unknown): void {
138
- if (this.editor && typeof value === 'string') {
139
- this.editor.setContent(value);
140
- }
141
- }
142
-
143
- registerOnChange(fn: (value: unknown) => void): void {
144
- this.onChange = fn;
145
- }
146
-
147
- registerOnTouched(fn: () => void): void {
148
- this.onTouched = fn;
149
- }
150
-
151
- setDisabledState(isDisabled: boolean): void {
152
- if (this.editor) {
153
- this.editor.configure({ readOnly: isDisabled });
154
- }
155
- }
156
- }
@@ -1,14 +0,0 @@
1
- /**
2
- * Angular module for NotectlEditor
3
- */
4
-
5
- import { NgModule } from '@angular/core';
6
- import { CommonModule } from '@angular/common';
7
- import { NotectlEditorComponent } from './notectl-editor.component';
8
-
9
- @NgModule({
10
- declarations: [NotectlEditorComponent],
11
- imports: [CommonModule],
12
- exports: [NotectlEditorComponent],
13
- })
14
- export class NotectlEditorModule {}
package/src/public-api.ts DELETED
@@ -1,7 +0,0 @@
1
- /**
2
- * Public API surface of @notectl/angular
3
- */
4
-
5
- export * from './lib/notectl-editor.component';
6
- export * from './lib/notectl-editor.module';
7
- export * from './lib/notectl-editor.directive';