croco-html 20.4.5 → 20.5.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,6 +1,6 @@
1
1
  {
2
2
  "name": "croco-html",
3
- "version": "20.4.5",
3
+ "version": "20.5.0",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^20.3.15",
6
6
  "@angular/core": "^20.3.15",
@@ -14,15 +14,16 @@
14
14
  "tslib": ">=2.2.0"
15
15
  },
16
16
  "module": "fesm2022/croco-html.mjs",
17
- "typings": "index.d.ts",
17
+ "typings": "types/croco-html.d.ts",
18
18
  "exports": {
19
19
  "./package.json": {
20
20
  "default": "./package.json"
21
21
  },
22
22
  ".": {
23
- "types": "./index.d.ts",
23
+ "types": "./types/croco-html.d.ts",
24
24
  "default": "./fesm2022/croco-html.mjs"
25
25
  }
26
26
  },
27
- "sideEffects": false
27
+ "sideEffects": false,
28
+ "type": "module"
28
29
  }
@@ -143,6 +143,94 @@ declare class TagEditorService {
143
143
  readonly presentOrEdit$: BehaviorSubject<boolean>;
144
144
  }
145
145
 
146
+ /**
147
+ * Types of changes that can occur to a body tag.
148
+ */
149
+ declare enum ChangeType {
150
+ /** One or more fields within the tag were modified */
151
+ Updated = "updated",
152
+ /** Tag was added to the array */
153
+ Added = "added",
154
+ /** Tag was removed from the array */
155
+ Removed = "removed",
156
+ /** Tag was moved (reordered) within the array */
157
+ Moved = "moved",
158
+ /** Multiple changes batched together */
159
+ Batch = "batch"
160
+ }
161
+ /**
162
+ * Describes a change at the field level within an HtmlBodyTag.
163
+ */
164
+ interface TagFieldChange {
165
+ fieldName: string;
166
+ oldValue: unknown;
167
+ newValue: unknown;
168
+ }
169
+ /**
170
+ * Granular diff between two HtmlBodyTag instances.
171
+ */
172
+ interface TagDiff {
173
+ /** The trackingId of the changed tag */
174
+ trackingId: string;
175
+ /** Index where the tag was located */
176
+ index: number;
177
+ /** What kind of operation occurred */
178
+ changeType: ChangeType;
179
+ /** Which fields changed and their values */
180
+ fieldChanges: TagFieldChange[];
181
+ /** Full old tag (before change) */
182
+ oldTag?: HtmlBodyTag;
183
+ /** Full new tag (after change) */
184
+ newTag?: HtmlBodyTag;
185
+ /** Full HTML snapshot after the change */
186
+ htmlSnapshot?: string;
187
+ /** Timestamp of the change */
188
+ timestamp: number;
189
+ }
190
+ /**
191
+ * Snapshot of the complete bodyTags array at a point in time.
192
+ * Used for undo/redo and diff computation.
193
+ */
194
+ interface ChangeSnapshot {
195
+ /** Sequential snapshot ID */
196
+ id: string;
197
+ /** The bodyTags array at this point */
198
+ bodyTags: HtmlBodyTag[];
199
+ /** The HTML string at this point */
200
+ html: string;
201
+ /** When this snapshot was taken (ms since epoch) */
202
+ timestamp: number;
203
+ /** Optional user/operation label */
204
+ label?: string;
205
+ }
206
+ /**
207
+ * A batched set of changes to be applied together.
208
+ */
209
+ interface ChangeBatch {
210
+ changes: TagDiff[];
211
+ batchId: string;
212
+ timestamp: number;
213
+ }
214
+ /**
215
+ * Options for the optimized change tracker.
216
+ */
217
+ interface ChangeTrackerOptions {
218
+ /** Maximum number of snapshots to keep in history */
219
+ maxHistorySize?: number;
220
+ /** Emit changes as they happen (true) or batch them (false) */
221
+ emitImmediately?: boolean;
222
+ /** Batching window in ms when emitImmediately is false */
223
+ batchWindowMs?: number;
224
+ }
225
+ /**
226
+ * Default snapshot limit to prevent unbounded memory growth.
227
+ */
228
+ declare const DEFAULT_MAX_HISTORY_SIZE = 100;
229
+ /**
230
+ * Default batching window in milliseconds.
231
+ */
232
+ declare const DEFAULT_BATCH_WINDOW_MS = 250;
233
+
146
234
  interface IVisualEditorProps {
147
235
  selectedVideoPlayer: string;
148
236
  htmlRaw: string;
@@ -912,10 +1000,127 @@ interface IVisualEditorLogger {
912
1000
  onChange(tag: HtmlBodyTag, index: number): void;
913
1001
  onRemove(index: number): void;
914
1002
  onHtmlChanged(html: string): void;
1003
+ /**
1004
+ * Logs a structured diff of what changed within a tag.
1005
+ * Provides granular insight into field-level modifications.
1006
+ */
1007
+ onTagDiff?(diff: TagDiff): void;
1008
+ /**
1009
+ * Logs a batch of changes applied together.
1010
+ */
1011
+ onBatchChanged?(batch: ChangeBatch): void;
1012
+ /**
1013
+ * Logs a full snapshot state.
1014
+ */
1015
+ onSnapshot?(snapshot: ChangeSnapshot): void;
1016
+ /**
1017
+ * Logs an undo operation.
1018
+ */
1019
+ onUndo?(step: ChangeSnapshot): void;
1020
+ /**
1021
+ * Logs a redo operation.
1022
+ */
1023
+ onRedo?(step: ChangeSnapshot): void;
1024
+ }
1025
+
1026
+ /**
1027
+ * Service responsible for detecting granular differences between two HtmlBodyTag instances.
1028
+ * Avoids unnecessary full re-renders by identifying exactly what changed.
1029
+ */
1030
+ declare class TagChangeDetector {
1031
+ /**
1032
+ * Compares two HtmlBodyTag instances and produces a structured diff.
1033
+ */
1034
+ detectDiff(oldTag: HtmlBodyTag, newTag: HtmlBodyTag, index: number, changeType: ChangeType): TagDiff | null;
1035
+ /**
1036
+ * Deep compares two attribute objects and returns field-level changes.
1037
+ */
1038
+ private diffAttributes;
1039
+ /**
1040
+ * Quick check: do two tags have the same content (ignoring trackingId)?
1041
+ * Useful for skip optimization when nothing actually changed.
1042
+ */
1043
+ tagsAreEqual(a: HtmlBodyTag, b: HtmlBodyTag): boolean;
1044
+ static ɵfac: i0.ɵɵFactoryDeclaration<TagChangeDetector, never>;
1045
+ static ɵprov: i0.ɵɵInjectableDeclaration<TagChangeDetector>;
1046
+ }
1047
+
1048
+ /**
1049
+ * Stack-based undo/redo service for the visual editor.
1050
+ * Maintains two stacks (undo/redo) and supports keyboard shortcuts (Ctrl+Z / Ctrl+Y).
1051
+ */
1052
+ declare class EditorUndoRedoService {
1053
+ private undoStack;
1054
+ private redoStack;
1055
+ /** RxJS observable for canUndo state */
1056
+ readonly canUndoChanged: BehaviorSubject<boolean>;
1057
+ /** RxJS observable for canRedo state */
1058
+ readonly canRedoChanged: BehaviorSubject<boolean>;
1059
+ /** Maximum number of undo steps to keep */
1060
+ private maxHistorySize;
1061
+ /**
1062
+ * Configure the undo/redo service.
1063
+ */
1064
+ configure(options: {
1065
+ maxHistorySize?: number;
1066
+ }): void;
1067
+ /**
1068
+ * Record the current state of the editor.
1069
+ * Call this BEFORE applying changes, so we have a point to undo TO.
1070
+ */
1071
+ pushState(bodyTags: HtmlBodyTag[], html: string, label?: string): void;
1072
+ /**
1073
+ * Undo the last action.
1074
+ * Returns the snapshot to restore, or null if nothing to undo.
1075
+ */
1076
+ undo(): ChangeSnapshot | null;
1077
+ /**
1078
+ * Redo the last undone action.
1079
+ * Returns the snapshot to restore, or null if nothing to redo.
1080
+ */
1081
+ redo(): ChangeSnapshot | null;
1082
+ /**
1083
+ * Clear both undo/redo stacks.
1084
+ * Call this on initial load or fresh state.
1085
+ */
1086
+ clear(): void;
1087
+ /**
1088
+ * Get the bodyTags array from a specific snapshot.
1089
+ */
1090
+ getSnapshotBodyTags(snapshotId: string): HtmlBodyTag[] | null;
1091
+ /**
1092
+ * Get the current undo stack for debugging.
1093
+ */
1094
+ getUndoStack(): ChangeSnapshot[];
1095
+ /**
1096
+ * Get the current redo stack for debugging.
1097
+ */
1098
+ getRedoStack(): ChangeSnapshot[];
1099
+ /**
1100
+ * Check if undo is available.
1101
+ */
1102
+ canUndo(): boolean;
1103
+ /**
1104
+ * Check if redo is available.
1105
+ */
1106
+ canRedo(): boolean;
1107
+ /**
1108
+ * Get the count of available undo steps.
1109
+ */
1110
+ undoCount(): number;
1111
+ /**
1112
+ * Get the count of available redo steps.
1113
+ */
1114
+ redoCount(): number;
1115
+ private updateStates;
1116
+ static ɵfac: i0.ɵɵFactoryDeclaration<EditorUndoRedoService, never>;
1117
+ static ɵprov: i0.ɵɵInjectableDeclaration<EditorUndoRedoService>;
915
1118
  }
916
1119
 
917
1120
  declare class VisualEditorComponent implements OnInit, AfterViewInit {
918
1121
  private readonly _cdr;
1122
+ private readonly _changeDetector;
1123
+ private readonly _undoRedo;
919
1124
  private readonly _options;
920
1125
  textArea: ElementRef;
921
1126
  imageUploadBtn: UploadFilesBtnComponent;
@@ -955,16 +1160,67 @@ declare class VisualEditorComponent implements OnInit, AfterViewInit {
955
1160
  bodyTags: HtmlBodyTag[];
956
1161
  saveBodyTags: HtmlBodyTag[];
957
1162
  useCustomWidgetsButton: boolean;
958
- constructor(_cdr: ChangeDetectorRef, _options: CrocoHtmlOptions);
1163
+ /** History of change snapshots for diff tracking */
1164
+ private historySnapshots;
1165
+ private maxHistorySize;
1166
+ /** Cached last-known bodyTags for diff comparison */
1167
+ private lastKnownTags;
1168
+ /** Destroyed state */
1169
+ private destroyed;
1170
+ constructor(_cdr: ChangeDetectorRef, _changeDetector: TagChangeDetector, _undoRedo: EditorUndoRedoService, _options: CrocoHtmlOptions);
959
1171
  ngAfterViewInit(): void;
1172
+ ngOnDestroy(): void;
1173
+ /**
1174
+ * Handle keyboard shortcuts for undo/redo:
1175
+ * - Ctrl+Z / Cmd+Z: Undo
1176
+ * - Ctrl+Y / Cmd+Y: Redo
1177
+ * - Ctrl+Shift+Z / Cmd+Shift+Z: Redo (alternative)
1178
+ */
1179
+ onKeyDown(event: KeyboardEvent): void;
960
1180
  resetTextStyle(): void;
961
1181
  drop(event: CdkDragDrop<HtmlBodyTag[]>): void;
962
1182
  addTag(tag: HtmlBodyTag): void;
963
1183
  addTags(tags: HtmlBodyTag[]): void;
964
1184
  onTagChangedHandler(data: HtmlBodyTag, index: number): void;
965
1185
  onTagRemovedHandler(index: number): void;
966
- recalculateHtml(): void;
1186
+ /**
1187
+ * Recalculates HTML from bodyTags and emits the result.
1188
+ * @param diff Optional structured diff of what changed (enables downstream consumers to apply incremental updates)
1189
+ */
1190
+ recalculateHtml(diff?: TagDiff | TagDiff[] | null): void;
1191
+ /**
1192
+ * Rebuilds the entire lastKnownTags cache from current bodyTags.
1193
+ * Used for moves or when diff tracking is unreliable.
1194
+ */
1195
+ private rebuildLastKnownTags;
967
1196
  recalculateBodyTags(): void;
1197
+ /**
1198
+ * Undo the last editor action (Ctrl+Z).
1199
+ * Restores bodyTags and html from the previous state.
1200
+ */
1201
+ undo(): boolean;
1202
+ /**
1203
+ * Redo the last undone action (Ctrl+Y or Ctrl+Shift+Z).
1204
+ * Restores bodyTags and html from the next state.
1205
+ */
1206
+ redo(): boolean;
1207
+ /**
1208
+ * Check if undo is currently available.
1209
+ */
1210
+ isUndoAvailable(): boolean;
1211
+ /**
1212
+ * Check if redo is currently available.
1213
+ */
1214
+ isRedoAvailable(): boolean;
1215
+ /**
1216
+ * Returns the current change history snapshot for debugging.
1217
+ */
1218
+ getChangeHistory(): ChangeSnapshot[];
1219
+ /**
1220
+ * trackBy function for ngFor to use trackingId instead of object reference.
1221
+ * Prevents DOM re-rendering when tags haven't actually moved.
1222
+ */
1223
+ trackByTrackingId(index: number, tag: HtmlBodyTag): string;
968
1224
  selectTag(data: TagItem): void;
969
1225
  isTagRequiringForm(): boolean;
970
1226
  addTagWithForm(): void;
@@ -1025,6 +1281,12 @@ declare class ConsoleVisualEditorLogger implements IVisualEditorLogger {
1025
1281
  onChange(tag: HtmlBodyTag, index: number): void;
1026
1282
  onRemove(index: number): void;
1027
1283
  onHtmlChanged(html: string): void;
1284
+ onTagDiff?(diff: TagDiff): void;
1285
+ onBatchChanged?(batch: ChangeBatch): void;
1286
+ onSnapshot?(snapshot: ChangeSnapshot): void;
1287
+ onUndo?(step: ChangeSnapshot): void;
1288
+ onRedo?(step: ChangeSnapshot): void;
1289
+ private getColorForChangeType;
1028
1290
  }
1029
1291
 
1030
1292
  declare class MainEditorComponent implements OnInit, AfterContentChecked, AfterViewInit {
@@ -1060,10 +1322,13 @@ declare class MainEditorBlockComponent implements OnDestroy {
1060
1322
  private readonly _options;
1061
1323
  textTags: string[];
1062
1324
  private unsubscribe;
1325
+ private _tagSub$;
1063
1326
  private readonly _cdr;
1327
+ private readonly _changeDetector;
1064
1328
  set tag(data: HtmlBodyTag);
1065
1329
  _tag: HtmlBodyTag | null;
1066
1330
  _tagService: TagEditorService;
1331
+ private _originalTagBeforeSet;
1067
1332
  presentOrEdit: boolean;
1068
1333
  onTagSaved: EventEmitter<HtmlBodyTag>;
1069
1334
  onTagRemoved: EventEmitter<HtmlBodyTag>;
@@ -1080,7 +1345,8 @@ declare class MainEditorBlockComponent implements OnDestroy {
1080
1345
  declare class DefinedCustomEditorBlockComponent implements OnInit, OnDestroy {
1081
1346
  private readonly _options;
1082
1347
  private readonly _cdr;
1083
- private readonly _destroyRef;
1348
+ private readonly _destroy$;
1349
+ private _tagServiceSub$;
1084
1350
  viewContainerRef: ViewContainerRef;
1085
1351
  useDynamicComponent: boolean;
1086
1352
  dynamicContainerRef: ComponentRef<any>;
@@ -1446,5 +1712,5 @@ declare class CrocoHtmlModule {
1446
1712
 
1447
1713
  declare const CrocoHtmlOptionsToken = "croco-html-options";
1448
1714
 
1449
- export { AddFilesBtnComponent, AngularMaterialTableMethods, AudioEditorComponent, AudioMethods, AudioPlayerTagViewComponent, BodyTagsExtensions, BootstrapTableMethods, ButtonTagDataConsts, ButtonTagService, ConsoleVisualEditorLogger, CrocoHtmlFileOptionsService, CrocoHtmlModule, CrocoHtmlOptionsToken, CustomWidgetEditorComponent, CustomWidgetIconComponent, CustomWidgetTagDataConsts, CustomWidgetTagService, DefinedCustomEditorBlockComponent, DefinedCustomTagViewComponent, DownloadButtonTagDataConsts, DownloadButtonTagService, ExternalVideoEditorComponent, ExternalVideoPlayers, ExternalVideoSupportedTypes, ExternalVideoTagDataConsts, ExternalVideoTagService, FileAudioTagDataConsts, FileIdSelectComponent, FileImageTagDataConsts, FileImageTagService, FileImageTagViewComponent, FileType, HtmlPageDataController, HtmlRawEditorComponent, HtmlRawTagDataConsts, HtmlRawTagService, HtmlRawViewComponent, HtmlViewComponent, HtmlViewController, ImageEditorComponent, ImageMethods, LinkEditorComponent, LinkTagAttrs, LinkTagConsts, LinkTagService, MainEditorBlockComponent, MainEditorComponent, NullVisualEditorLogger, TableBuilder, TableMethods, TableTypes, TagBuildExtensions, TagEditorService, TagToSpanPipe, TextAlignment, TextEditorComponent, TextSimpleMethods, TextTag, TextTagDataConsts, TextTagHtmlMarkupTagService, TextTags, ToHtmlBodyTagsPipe, ToPreviewHtmlPipe, ToPreviewPipe, UploadFilesBtnComponent, VisualEditorComponent, XmlExtensions, XmlTagCustomWidgetComponent, XmlTagExternalVideoComponent, XmlTagHeaderInnerTextViewComponent, XmlTagHeaderTextViewComponent, XmlTagHtmlViewComponent, XmlTagTextViewComponent, XmlTagViewComponent };
1450
- export type { AngularMaterialTableData, BaseApiResponse, ButtonTag, ButtonTagData, CommonFileInfoResultModel, CrocoHtmlEditorFileOptions, CrocoHtmlImageOptions, CrocoHtmlOptions, CustomWidgetTag, CustomWidgetTagData, DownloadButtonTag, DownloadButtonTagData, ExternalVideoTag, ExternalVideoTagData, FileAudioTag, FileAudioTagData, FileImageTag, FileImageTagData, FileInfoModel, FilePostingStarted, FileRelationModel, FileSimpleModel, FileUnifiedModel, GenericTextTag, GetListResult, GetListSearchModel, HtmlBodyTag, HtmlRawTag, HtmlRawTagData, IHorizontalAlignmentExtractionResult, IImageMediaRequest, IMarkUpTagService, ITagEditorViewRender, ITagViewViewRender, IVisualEditorLogger, IVisualEditorProps, ImageRestrictions, InterfaceBlock, LinkTagData, SearchFilesRequest, SearchQuestionsFormData, SimpleTextTagData, TableData, TableHeaderData, TableRowColumnData, TableRowData, TableTagData, TagItem };
1715
+ export { AddFilesBtnComponent, AngularMaterialTableMethods, AudioEditorComponent, AudioMethods, AudioPlayerTagViewComponent, BodyTagsExtensions, BootstrapTableMethods, ButtonTagDataConsts, ButtonTagService, ChangeType, ConsoleVisualEditorLogger, CrocoHtmlFileOptionsService, CrocoHtmlModule, CrocoHtmlOptionsToken, CustomWidgetEditorComponent, CustomWidgetIconComponent, CustomWidgetTagDataConsts, CustomWidgetTagService, DEFAULT_BATCH_WINDOW_MS, DEFAULT_MAX_HISTORY_SIZE, DefinedCustomEditorBlockComponent, DefinedCustomTagViewComponent, DownloadButtonTagDataConsts, DownloadButtonTagService, EditorUndoRedoService, ExternalVideoEditorComponent, ExternalVideoPlayers, ExternalVideoSupportedTypes, ExternalVideoTagDataConsts, ExternalVideoTagService, FileAudioTagDataConsts, FileIdSelectComponent, FileImageTagDataConsts, FileImageTagService, FileImageTagViewComponent, FileType, HtmlPageDataController, HtmlRawEditorComponent, HtmlRawTagDataConsts, HtmlRawTagService, HtmlRawViewComponent, HtmlViewComponent, HtmlViewController, ImageEditorComponent, ImageMethods, LinkEditorComponent, LinkTagAttrs, LinkTagConsts, LinkTagService, MainEditorBlockComponent, MainEditorComponent, NullVisualEditorLogger, TableBuilder, TableMethods, TableTypes, TagBuildExtensions, TagChangeDetector, TagEditorService, TagToSpanPipe, TextAlignment, TextEditorComponent, TextSimpleMethods, TextTag, TextTagDataConsts, TextTagHtmlMarkupTagService, TextTags, ToHtmlBodyTagsPipe, ToPreviewHtmlPipe, ToPreviewPipe, UploadFilesBtnComponent, VisualEditorComponent, XmlExtensions, XmlTagCustomWidgetComponent, XmlTagExternalVideoComponent, XmlTagHeaderInnerTextViewComponent, XmlTagHeaderTextViewComponent, XmlTagHtmlViewComponent, XmlTagTextViewComponent, XmlTagViewComponent };
1716
+ export type { AngularMaterialTableData, BaseApiResponse, ButtonTag, ButtonTagData, ChangeBatch, ChangeSnapshot, ChangeTrackerOptions, CommonFileInfoResultModel, CrocoHtmlEditorFileOptions, CrocoHtmlImageOptions, CrocoHtmlOptions, CustomWidgetTag, CustomWidgetTagData, DownloadButtonTag, DownloadButtonTagData, ExternalVideoTag, ExternalVideoTagData, FileAudioTag, FileAudioTagData, FileImageTag, FileImageTagData, FileInfoModel, FilePostingStarted, FileRelationModel, FileSimpleModel, FileUnifiedModel, GenericTextTag, GetListResult, GetListSearchModel, HtmlBodyTag, HtmlRawTag, HtmlRawTagData, IHorizontalAlignmentExtractionResult, IImageMediaRequest, IMarkUpTagService, ITagEditorViewRender, ITagViewViewRender, IVisualEditorLogger, IVisualEditorProps, ImageRestrictions, InterfaceBlock, LinkTagData, SearchFilesRequest, SearchQuestionsFormData, SimpleTextTagData, TableData, TableHeaderData, TableRowColumnData, TableRowData, TableTagData, TagDiff, TagFieldChange, TagItem };