ngx-form-draft 2.0.2 → 2.0.4

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.
@@ -1,409 +0,0 @@
1
- import * as i0 from '@angular/core';
2
- import { EventEmitter, Component, ChangeDetectionStrategy, Input, Output, Injectable, Directive, Optional, NgModule } from '@angular/core';
3
- import * as i1$1 from '@angular/forms';
4
- import { FormGroup, FormArray, FormControl } from '@angular/forms';
5
- import { Subject } from 'rxjs';
6
- import { debounceTime, takeUntil } from 'rxjs/operators';
7
- import { trigger, transition, style, animate } from '@angular/animations';
8
- import * as i1 from '@angular/common';
9
- import { CommonModule } from '@angular/common';
10
-
11
- class FormDraftBannerComponent {
12
- constructor() {
13
- this.visible = false;
14
- this.timeLabel = '';
15
- this.isRestored = false;
16
- this.restoredText = 'Draft restored';
17
- this.savedText = 'Draft saved';
18
- this.savedLabel = 'saved';
19
- this.discardText = 'Discard';
20
- this.discard = new EventEmitter();
21
- }
22
- }
23
- FormDraftBannerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FormDraftBannerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
24
- FormDraftBannerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: FormDraftBannerComponent, selector: "ngx-form-draft-banner", inputs: { visible: "visible", timeLabel: "timeLabel", isRestored: "isRestored", restoredText: "restoredText", savedText: "savedText", savedLabel: "savedLabel", discardText: "discardText" }, outputs: { discard: "discard" }, ngImport: i0, template: `
25
- <div class="form-draft-banner" *ngIf="visible" [@slideDown]>
26
- <div class="form-draft-banner__icon">
27
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
28
- <path d="M12 8V12L14.5 14.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
29
- <circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/>
30
- </svg>
31
- </div>
32
- <div class="form-draft-banner__content">
33
- <span class="form-draft-banner__text">
34
- <span *ngIf="isRestored">{{ restoredText }}</span>
35
- <span *ngIf="!isRestored">{{ savedText }}</span>
36
- <span class="form-draft-banner__time" *ngIf="timeLabel && isRestored">
37
- &middot; {{ savedLabel }} {{ timeLabel }}
38
- </span>
39
- </span>
40
- </div>
41
- <div class="form-draft-banner__actions">
42
- <button class="form-draft-banner__btn form-draft-banner__btn--discard" (click)="discard.emit()" type="button">
43
- ✕ {{ discardText }}
44
- </button>
45
- </div>
46
- </div>
47
- `, isInline: true, styles: [":host{display:block;width:100%}.form-draft-banner{display:flex;align-items:center;gap:10px;padding:10px 14px;margin-bottom:12px;border-radius:8px;background:linear-gradient(135deg,#eef6ff 0%,#f0f4ff 100%);border:1px solid #c5ddf8;box-shadow:0 2px 8px #128ad614}.form-draft-banner__icon{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:6px;background:linear-gradient(135deg,#128ad6,#22b9ff);color:#fff;flex-shrink:0}.form-draft-banner__content{flex:1;min-width:0}.form-draft-banner__text{font-size:13px;font-weight:600;color:#1a3a5c}.form-draft-banner__time{font-weight:400;color:#6b8aaa;font-size:12px}.form-draft-banner__actions{flex-shrink:0}.form-draft-banner__btn{border:none;padding:5px 12px;border-radius:6px;font-size:12px;font-weight:600;cursor:pointer;transition:all .2s ease}.form-draft-banner__btn--discard{background:transparent;color:#8899a6;border:1px solid #d0dce6}.form-draft-banner__btn--discard:hover{background:#fef2f2;color:#e62e43;border-color:#e62e43}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], animations: [
48
- trigger('slideDown', [
49
- transition(':enter', [
50
- style({ opacity: 0, transform: 'translateY(-8px)' }),
51
- animate('250ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 1, transform: 'translateY(0)' }))
52
- ]),
53
- transition(':leave', [
54
- animate('200ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 0, transform: 'translateY(-8px)' }))
55
- ])
56
- ])
57
- ], changeDetection: i0.ChangeDetectionStrategy.OnPush });
58
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FormDraftBannerComponent, decorators: [{
59
- type: Component,
60
- args: [{ selector: 'ngx-form-draft-banner', template: `
61
- <div class="form-draft-banner" *ngIf="visible" [@slideDown]>
62
- <div class="form-draft-banner__icon">
63
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
64
- <path d="M12 8V12L14.5 14.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
65
- <circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/>
66
- </svg>
67
- </div>
68
- <div class="form-draft-banner__content">
69
- <span class="form-draft-banner__text">
70
- <span *ngIf="isRestored">{{ restoredText }}</span>
71
- <span *ngIf="!isRestored">{{ savedText }}</span>
72
- <span class="form-draft-banner__time" *ngIf="timeLabel && isRestored">
73
- &middot; {{ savedLabel }} {{ timeLabel }}
74
- </span>
75
- </span>
76
- </div>
77
- <div class="form-draft-banner__actions">
78
- <button class="form-draft-banner__btn form-draft-banner__btn--discard" (click)="discard.emit()" type="button">
79
- ✕ {{ discardText }}
80
- </button>
81
- </div>
82
- </div>
83
- `, animations: [
84
- trigger('slideDown', [
85
- transition(':enter', [
86
- style({ opacity: 0, transform: 'translateY(-8px)' }),
87
- animate('250ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 1, transform: 'translateY(0)' }))
88
- ]),
89
- transition(':leave', [
90
- animate('200ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 0, transform: 'translateY(-8px)' }))
91
- ])
92
- ])
93
- ], changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;width:100%}.form-draft-banner{display:flex;align-items:center;gap:10px;padding:10px 14px;margin-bottom:12px;border-radius:8px;background:linear-gradient(135deg,#eef6ff 0%,#f0f4ff 100%);border:1px solid #c5ddf8;box-shadow:0 2px 8px #128ad614}.form-draft-banner__icon{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:6px;background:linear-gradient(135deg,#128ad6,#22b9ff);color:#fff;flex-shrink:0}.form-draft-banner__content{flex:1;min-width:0}.form-draft-banner__text{font-size:13px;font-weight:600;color:#1a3a5c}.form-draft-banner__time{font-weight:400;color:#6b8aaa;font-size:12px}.form-draft-banner__actions{flex-shrink:0}.form-draft-banner__btn{border:none;padding:5px 12px;border-radius:6px;font-size:12px;font-weight:600;cursor:pointer;transition:all .2s ease}.form-draft-banner__btn--discard{background:transparent;color:#8899a6;border:1px solid #d0dce6}.form-draft-banner__btn--discard:hover{background:#fef2f2;color:#e62e43;border-color:#e62e43}\n"] }]
94
- }], propDecorators: { visible: [{
95
- type: Input
96
- }], timeLabel: [{
97
- type: Input
98
- }], isRestored: [{
99
- type: Input
100
- }], restoredText: [{
101
- type: Input
102
- }], savedText: [{
103
- type: Input
104
- }], savedLabel: [{
105
- type: Input
106
- }], discardText: [{
107
- type: Input
108
- }], discard: [{
109
- type: Output
110
- }] } });
111
-
112
- class FormDraftService {
113
- constructor() {
114
- this.STORAGE_PREFIX = 'form_draft_';
115
- this.MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
116
- }
117
- buildKey(formId) {
118
- return `${this.STORAGE_PREFIX}${formId}`;
119
- }
120
- save(formId, values) {
121
- try {
122
- const draft = { values, savedAt: Date.now(), formId };
123
- localStorage.setItem(this.buildKey(formId), JSON.stringify(draft));
124
- }
125
- catch (e) {
126
- console.warn('[FormDraft] Could not save draft:', e);
127
- }
128
- }
129
- load(formId) {
130
- try {
131
- const raw = localStorage.getItem(this.buildKey(formId));
132
- if (!raw)
133
- return null;
134
- const draft = JSON.parse(raw);
135
- if (Date.now() - draft.savedAt > this.MAX_AGE_MS) {
136
- this.clear(formId);
137
- return null;
138
- }
139
- return draft;
140
- }
141
- catch (e) {
142
- console.warn('[FormDraft] Could not load draft:', e);
143
- return null;
144
- }
145
- }
146
- clear(formId) {
147
- try {
148
- localStorage.removeItem(this.buildKey(formId));
149
- }
150
- catch (e) {
151
- console.warn('[FormDraft] Could not clear draft:', e);
152
- }
153
- }
154
- formatTimestamp(timestamp) {
155
- const seconds = Math.floor((Date.now() - timestamp) / 1000);
156
- if (seconds < 60)
157
- return 'just now';
158
- const minutes = Math.floor(seconds / 60);
159
- if (minutes < 60)
160
- return `${minutes}m ago`;
161
- const hours = Math.floor(minutes / 60);
162
- if (hours < 24)
163
- return `${hours}h ago`;
164
- const days = Math.floor(hours / 24);
165
- return `${days}d ago`;
166
- }
167
- }
168
- FormDraftService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FormDraftService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
169
- FormDraftService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FormDraftService, providedIn: 'root' });
170
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FormDraftService, decorators: [{
171
- type: Injectable,
172
- args: [{
173
- providedIn: 'root'
174
- }]
175
- }] });
176
-
177
- /**
178
- * Auto-saves and restores form drafts
179
- *
180
- * @example
181
- * <form [formGroup]="myForm" ngxFormDraft="myFormId">
182
- *
183
- * @example
184
- * <form [formGroup]="myForm" [ngxFormDraft]="'edit_' + entityId" [draftExcludeFields]="['password']">
185
- */
186
- class FormDraftDirective {
187
- constructor(formGroupDir, ngForm, draftService, viewContainerRef, cdRef, elRef, renderer) {
188
- this.formGroupDir = formGroupDir;
189
- this.ngForm = ngForm;
190
- this.draftService = draftService;
191
- this.viewContainerRef = viewContainerRef;
192
- this.cdRef = cdRef;
193
- this.elRef = elRef;
194
- this.renderer = renderer;
195
- this.draftDebounce = 800;
196
- this.draftExcludeFields = [];
197
- this.draftShowOnChange = false;
198
- this.draftRestoredText = 'Draft restored';
199
- this.draftSavedText = 'Draft saved';
200
- this.draftSavedLabel = 'saved';
201
- this.draftDiscardText = 'Discard';
202
- this.destroy$ = new Subject();
203
- this.bannerRef = null;
204
- this.formControl = null;
205
- this.initialValues = {};
206
- this.isRestoring = false;
207
- }
208
- ngOnInit() {
209
- this.formControl = this.formGroupDir?.form || this.ngForm?.form || null;
210
- if (!this.formControl || !this.formId)
211
- return;
212
- this.initialValues = JSON.parse(JSON.stringify(this.formControl.value));
213
- const draft = this.draftService.load(this.formId);
214
- if (draft) {
215
- this.restoreDraft(draft.values);
216
- this.showBanner(draft.savedAt, true);
217
- }
218
- this.formControl.valueChanges
219
- .pipe(debounceTime(this.draftDebounce), takeUntil(this.destroy$))
220
- .subscribe((values) => {
221
- if (this.isRestoring)
222
- return;
223
- this.saveDraft(values);
224
- });
225
- }
226
- ngOnDestroy() {
227
- this.destroy$.next();
228
- this.destroy$.complete();
229
- this.destroyBanner();
230
- }
231
- saveDraft(values) {
232
- const filtered = this.filterFields(values);
233
- if (this.isAllEmpty(filtered) || this.matchesInitialValues(filtered)) {
234
- return;
235
- }
236
- this.draftService.save(this.formId, filtered);
237
- if (this.draftShowOnChange && !this.bannerRef) {
238
- this.showBanner(Date.now(), false);
239
- }
240
- }
241
- filterFields(values) {
242
- if (!this.draftExcludeFields.length)
243
- return values;
244
- const result = { ...values };
245
- this.draftExcludeFields.forEach(field => delete result[field]);
246
- return result;
247
- }
248
- isAllEmpty(values) {
249
- return Object.values(values).every(v => v === null || v === undefined || v === '' || (Array.isArray(v) && v.length === 0));
250
- }
251
- matchesInitialValues(values) {
252
- return JSON.stringify(values) === JSON.stringify(this.initialValues);
253
- }
254
- restoreDraft(values) {
255
- if (!this.formControl)
256
- return;
257
- this.isRestoring = true;
258
- const form = this.formGroupDir?.form || this.ngForm?.form;
259
- if (form) {
260
- this.prepareFormArrays(form, values);
261
- form.patchValue(values);
262
- }
263
- setTimeout(() => this.isRestoring = false, 100);
264
- }
265
- prepareFormArrays(control, value) {
266
- if (!control || value == null)
267
- return;
268
- if (control instanceof FormGroup && value && typeof value === 'object' && !Array.isArray(value)) {
269
- Object.keys(value).forEach(key => {
270
- const childControl = control.get(key);
271
- if (childControl)
272
- this.prepareFormArrays(childControl, value[key]);
273
- });
274
- return;
275
- }
276
- if (control instanceof FormArray && Array.isArray(value)) {
277
- const formArray = control;
278
- while (formArray.length < value.length) {
279
- const template = formArray.at(0);
280
- if (template instanceof FormGroup) {
281
- const newGroup = new FormGroup({});
282
- Object.keys(template.controls).forEach(ctrlName => {
283
- const existing = template.get(ctrlName);
284
- if (existing instanceof FormArray) {
285
- newGroup.addControl(ctrlName, new FormArray([]));
286
- }
287
- else if (existing instanceof FormGroup) {
288
- newGroup.addControl(ctrlName, new FormGroup({}));
289
- }
290
- else {
291
- newGroup.addControl(ctrlName, new FormControl(null));
292
- }
293
- });
294
- formArray.push(newGroup);
295
- }
296
- else if (template) {
297
- formArray.push(new FormControl(null));
298
- }
299
- else {
300
- const firstValue = value[0];
301
- if (firstValue && typeof firstValue === 'object' && !Array.isArray(firstValue)) {
302
- const group = new FormGroup({});
303
- Object.keys(firstValue).forEach(key => group.addControl(key, new FormControl(null)));
304
- formArray.push(group);
305
- }
306
- else {
307
- formArray.push(new FormControl(null));
308
- }
309
- }
310
- }
311
- while (formArray.length > value.length) {
312
- formArray.removeAt(formArray.length - 1);
313
- }
314
- value.forEach((childValue, index) => {
315
- this.prepareFormArrays(formArray.at(index), childValue);
316
- });
317
- }
318
- }
319
- discardDraft() {
320
- this.draftService.clear(this.formId);
321
- if (this.formControl) {
322
- this.isRestoring = true;
323
- const form = this.formGroupDir?.form || this.ngForm?.form;
324
- if (form) {
325
- this.prepareFormArrays(form, this.initialValues);
326
- form.reset(this.initialValues);
327
- }
328
- setTimeout(() => {
329
- this.isRestoring = false;
330
- }, this.draftDebounce + 200);
331
- }
332
- this.destroyBanner();
333
- }
334
- showBanner(savedAt, isRestored = false) {
335
- this.bannerRef = this.viewContainerRef.createComponent(FormDraftBannerComponent);
336
- this.bannerRef.setInput('visible', true);
337
- this.bannerRef.setInput('isRestored', isRestored);
338
- this.bannerRef.setInput('timeLabel', isRestored ? this.draftService.formatTimestamp(savedAt) : '');
339
- this.bannerRef.setInput('restoredText', this.draftRestoredText);
340
- this.bannerRef.setInput('savedText', this.draftSavedText);
341
- this.bannerRef.setInput('savedLabel', this.draftSavedLabel);
342
- this.bannerRef.setInput('discardText', this.draftDiscardText);
343
- this.bannerRef.instance.discard.subscribe(() => this.discardDraft());
344
- const bannerEl = this.bannerRef.location.nativeElement;
345
- const formEl = this.elRef.nativeElement;
346
- this.renderer.insertBefore(formEl, bannerEl, formEl.firstChild);
347
- this.cdRef.detectChanges();
348
- }
349
- destroyBanner() {
350
- if (this.bannerRef) {
351
- this.bannerRef.destroy();
352
- this.bannerRef = null;
353
- }
354
- }
355
- clearDraft() {
356
- this.draftService.clear(this.formId);
357
- this.destroyBanner();
358
- }
359
- }
360
- FormDraftDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FormDraftDirective, deps: [{ token: i1$1.FormGroupDirective, optional: true }, { token: i1$1.NgForm, optional: true }, { token: FormDraftService }, { token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
361
- FormDraftDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.3.0", type: FormDraftDirective, selector: "[ngxFormDraft]", inputs: { formId: ["ngxFormDraft", "formId"], draftDebounce: "draftDebounce", draftExcludeFields: "draftExcludeFields", draftShowOnChange: "draftShowOnChange", draftRestoredText: "draftRestoredText", draftSavedText: "draftSavedText", draftSavedLabel: "draftSavedLabel", draftDiscardText: "draftDiscardText" }, ngImport: i0 });
362
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FormDraftDirective, decorators: [{
363
- type: Directive,
364
- args: [{
365
- selector: '[ngxFormDraft]',
366
- }]
367
- }], ctorParameters: function () { return [{ type: i1$1.FormGroupDirective, decorators: [{
368
- type: Optional
369
- }] }, { type: i1$1.NgForm, decorators: [{
370
- type: Optional
371
- }] }, { type: FormDraftService }, { type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { formId: [{
372
- type: Input,
373
- args: ['ngxFormDraft']
374
- }], draftDebounce: [{
375
- type: Input
376
- }], draftExcludeFields: [{
377
- type: Input
378
- }], draftShowOnChange: [{
379
- type: Input
380
- }], draftRestoredText: [{
381
- type: Input
382
- }], draftSavedText: [{
383
- type: Input
384
- }], draftSavedLabel: [{
385
- type: Input
386
- }], draftDiscardText: [{
387
- type: Input
388
- }] } });
389
-
390
- class NgxFormDraftModule {
391
- }
392
- NgxFormDraftModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgxFormDraftModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
393
- NgxFormDraftModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: NgxFormDraftModule, declarations: [FormDraftDirective, FormDraftBannerComponent], imports: [CommonModule], exports: [FormDraftDirective, FormDraftBannerComponent] });
394
- NgxFormDraftModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgxFormDraftModule, imports: [CommonModule] });
395
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgxFormDraftModule, decorators: [{
396
- type: NgModule,
397
- args: [{
398
- declarations: [FormDraftDirective, FormDraftBannerComponent],
399
- imports: [CommonModule],
400
- exports: [FormDraftDirective, FormDraftBannerComponent],
401
- }]
402
- }] });
403
-
404
- /**
405
- * Generated bundle index. Do not edit.
406
- */
407
-
408
- export { FormDraftBannerComponent, FormDraftDirective, FormDraftService, NgxFormDraftModule };
409
- //# sourceMappingURL=ngx-form-draft.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ngx-form-draft.mjs","sources":["../../src/form-draft-banner.component.ts","../../src/form-draft.service.ts","../../src/form-draft.directive.ts","../../src/ngx-form-draft.module.ts","../../src/ngx-form-draft.ts"],"sourcesContent":["import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';\nimport { trigger, transition, style, animate } from '@angular/animations';\n\n@Component({\n selector: 'ngx-form-draft-banner',\n template: `\n <div class=\"form-draft-banner\" *ngIf=\"visible\" [@slideDown]>\n <div class=\"form-draft-banner__icon\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 8V12L14.5 14.5\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <circle cx=\"12\" cy=\"12\" r=\"9\" stroke=\"currentColor\" stroke-width=\"2\"/>\n </svg>\n </div>\n <div class=\"form-draft-banner__content\">\n <span class=\"form-draft-banner__text\">\n <span *ngIf=\"isRestored\">{{ restoredText }}</span>\n <span *ngIf=\"!isRestored\">{{ savedText }}</span>\n <span class=\"form-draft-banner__time\" *ngIf=\"timeLabel && isRestored\">\n &middot; {{ savedLabel }} {{ timeLabel }}\n </span>\n </span>\n </div>\n <div class=\"form-draft-banner__actions\">\n <button class=\"form-draft-banner__btn form-draft-banner__btn--discard\" (click)=\"discard.emit()\" type=\"button\">\n ✕ {{ discardText }}\n </button>\n </div>\n </div>\n `,\n styles: [`\n :host { display: block; width: 100%; }\n .form-draft-banner {\n display: flex; align-items: center; gap: 10px; padding: 10px 14px; margin-bottom: 12px;\n border-radius: 8px; background: linear-gradient(135deg, #eef6ff 0%, #f0f4ff 100%);\n border: 1px solid #c5ddf8; box-shadow: 0 2px 8px rgba(18, 138, 214, 0.08);\n }\n .form-draft-banner__icon {\n display: flex; align-items: center; justify-content: center; width: 32px; height: 32px;\n border-radius: 6px; background: linear-gradient(135deg, #128ad6, #22b9ff); color: #fff; flex-shrink: 0;\n }\n .form-draft-banner__content { flex: 1; min-width: 0; }\n .form-draft-banner__text { font-size: 13px; font-weight: 600; color: #1a3a5c; }\n .form-draft-banner__time { font-weight: 400; color: #6b8aaa; font-size: 12px; }\n .form-draft-banner__actions { flex-shrink: 0; }\n .form-draft-banner__btn {\n border: none; padding: 5px 12px; border-radius: 6px; font-size: 12px;\n font-weight: 600; cursor: pointer; transition: all 0.2s ease;\n }\n .form-draft-banner__btn--discard { background: transparent; color: #8899a6; border: 1px solid #d0dce6; }\n .form-draft-banner__btn--discard:hover { background: #fef2f2; color: #e62e43; border-color: #e62e43; }\n `],\n animations: [\n trigger('slideDown', [\n transition(':enter', [\n style({ opacity: 0, transform: 'translateY(-8px)' }),\n animate('250ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 1, transform: 'translateY(0)' }))\n ]),\n transition(':leave', [\n animate('200ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 0, transform: 'translateY(-8px)' }))\n ])\n ])\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class FormDraftBannerComponent {\n @Input() visible = false;\n @Input() timeLabel = '';\n @Input() isRestored = false;\n @Input() restoredText = 'Draft restored';\n @Input() savedText = 'Draft saved';\n @Input() savedLabel = 'saved';\n @Input() discardText = 'Discard';\n @Output() discard = new EventEmitter<void>();\n}\n","import { Injectable } from '@angular/core';\n\nexport interface FormDraftData {\n values: Record<string, any>;\n savedAt: number;\n formId: string;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class FormDraftService {\n private readonly STORAGE_PREFIX = 'form_draft_';\n private readonly MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;\n\n private buildKey(formId: string): string {\n return `${this.STORAGE_PREFIX}${formId}`;\n }\n\n save(formId: string, values: Record<string, any>): void {\n try {\n const draft: FormDraftData = { values, savedAt: Date.now(), formId };\n localStorage.setItem(this.buildKey(formId), JSON.stringify(draft));\n } catch (e) {\n console.warn('[FormDraft] Could not save draft:', e);\n }\n }\n\n load(formId: string): FormDraftData | null {\n try {\n const raw = localStorage.getItem(this.buildKey(formId));\n if (!raw) return null;\n\n const draft: FormDraftData = JSON.parse(raw);\n if (Date.now() - draft.savedAt > this.MAX_AGE_MS) {\n this.clear(formId);\n return null;\n }\n return draft;\n } catch (e) {\n console.warn('[FormDraft] Could not load draft:', e);\n return null;\n }\n }\n\n clear(formId: string): void {\n try {\n localStorage.removeItem(this.buildKey(formId));\n } catch (e) {\n console.warn('[FormDraft] Could not clear draft:', e);\n }\n }\n\n formatTimestamp(timestamp: number): string {\n const seconds = Math.floor((Date.now() - timestamp) / 1000);\n if (seconds < 60) return 'just now';\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m ago`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours}h ago`;\n const days = Math.floor(hours / 24);\n return `${days}d ago`;\n }\n}\n","import {\n Directive, Input, OnInit, OnDestroy, Optional, ComponentRef,\n ViewContainerRef, ChangeDetectorRef, ElementRef, Renderer2,\n} from '@angular/core';\nimport { NgForm, FormGroupDirective, AbstractControl, FormArray, FormGroup, FormControl } from '@angular/forms';\nimport { Subject } from 'rxjs';\nimport { debounceTime, takeUntil } from 'rxjs/operators';\nimport { FormDraftService } from './form-draft.service';\nimport { FormDraftBannerComponent } from './form-draft-banner.component';\n\n/**\n * Auto-saves and restores form drafts\n * \n * @example\n * <form [formGroup]=\"myForm\" ngxFormDraft=\"myFormId\">\n * \n * @example\n * <form [formGroup]=\"myForm\" [ngxFormDraft]=\"'edit_' + entityId\" [draftExcludeFields]=\"['password']\">\n */\n@Directive({\n selector: '[ngxFormDraft]',\n})\nexport class FormDraftDirective implements OnInit, OnDestroy {\n @Input('ngxFormDraft') formId!: string;\n @Input() draftDebounce = 800;\n @Input() draftExcludeFields: string[] = [];\n @Input() draftShowOnChange = false;\n @Input() draftRestoredText = 'Draft restored';\n @Input() draftSavedText = 'Draft saved';\n @Input() draftSavedLabel = 'saved';\n @Input() draftDiscardText = 'Discard';\n\n private destroy$ = new Subject<void>();\n private bannerRef: ComponentRef<FormDraftBannerComponent> | null = null;\n private formControl: AbstractControl | null = null;\n private initialValues: Record<string, any> = {};\n private isRestoring = false;\n\n constructor(\n @Optional() private formGroupDir: FormGroupDirective,\n @Optional() private ngForm: NgForm,\n private draftService: FormDraftService,\n private viewContainerRef: ViewContainerRef,\n private cdRef: ChangeDetectorRef,\n private elRef: ElementRef,\n private renderer: Renderer2,\n ) {}\n\n ngOnInit(): void {\n this.formControl = this.formGroupDir?.form || this.ngForm?.form || null;\n if (!this.formControl || !this.formId) return;\n\n this.initialValues = JSON.parse(JSON.stringify(this.formControl.value));\n\n const draft = this.draftService.load(this.formId);\n if (draft) {\n this.restoreDraft(draft.values);\n this.showBanner(draft.savedAt, true);\n }\n\n this.formControl.valueChanges\n .pipe(debounceTime(this.draftDebounce), takeUntil(this.destroy$))\n .subscribe((values) => {\n if (this.isRestoring) return;\n this.saveDraft(values);\n });\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n this.destroyBanner();\n }\n\n private saveDraft(values: Record<string, any>): void {\n const filtered = this.filterFields(values);\n \n if (this.isAllEmpty(filtered) || this.matchesInitialValues(filtered)) {\n return;\n }\n\n this.draftService.save(this.formId, filtered);\n if (this.draftShowOnChange && !this.bannerRef) {\n this.showBanner(Date.now(), false);\n }\n }\n\n private filterFields(values: Record<string, any>): Record<string, any> {\n if (!this.draftExcludeFields.length) return values;\n const result = { ...values };\n this.draftExcludeFields.forEach(field => delete result[field]);\n return result;\n }\n\n private isAllEmpty(values: Record<string, any>): boolean {\n return Object.values(values).every(\n v => v === null || v === undefined || v === '' || (Array.isArray(v) && v.length === 0)\n );\n }\n\n private matchesInitialValues(values: Record<string, any>): boolean {\n return JSON.stringify(values) === JSON.stringify(this.initialValues);\n }\n\n private restoreDraft(values: Record<string, any>): void {\n if (!this.formControl) return;\n this.isRestoring = true;\n\n const form = this.formGroupDir?.form || this.ngForm?.form;\n if (form) {\n this.prepareFormArrays(form, values);\n form.patchValue(values);\n }\n\n setTimeout(() => this.isRestoring = false, 100);\n }\n\n private prepareFormArrays(control: AbstractControl, value: any): void {\n if (!control || value == null) return;\n\n if (control instanceof FormGroup && value && typeof value === 'object' && !Array.isArray(value)) {\n Object.keys(value).forEach(key => {\n const childControl = control.get(key);\n if (childControl) this.prepareFormArrays(childControl, value[key]);\n });\n return;\n }\n\n if (control instanceof FormArray && Array.isArray(value)) {\n const formArray = control as FormArray;\n\n while (formArray.length < value.length) {\n const template = formArray.at(0);\n if (template instanceof FormGroup) {\n const newGroup = new FormGroup({});\n Object.keys(template.controls).forEach(ctrlName => {\n const existing = template.get(ctrlName) as AbstractControl;\n if (existing instanceof FormArray) {\n newGroup.addControl(ctrlName, new FormArray([]));\n } else if (existing instanceof FormGroup) {\n newGroup.addControl(ctrlName, new FormGroup({}));\n } else {\n newGroup.addControl(ctrlName, new FormControl(null));\n }\n });\n formArray.push(newGroup);\n } else if (template) {\n formArray.push(new FormControl(null));\n } else {\n const firstValue = value[0];\n if (firstValue && typeof firstValue === 'object' && !Array.isArray(firstValue)) {\n const group = new FormGroup({});\n Object.keys(firstValue).forEach(key => group.addControl(key, new FormControl(null)));\n formArray.push(group);\n } else {\n formArray.push(new FormControl(null));\n }\n }\n }\n\n while (formArray.length > value.length) {\n formArray.removeAt(formArray.length - 1);\n }\n\n value.forEach((childValue, index) => {\n this.prepareFormArrays(formArray.at(index), childValue);\n });\n }\n }\n\n private discardDraft(): void {\n this.draftService.clear(this.formId);\n\n if (this.formControl) {\n this.isRestoring = true;\n const form = this.formGroupDir?.form || this.ngForm?.form;\n if (form) {\n this.prepareFormArrays(form, this.initialValues);\n form.reset(this.initialValues);\n }\n setTimeout(() => {\n this.isRestoring = false;\n }, this.draftDebounce + 200);\n }\n\n this.destroyBanner();\n }\n\n private showBanner(savedAt: number, isRestored = false): void {\n this.bannerRef = this.viewContainerRef.createComponent(FormDraftBannerComponent);\n this.bannerRef.setInput('visible', true);\n this.bannerRef.setInput('isRestored', isRestored);\n this.bannerRef.setInput('timeLabel', isRestored ? this.draftService.formatTimestamp(savedAt) : '');\n this.bannerRef.setInput('restoredText', this.draftRestoredText);\n this.bannerRef.setInput('savedText', this.draftSavedText);\n this.bannerRef.setInput('savedLabel', this.draftSavedLabel);\n this.bannerRef.setInput('discardText', this.draftDiscardText);\n\n this.bannerRef.instance.discard.subscribe(() => this.discardDraft());\n\n const bannerEl = this.bannerRef.location.nativeElement;\n const formEl = this.elRef.nativeElement;\n this.renderer.insertBefore(formEl, bannerEl, formEl.firstChild);\n\n this.cdRef.detectChanges();\n }\n\n private destroyBanner(): void {\n if (this.bannerRef) {\n this.bannerRef.destroy();\n this.bannerRef = null;\n }\n }\n\n public clearDraft(): void {\n this.draftService.clear(this.formId);\n this.destroyBanner();\n }\n}\n","import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormDraftDirective } from './form-draft.directive';\nimport { FormDraftBannerComponent } from './form-draft-banner.component';\n\n@NgModule({\n declarations: [FormDraftDirective, FormDraftBannerComponent],\n imports: [CommonModule],\n exports: [FormDraftDirective, FormDraftBannerComponent],\n})\nexport class NgxFormDraftModule {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1","i2.FormDraftService"],"mappings":"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"}
@@ -1,14 +0,0 @@
1
- import { EventEmitter } from '@angular/core';
2
- import * as i0 from "@angular/core";
3
- export declare class FormDraftBannerComponent {
4
- visible: boolean;
5
- timeLabel: string;
6
- isRestored: boolean;
7
- restoredText: string;
8
- savedText: string;
9
- savedLabel: string;
10
- discardText: string;
11
- discard: EventEmitter<void>;
12
- static ɵfac: i0.ɵɵFactoryDeclaration<FormDraftBannerComponent, never>;
13
- static ɵcmp: i0.ɵɵComponentDeclaration<FormDraftBannerComponent, "ngx-form-draft-banner", never, { "visible": "visible"; "timeLabel": "timeLabel"; "isRestored": "isRestored"; "restoredText": "restoredText"; "savedText": "savedText"; "savedLabel": "savedLabel"; "discardText": "discardText"; }, { "discard": "discard"; }, never, never, false>;
14
- }
@@ -1,50 +0,0 @@
1
- import { OnInit, OnDestroy, ViewContainerRef, ChangeDetectorRef, ElementRef, Renderer2 } from '@angular/core';
2
- import { NgForm, FormGroupDirective } from '@angular/forms';
3
- import { FormDraftService } from './form-draft.service';
4
- import * as i0 from "@angular/core";
5
- /**
6
- * Auto-saves and restores form drafts
7
- *
8
- * @example
9
- * <form [formGroup]="myForm" ngxFormDraft="myFormId">
10
- *
11
- * @example
12
- * <form [formGroup]="myForm" [ngxFormDraft]="'edit_' + entityId" [draftExcludeFields]="['password']">
13
- */
14
- export declare class FormDraftDirective implements OnInit, OnDestroy {
15
- private formGroupDir;
16
- private ngForm;
17
- private draftService;
18
- private viewContainerRef;
19
- private cdRef;
20
- private elRef;
21
- private renderer;
22
- formId: string;
23
- draftDebounce: number;
24
- draftExcludeFields: string[];
25
- draftShowOnChange: boolean;
26
- draftRestoredText: string;
27
- draftSavedText: string;
28
- draftSavedLabel: string;
29
- draftDiscardText: string;
30
- private destroy$;
31
- private bannerRef;
32
- private formControl;
33
- private initialValues;
34
- private isRestoring;
35
- constructor(formGroupDir: FormGroupDirective, ngForm: NgForm, draftService: FormDraftService, viewContainerRef: ViewContainerRef, cdRef: ChangeDetectorRef, elRef: ElementRef, renderer: Renderer2);
36
- ngOnInit(): void;
37
- ngOnDestroy(): void;
38
- private saveDraft;
39
- private filterFields;
40
- private isAllEmpty;
41
- private matchesInitialValues;
42
- private restoreDraft;
43
- private prepareFormArrays;
44
- private discardDraft;
45
- private showBanner;
46
- private destroyBanner;
47
- clearDraft(): void;
48
- static ɵfac: i0.ɵɵFactoryDeclaration<FormDraftDirective, [{ optional: true; }, { optional: true; }, null, null, null, null, null]>;
49
- static ɵdir: i0.ɵɵDirectiveDeclaration<FormDraftDirective, "[ngxFormDraft]", never, { "formId": "ngxFormDraft"; "draftDebounce": "draftDebounce"; "draftExcludeFields": "draftExcludeFields"; "draftShowOnChange": "draftShowOnChange"; "draftRestoredText": "draftRestoredText"; "draftSavedText": "draftSavedText"; "draftSavedLabel": "draftSavedLabel"; "draftDiscardText": "draftDiscardText"; }, {}, never, never, false>;
50
- }
@@ -1,17 +0,0 @@
1
- import * as i0 from "@angular/core";
2
- export interface FormDraftData {
3
- values: Record<string, any>;
4
- savedAt: number;
5
- formId: string;
6
- }
7
- export declare class FormDraftService {
8
- private readonly STORAGE_PREFIX;
9
- private readonly MAX_AGE_MS;
10
- private buildKey;
11
- save(formId: string, values: Record<string, any>): void;
12
- load(formId: string): FormDraftData | null;
13
- clear(formId: string): void;
14
- formatTimestamp(timestamp: number): string;
15
- static ɵfac: i0.ɵɵFactoryDeclaration<FormDraftService, never>;
16
- static ɵprov: i0.ɵɵInjectableDeclaration<FormDraftService>;
17
- }
package/dist/index.d.ts DELETED
@@ -1,4 +0,0 @@
1
- export * from './form-draft.directive';
2
- export * from './form-draft-banner.component';
3
- export * from './form-draft.service';
4
- export * from './ngx-form-draft.module';
@@ -1,9 +0,0 @@
1
- import * as i0 from "@angular/core";
2
- import * as i1 from "./form-draft.directive";
3
- import * as i2 from "./form-draft-banner.component";
4
- import * as i3 from "@angular/common";
5
- export declare class NgxFormDraftModule {
6
- static ɵfac: i0.ɵɵFactoryDeclaration<NgxFormDraftModule, never>;
7
- static ɵmod: i0.ɵɵNgModuleDeclaration<NgxFormDraftModule, [typeof i1.FormDraftDirective, typeof i2.FormDraftBannerComponent], [typeof i3.CommonModule], [typeof i1.FormDraftDirective, typeof i2.FormDraftBannerComponent]>;
8
- static ɵinj: i0.ɵɵInjectorDeclaration<NgxFormDraftModule>;
9
- }
package/dist/package.json DELETED
@@ -1,64 +0,0 @@
1
- {
2
- "name": "ngx-form-draft",
3
- "version": "2.0.2",
4
- "description": "Auto-save and restore Angular form drafts with zero dependencies",
5
- "author": "Neokyuubi",
6
- "publishConfig": {
7
- "directory": "dist"
8
- },
9
- "repository": {
10
- "type": "git",
11
- "url": "git+https://github.com/neokyuubi/ngx-form-draft.git"
12
- },
13
- "bugs": {
14
- "url": "https://github.com/neokyuubi/ngx-form-draft/issues"
15
- },
16
- "homepage": "https://github.com/neokyuubi/ngx-form-draft#readme",
17
- "peerDependencies": {
18
- "@angular/core": ">=14.0.0",
19
- "@angular/common": ">=14.0.0",
20
- "@angular/forms": ">=14.0.0",
21
- "@angular/animations": ">=14.0.0",
22
- "rxjs": ">=6.0.0"
23
- },
24
- "keywords": [
25
- "angular",
26
- "forms",
27
- "draft",
28
- "autosave",
29
- "reactive-forms",
30
- "template-driven-forms",
31
- "form-array",
32
- "localstorage",
33
- "angular-directive"
34
- ],
35
- "license": "MIT",
36
- "files": [
37
- "dist",
38
- "README.md",
39
- "LICENSE"
40
- ],
41
- "module": "fesm2015/ngx-form-draft.mjs",
42
- "es2020": "fesm2020/ngx-form-draft.mjs",
43
- "esm2020": "esm2020/ngx-form-draft.mjs",
44
- "fesm2020": "fesm2020/ngx-form-draft.mjs",
45
- "fesm2015": "fesm2015/ngx-form-draft.mjs",
46
- "typings": "index.d.ts",
47
- "exports": {
48
- "./package.json": {
49
- "default": "./package.json"
50
- },
51
- ".": {
52
- "types": "./index.d.ts",
53
- "esm2020": "./esm2020/ngx-form-draft.mjs",
54
- "es2020": "./fesm2020/ngx-form-draft.mjs",
55
- "es2015": "./fesm2015/ngx-form-draft.mjs",
56
- "node": "./fesm2015/ngx-form-draft.mjs",
57
- "default": "./fesm2020/ngx-form-draft.mjs"
58
- }
59
- },
60
- "sideEffects": false,
61
- "dependencies": {
62
- "tslib": "^2.0.0"
63
- }
64
- }