@notectl/core 0.0.2 → 0.0.5

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.
@@ -8,6 +8,12 @@ export declare interface ApplyMarkOp extends BaseOperation {
8
8
  add: boolean;
9
9
  }
10
10
 
11
+ /**
12
+ * Default timeout for screen reader announcements
13
+ * Used to clear and reset the aria-live region
14
+ */
15
+ export declare const ARIA_ANNOUNCEMENT_DELAY = 100;
16
+
11
17
  /**
12
18
  * Attribute specification
13
19
  */
@@ -52,6 +58,33 @@ export declare interface BlockAttrs {
52
58
  [key: string]: unknown;
53
59
  }
54
60
 
61
+ /**
62
+ * Block type utilities
63
+ */
64
+ export declare interface BlockHelpers {
65
+ /**
66
+ * Check if a node is a text node
67
+ */
68
+ isTextNode(node: Node_2): node is TextNode;
69
+ /**
70
+ * Check if a node is a block node
71
+ */
72
+ isBlockNode(node: Node_2): node is BlockNode;
73
+ /**
74
+ * Get all text content from a block
75
+ */
76
+ getTextContent(block: BlockNode): string;
77
+ /**
78
+ * Check if block is empty
79
+ */
80
+ isEmpty(block: BlockNode): boolean;
81
+ }
82
+
83
+ /**
84
+ * Block helper implementation
85
+ */
86
+ export declare const blockHelpers: BlockHelpers;
87
+
55
88
  /**
56
89
  * Core type definitions for Notectl editor
57
90
  */
@@ -75,11 +108,33 @@ export declare interface BlockNode {
75
108
  */
76
109
  export declare function canCompose(deltaA: Delta, deltaB: Delta): boolean;
77
110
 
111
+ /**
112
+ * Command definition with type safety
113
+ */
114
+ export declare interface CommandDefinition<TArgs extends unknown[] = unknown[], TReturn = unknown> {
115
+ name: string;
116
+ description?: string;
117
+ handler: CommandHandler_2<TArgs, TReturn>;
118
+ }
119
+
78
120
  /**
79
121
  * Command handler function
80
122
  */
81
123
  export declare type CommandHandler = (...args: unknown[]) => unknown;
82
124
 
125
+ /**
126
+ * Command handler function signature
127
+ */
128
+ declare type CommandHandler_2<TArgs extends unknown[] = unknown[], TReturn = unknown> = (...args: TArgs) => TReturn | Promise<TReturn>;
129
+
130
+ /**
131
+ * Built-in command registry
132
+ * Maps command names to their handlers
133
+ */
134
+ export declare interface CommandRegistry {
135
+ [key: string]: CommandHandler_2<unknown[], unknown>;
136
+ }
137
+
83
138
  /**
84
139
  * Compose two deltas into a single delta
85
140
  * Applies deltaB after deltaA
@@ -109,6 +164,16 @@ export declare function createEditor(container: HTMLElement, config?: EditorConf
109
164
  */
110
165
  export declare function createNodeFactory(schema: Schema): NodeFactory;
111
166
 
167
+ /**
168
+ * Default maximum number of history entries to keep
169
+ */
170
+ export declare const DEFAULT_MAX_HISTORY_DEPTH = 100;
171
+
172
+ /**
173
+ * Default minimum height for the editor content area
174
+ */
175
+ export declare const DEFAULT_MIN_HEIGHT = 200;
176
+
112
177
  /**
113
178
  * Delete a block
114
179
  */
@@ -202,6 +267,23 @@ declare interface Document_2 {
202
267
  }
203
268
  export { Document_2 as Document }
204
269
 
270
+ /**
271
+ * Timeout in milliseconds to wait for editor's connectedCallback to complete
272
+ * and render the DOM structure including plugin containers.
273
+ *
274
+ * This is needed when registering plugins immediately after appending the editor
275
+ * to the DOM, as the connectedCallback runs asynchronously.
276
+ *
277
+ * @example
278
+ * ```typescript
279
+ * const editor = document.createElement('notectl-editor');
280
+ * container.appendChild(editor);
281
+ * await new Promise(resolve => setTimeout(resolve, EDITOR_READY_TIMEOUT));
282
+ * await editor.registerPlugin(new ToolbarPlugin());
283
+ * ```
284
+ */
285
+ export declare const EDITOR_READY_TIMEOUT = 100;
286
+
205
287
  /**
206
288
  * Editor API interface
207
289
  * Public methods exposed by the NotectlEditor class
@@ -239,6 +321,7 @@ export declare interface EditorConfig {
239
321
  autofocus?: boolean;
240
322
  sanitizeHTML?: boolean;
241
323
  maxHistoryDepth?: number;
324
+ content?: string | Document_2;
242
325
  [key: string]: unknown;
243
326
  }
244
327
 
@@ -346,6 +429,39 @@ export declare class EditorState {
346
429
  static fromJSON(json: Document_2, schema?: Schema): EditorState;
347
430
  }
348
431
 
432
+ /**
433
+ * Type for error codes
434
+ */
435
+ export declare type ErrorCode = typeof ErrorCodes[keyof typeof ErrorCodes];
436
+
437
+ /**
438
+ * Error codes for structured error handling
439
+ */
440
+ export declare const ErrorCodes: {
441
+ readonly PLUGIN_ALREADY_REGISTERED: "PLUGIN_ALREADY_REGISTERED";
442
+ readonly PLUGIN_NOT_FOUND: "PLUGIN_NOT_FOUND";
443
+ readonly PLUGIN_MISSING_DEPENDENCY: "PLUGIN_MISSING_DEPENDENCY";
444
+ readonly PLUGIN_INVALID_CONFIG: "PLUGIN_INVALID_CONFIG";
445
+ readonly PLUGIN_INIT_FAILED: "PLUGIN_INIT_FAILED";
446
+ readonly PLUGIN_DESTROY_FAILED: "PLUGIN_DESTROY_FAILED";
447
+ readonly PLUGIN_DEPENDENCY_CONFLICT: "PLUGIN_DEPENDENCY_CONFLICT";
448
+ readonly EDITOR_NOT_MOUNTED: "EDITOR_NOT_MOUNTED";
449
+ readonly EDITOR_NOT_INITIALIZED: "EDITOR_NOT_INITIALIZED";
450
+ readonly EDITOR_DESTROYED: "EDITOR_DESTROYED";
451
+ readonly COMMAND_NOT_FOUND: "COMMAND_NOT_FOUND";
452
+ readonly COMMAND_ALREADY_REGISTERED: "COMMAND_ALREADY_REGISTERED";
453
+ readonly COMMAND_EXECUTION_FAILED: "COMMAND_EXECUTION_FAILED";
454
+ readonly COMMAND_INVALID_ARGS: "COMMAND_INVALID_ARGS";
455
+ readonly INVALID_CONTENT: "INVALID_CONTENT";
456
+ readonly INVALID_DELTA: "INVALID_DELTA";
457
+ readonly INVALID_DOCUMENT: "INVALID_DOCUMENT";
458
+ readonly SANITIZATION_FAILED: "SANITIZATION_FAILED";
459
+ readonly XSS_DETECTED: "XSS_DETECTED";
460
+ readonly UNSAFE_OPERATION: "UNSAFE_OPERATION";
461
+ readonly INVALID_OPERATION: "INVALID_OPERATION";
462
+ readonly INTERNAL_ERROR: "INTERNAL_ERROR";
463
+ };
464
+
349
465
  /**
350
466
  * Error response envelope
351
467
  */
@@ -538,6 +654,10 @@ export declare class NotectlEditor extends HTMLElement {
538
654
  private config;
539
655
  private keyboardShortcutCleanup?;
540
656
  private ariaLiveRegion;
657
+ private pendingPlugins;
658
+ private readyPromise;
659
+ private readyResolve?;
660
+ private isReady;
541
661
  constructor();
542
662
  /**
543
663
  * Observed attributes for the web component
@@ -546,7 +666,7 @@ export declare class NotectlEditor extends HTMLElement {
546
666
  /**
547
667
  * Called when element is connected to DOM
548
668
  */
549
- connectedCallback(): void;
669
+ connectedCallback(): Promise<void>;
550
670
  /**
551
671
  * Called when element is disconnected from DOM
552
672
  */
@@ -583,6 +703,10 @@ export declare class NotectlEditor extends HTMLElement {
583
703
  * Escape HTML
584
704
  */
585
705
  private escapeHTML;
706
+ private tableToHTML;
707
+ private tableRowToHTML;
708
+ private tableCellToHTML;
709
+ private styleObjectToString;
586
710
  /**
587
711
  * Setup accessibility features
588
712
  */
@@ -627,6 +751,7 @@ export declare class NotectlEditor extends HTMLElement {
627
751
  * Handle blur event
628
752
  */
629
753
  private handleBlur;
754
+ private handleContextMenu;
630
755
  /**
631
756
  * Update placeholder visibility
632
757
  */
@@ -657,12 +782,81 @@ export declare class NotectlEditor extends HTMLElement {
657
782
  private updateReadonly;
658
783
  /**
659
784
  * Register a plugin
785
+ *
786
+ * Plugins can be registered before or after the editor is mounted.
787
+ * If registered before mounting, they will be queued and initialized
788
+ * automatically when the editor connects to the DOM.
789
+ *
790
+ * @param plugin - The plugin to register
791
+ * @returns Promise that resolves when the plugin is registered
660
792
  */
661
793
  registerPlugin(plugin: Plugin_2): Promise<void>;
662
794
  /**
663
795
  * Unregister a plugin
664
796
  */
665
797
  unregisterPlugin(pluginId: string): Promise<void>;
798
+ /**
799
+ * Wait for the editor to be ready
800
+ *
801
+ * Returns a Promise that resolves when the editor has been mounted
802
+ * and all pending plugins have been initialized. This is useful when
803
+ * you need to ensure the editor is fully initialized before performing
804
+ * operations that depend on the editor being mounted.
805
+ *
806
+ * @returns Promise that resolves when the editor is ready
807
+ * @example
808
+ * ```typescript
809
+ * const editor = document.createElement('notectl-editor');
810
+ * container.appendChild(editor);
811
+ * await editor.whenReady();
812
+ * // Editor is now fully initialized
813
+ * ```
814
+ */
815
+ whenReady(): Promise<void>;
816
+ /**
817
+ * Get the block containing the current selection
818
+ */
819
+ private getSelectedBlock;
820
+ /**
821
+ * Find all blocks of a specific type
822
+ */
823
+ private findBlocksByType;
824
+ /**
825
+ * Find parent block of a given block
826
+ */
827
+ private findParentBlock;
828
+ /**
829
+ * Get block at current cursor position
830
+ */
831
+ private getBlockAtCursor;
832
+ /**
833
+ * Insert a block after another block (Delta-based)
834
+ */
835
+ private insertBlockAfter;
836
+ /**
837
+ * Insert a block before another block (Delta-based)
838
+ */
839
+ private insertBlockBefore;
840
+ /**
841
+ * Update block attributes (Delta-based)
842
+ */
843
+ private updateBlockAttrs;
844
+ /**
845
+ * Delete a block (Delta-based)
846
+ */
847
+ private deleteBlockById;
848
+ /**
849
+ * Add mark to current selection (Delta-based)
850
+ */
851
+ private addMarkToSelection;
852
+ /**
853
+ * Remove mark from current selection (Delta-based)
854
+ */
855
+ private removeMarkFromSelection;
856
+ /**
857
+ * Toggle mark on current selection (Delta-based)
858
+ */
859
+ private toggleMarkOnSelection;
666
860
  /**
667
861
  * Create plugin context
668
862
  */
@@ -755,6 +949,25 @@ export declare class NotectlEditor extends HTMLElement {
755
949
  blur(): void;
756
950
  }
757
951
 
952
+ /**
953
+ * Structured error class for Notectl
954
+ */
955
+ export declare class NotectlError extends Error {
956
+ code: ErrorCode;
957
+ details?: unknown | undefined;
958
+ constructor(code: ErrorCode, message: string, details?: unknown | undefined);
959
+ /**
960
+ * Convert to JSON-serializable format
961
+ */
962
+ toJSON(): {
963
+ error: {
964
+ code: ErrorCode;
965
+ message: string;
966
+ details: unknown;
967
+ };
968
+ };
969
+ }
970
+
758
971
  /**
759
972
  * Union of all operation types
760
973
  */
@@ -811,6 +1024,78 @@ export declare interface PluginContext {
811
1024
  * Apply a delta to the editor
812
1025
  */
813
1026
  applyDelta(delta: Delta): void;
1027
+ /**
1028
+ * Get current selection
1029
+ */
1030
+ getSelection(): Selection_2 | null;
1031
+ /**
1032
+ * Set selection
1033
+ */
1034
+ setSelection(selection: Selection_2): void;
1035
+ /**
1036
+ * Get the block containing the current cursor/selection
1037
+ */
1038
+ getSelectedBlock(): BlockNode | null;
1039
+ /**
1040
+ * Find all blocks of a specific type
1041
+ * @param type - Block type to search for (e.g., 'table', 'heading', 'paragraph')
1042
+ * @returns Array of matching blocks
1043
+ */
1044
+ findBlocksByType(type: string): BlockNode[];
1045
+ /**
1046
+ * Find a block by its ID
1047
+ * @param blockId - Block identifier
1048
+ * @returns Block or undefined if not found
1049
+ */
1050
+ findBlockById(blockId: BlockId): BlockNode | undefined;
1051
+ /**
1052
+ * Find parent block of a given block
1053
+ * @param block - Child block
1054
+ * @returns Parent block or null if block is at root level
1055
+ */
1056
+ findParentBlock(block: BlockNode): BlockNode | null;
1057
+ /**
1058
+ * Get block at current cursor position
1059
+ */
1060
+ getBlockAtCursor(): BlockNode | null;
1061
+ /**
1062
+ * Insert a block after another block
1063
+ * @param block - Block to insert
1064
+ * @param afterId - ID of block to insert after (if undefined, appends to end)
1065
+ */
1066
+ insertBlockAfter(block: BlockNode, afterId?: BlockId): void;
1067
+ /**
1068
+ * Insert a block before another block
1069
+ * @param block - Block to insert
1070
+ * @param beforeId - ID of block to insert before (if undefined, prepends to start)
1071
+ */
1072
+ insertBlockBefore(block: BlockNode, beforeId?: BlockId): void;
1073
+ /**
1074
+ * Update block attributes
1075
+ * @param blockId - Block to update
1076
+ * @param attrs - Attributes to merge
1077
+ */
1078
+ updateBlockAttrs(blockId: BlockId, attrs: Record<string, unknown>): void;
1079
+ /**
1080
+ * Delete a block
1081
+ * @param blockId - Block to delete
1082
+ */
1083
+ deleteBlock(blockId: BlockId): void;
1084
+ /**
1085
+ * Add mark to current selection
1086
+ * @param mark - Mark to add
1087
+ */
1088
+ addMark(mark: Mark): void;
1089
+ /**
1090
+ * Remove mark from current selection
1091
+ * @param markType - Type of mark to remove
1092
+ */
1093
+ removeMark(markType: string): void;
1094
+ /**
1095
+ * Toggle mark on current selection
1096
+ * @param markType - Type of mark to toggle
1097
+ */
1098
+ toggleMark(markType: string): void;
814
1099
  /**
815
1100
  * Register event listener
816
1101
  */
@@ -833,6 +1118,7 @@ export declare interface PluginContext {
833
1118
  executeCommand(name: string, ...args: unknown[]): unknown;
834
1119
  /**
835
1120
  * Access DOM container (editable area)
1121
+ * @deprecated Prefer using Delta operations instead of direct DOM manipulation
836
1122
  */
837
1123
  getContainer(): HTMLElement;
838
1124
  /**
@@ -856,10 +1142,29 @@ export declare class PluginManager {
856
1142
  constructor();
857
1143
  /**
858
1144
  * Register a plugin
1145
+ *
1146
+ * @param plugin - The plugin to register
1147
+ * @param context - Plugin context with editor APIs
1148
+ * @throws {NotectlError} If plugin validation fails or initialization errors occur
1149
+ *
1150
+ * @example
1151
+ * ```typescript
1152
+ * const toolbarPlugin = new ToolbarPlugin();
1153
+ * await pluginManager.register(toolbarPlugin, context);
1154
+ * ```
859
1155
  */
860
1156
  register(plugin: Plugin_2, context: PluginContext): Promise<void>;
861
1157
  /**
862
1158
  * Unregister a plugin
1159
+ *
1160
+ * @param pluginId - ID of the plugin to unregister
1161
+ * @param context - Plugin context for event emission
1162
+ * @throws {NotectlError} If plugin is not found or has dependents
1163
+ *
1164
+ * @example
1165
+ * ```typescript
1166
+ * await pluginManager.unregister('toolbar-plugin', context);
1167
+ * ```
863
1168
  */
864
1169
  unregister(pluginId: string, context: PluginContext): Promise<void>;
865
1170
  /**
@@ -951,6 +1256,37 @@ declare interface Selection_2 {
951
1256
  }
952
1257
  export { Selection_2 as Selection }
953
1258
 
1259
+ /**
1260
+ * Selection helper utilities
1261
+ */
1262
+ export declare interface SelectionHelpers {
1263
+ /**
1264
+ * Check if selection is collapsed (cursor)
1265
+ */
1266
+ isCollapsed(selection: Selection_2): boolean;
1267
+ /**
1268
+ * Check if selection spans multiple blocks
1269
+ */
1270
+ isMultiBlock(selection: Selection_2): boolean;
1271
+ /**
1272
+ * Get the direction of selection (forward/backward)
1273
+ */
1274
+ getDirection(selection: Selection_2): 'forward' | 'backward' | 'none';
1275
+ /**
1276
+ * Create a collapsed selection at a position
1277
+ */
1278
+ createCollapsed(position: Position): Selection_2;
1279
+ /**
1280
+ * Create a selection range
1281
+ */
1282
+ createRange(start: Position, end: Position): Selection_2;
1283
+ }
1284
+
1285
+ /**
1286
+ * Selection helper implementation
1287
+ */
1288
+ export declare const selectionHelpers: SelectionHelpers;
1289
+
954
1290
  /**
955
1291
  * Set attributes on a block
956
1292
  */
@@ -962,6 +1298,27 @@ export declare interface SetAttrsOp extends BaseOperation {
962
1298
  attrs: BlockAttrs;
963
1299
  }
964
1300
 
1301
+ /**
1302
+ * Table cell structure
1303
+ */
1304
+ export declare interface TableCell {
1305
+ id?: string;
1306
+ content: string;
1307
+ rowSpan?: number;
1308
+ colSpan?: number;
1309
+ attrs?: {
1310
+ style?: Record<string, string | number>;
1311
+ [key: string]: unknown;
1312
+ };
1313
+ }
1314
+
1315
+ /**
1316
+ * Table structure for attributes
1317
+ */
1318
+ export declare interface TableData {
1319
+ rows: TableRow[];
1320
+ }
1321
+
965
1322
  /**
966
1323
  * Table operation: delete column
967
1324
  */
@@ -1018,6 +1375,18 @@ export declare interface TableMergeCellsOp extends BaseOperation {
1018
1375
  };
1019
1376
  }
1020
1377
 
1378
+ /**
1379
+ * Table row structure
1380
+ */
1381
+ export declare interface TableRow {
1382
+ id?: string;
1383
+ cells: TableCell[];
1384
+ attrs?: {
1385
+ style?: Record<string, string | number>;
1386
+ [key: string]: unknown;
1387
+ };
1388
+ }
1389
+
1021
1390
  /**
1022
1391
  * Table operation: split cell
1023
1392
  */
@@ -1075,6 +1444,16 @@ export declare function validateDelta(delta: Delta): {
1075
1444
  */
1076
1445
  export declare type ValidationConstraint = 'noDanglingRefs' | 'tableGridConsistent' | 'altOrDecorative' | 'rtlIntegrity' | string;
1077
1446
 
1447
+ /**
1448
+ * Validation constraints for document structure
1449
+ */
1450
+ export declare const ValidationConstraints: {
1451
+ readonly NO_DANGLING_REFS: "noDanglingRefs";
1452
+ readonly TABLE_GRID_CONSISTENT: "tableGridConsistent";
1453
+ readonly ALT_OR_DECORATIVE: "altOrDecorative";
1454
+ readonly RTL_INTEGRITY: "rtlIntegrity";
1455
+ };
1456
+
1078
1457
  export declare const VERSION = "0.0.1";
1079
1458
 
1080
1459
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notectl/core",
3
- "version": "0.0.2",
3
+ "version": "0.0.5",
4
4
  "description": "Framework-agnostic rich text editor core for Notectl",
5
5
  "type": "module",
6
6
  "main": "./dist/notectl-core.umd.cjs",
@@ -51,7 +51,7 @@
51
51
  },
52
52
  "repository": {
53
53
  "type": "git",
54
- "url": "git+https://github.com/neuravision-io/notectl.git",
54
+ "url": "git+https://github.com/Samyssmile/notectl.git",
55
55
  "directory": "packages/core"
56
56
  }
57
57
  }