ngx-kit 7.2.0 → 7.3.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.
Files changed (71) hide show
  1. package/angle-selector/README.md +34 -34
  2. package/box-shadow/README.md +33 -33
  3. package/color-picker/README.md +52 -52
  4. package/{shared → core}/README.md +117 -117
  5. package/data-table/README.md +120 -120
  6. package/date-picker/README.md +74 -74
  7. package/dialog/README.md +122 -92
  8. package/drag-resize/README.md +53 -55
  9. package/fesm2022/ngx-kit-angle-selector.mjs +9 -26
  10. package/fesm2022/ngx-kit-angle-selector.mjs.map +1 -1
  11. package/fesm2022/ngx-kit-box-shadow.mjs +330 -356
  12. package/fesm2022/ngx-kit-box-shadow.mjs.map +1 -1
  13. package/fesm2022/ngx-kit-color-picker.mjs +132 -272
  14. package/fesm2022/ngx-kit-color-picker.mjs.map +1 -1
  15. package/fesm2022/{ngx-kit-shared.mjs → ngx-kit-core.mjs} +845 -277
  16. package/fesm2022/ngx-kit-core.mjs.map +1 -0
  17. package/fesm2022/ngx-kit-data-table.mjs +1 -1
  18. package/fesm2022/ngx-kit-data-table.mjs.map +1 -1
  19. package/fesm2022/ngx-kit-date-picker.mjs +27 -21
  20. package/fesm2022/ngx-kit-date-picker.mjs.map +1 -1
  21. package/fesm2022/ngx-kit-dialog.mjs +430 -331
  22. package/fesm2022/ngx-kit-dialog.mjs.map +1 -1
  23. package/fesm2022/ngx-kit-drag-resize.mjs +126 -45
  24. package/fesm2022/ngx-kit-drag-resize.mjs.map +1 -1
  25. package/fesm2022/ngx-kit-drawer-menu.mjs +2 -2
  26. package/fesm2022/ngx-kit-drawer-menu.mjs.map +1 -1
  27. package/fesm2022/ngx-kit-dropzone.mjs.map +1 -1
  28. package/fesm2022/ngx-kit-form-field.mjs.map +1 -1
  29. package/fesm2022/ngx-kit-gallery.mjs +3 -3
  30. package/fesm2022/ngx-kit-gallery.mjs.map +1 -1
  31. package/fesm2022/ngx-kit-gradient-picker.mjs +20 -38
  32. package/fesm2022/ngx-kit-gradient-picker.mjs.map +1 -1
  33. package/fesm2022/ngx-kit-grid-layout.mjs +14 -14
  34. package/fesm2022/ngx-kit-grid-layout.mjs.map +1 -1
  35. package/fesm2022/ngx-kit-image-editor.mjs +3 -3
  36. package/fesm2022/ngx-kit-image-editor.mjs.map +1 -1
  37. package/fesm2022/ngx-kit-menu.mjs +1 -1
  38. package/fesm2022/ngx-kit-menu.mjs.map +1 -1
  39. package/fesm2022/ngx-kit-message.mjs +1 -1
  40. package/fesm2022/ngx-kit-message.mjs.map +1 -1
  41. package/fesm2022/ngx-kit-notify.mjs +1 -1
  42. package/fesm2022/ngx-kit-notify.mjs.map +1 -1
  43. package/fesm2022/ngx-kit-time-picker.mjs +1 -1
  44. package/fesm2022/ngx-kit-time-picker.mjs.map +1 -1
  45. package/fesm2022/ngx-kit-virtual-scroll.mjs +2 -2
  46. package/fesm2022/ngx-kit-virtual-scroll.mjs.map +1 -1
  47. package/gallery/README.md +71 -71
  48. package/gradient-picker/README.md +41 -41
  49. package/grid-layout/README.md +64 -64
  50. package/image-editor/README.md +44 -44
  51. package/menu/README.md +85 -85
  52. package/message/README.md +70 -70
  53. package/notify/README.md +56 -56
  54. package/package.json +5 -9
  55. package/time-picker/README.md +89 -89
  56. package/types/ngx-kit-angle-selector.d.ts +13 -16
  57. package/types/ngx-kit-box-shadow.d.ts +37 -95
  58. package/types/ngx-kit-color-picker.d.ts +61 -58
  59. package/types/{ngx-kit-shared.d.ts → ngx-kit-core.d.ts} +156 -34
  60. package/types/ngx-kit-data-table.d.ts +2 -2
  61. package/types/ngx-kit-date-picker.d.ts +1 -1
  62. package/types/ngx-kit-dialog.d.ts +208 -107
  63. package/types/ngx-kit-drag-resize.d.ts +33 -6
  64. package/types/ngx-kit-gradient-picker.d.ts +4 -7
  65. package/types/ngx-kit-menu.d.ts +1 -1
  66. package/types/ngx-kit-time-picker.d.ts +1 -1
  67. package/virtual-scroll/README.md +199 -199
  68. package/fesm2022/ngx-kit-shared.mjs.map +0 -1
  69. package/fesm2022/ngx-kit-webflow.mjs +0 -709
  70. package/fesm2022/ngx-kit-webflow.mjs.map +0 -1
  71. package/types/ngx-kit-webflow.d.ts +0 -286
@@ -1,409 +1,508 @@
1
- import * as i1 from '@angular/common';
2
- import { DOCUMENT, isPlatformServer, CommonModule } from '@angular/common';
3
1
  import * as i0 from '@angular/core';
4
- import { InjectionToken, inject, Directive, Input, Inject, ChangeDetectorRef, ViewChild, ChangeDetectionStrategy, Component, Injector, runInInjectionContext, createComponent, Injectable, PLATFORM_ID, Optional, SkipSelf, NgModule } from '@angular/core';
2
+ import { signal, InjectionToken, input, inject, ElementRef, Directive, computed, ChangeDetectionStrategy, Component, Injector, Injectable, makeEnvironmentProviders, provideEnvironmentInitializer, PLATFORM_ID, Renderer2, DestroyRef, effect, NgModule } from '@angular/core';
3
+ import { DOCUMENT, NgComponentOutlet, isPlatformServer } from '@angular/common';
4
+ import { DIALOG_OVERLAY_CLASSNAME, OverlayService } from 'ngx-kit/core';
5
5
  import { Subject } from 'rxjs';
6
- import { randomStrnig } from 'ngx-kit/shared';
6
+ import * as i1 from 'ngx-kit/drag-resize';
7
+ import { NgxDraggable } from 'ngx-kit/drag-resize';
7
8
 
8
- const DIALOG_DATA = new InjectionToken('DIALOG_DATA');
9
- const DIALOG_REF = new InjectionToken('DIALOG_REF');
10
-
11
- class NgxDialogBodyDirective {
12
- _el;
13
- _renderer;
14
- height;
15
- _dialogRef = inject(DIALOG_REF);
16
- constructor(_el, _renderer) {
17
- this._el = _el;
18
- this._renderer = _renderer;
19
- this._dialogRef.body = this._el;
9
+ let uniqueId = 0;
10
+ function nextDialogId() {
11
+ uniqueId += 1;
12
+ return `ngx-dialog-${Date.now().toString(36)}-${uniqueId}`;
13
+ }
14
+ class NgxDialogRef {
15
+ id = nextDialogId();
16
+ /** true from the moment `close()` is called, even before teardown finishes. */
17
+ closing = signal(false, /* @ts-ignore */
18
+ ...(ngDevMode ? [{ debugName: "closing" }] : /* istanbul ignore next */ []));
19
+ /** true once the dialog has been fully removed from the DOM. */
20
+ closed = signal(false, /* @ts-ignore */
21
+ ...(ngDevMode ? [{ debugName: "closed" }] : /* istanbul ignore next */ []));
22
+ _afterClosed = new Subject();
23
+ /** Emits the result exactly once, after the dialog has been fully torn down. */
24
+ afterClosed = this._afterClosed.asObservable();
25
+ /** @internal set by the layout directives; read by NgxDialogBody to size itself. */
26
+ headerEl = signal(null, /* @ts-ignore */
27
+ ...(ngDevMode ? [{ debugName: "headerEl" }] : /* istanbul ignore next */ []));
28
+ /** @internal */
29
+ footerEl = signal(null, /* @ts-ignore */
30
+ ...(ngDevMode ? [{ debugName: "footerEl" }] : /* istanbul ignore next */ []));
31
+ /** @internal */
32
+ bodyEl = signal(null, /* @ts-ignore */
33
+ ...(ngDevMode ? [{ debugName: "bodyEl" }] : /* istanbul ignore next */ []));
34
+ /** @internal the dialog panel's own host element. */
35
+ panelEl = signal(null, /* @ts-ignore */
36
+ ...(ngDevMode ? [{ debugName: "panelEl" }] : /* istanbul ignore next */ []));
37
+ /** Optional synchronous guard - return `false` to prevent Escape/outside-click from closing. */
38
+ beforeClose;
39
+ overlayRef;
40
+ result;
41
+ /** @internal used by NgxDialogService right after creating the overlay. */
42
+ _attachOverlayRef(ref) {
43
+ this.overlayRef = ref;
20
44
  }
21
- ngAfterViewInit() {
22
- this.onWindowResize();
23
- if (this._dialogRef.dialog && this._dialogRef.dialog.nativeElement) {
24
- new ResizeObserver(() => {
25
- this.onWindowResize();
26
- }).observe(this._dialogRef.dialog.nativeElement);
27
- }
45
+ /** @internal used by the header/footer/body directives and the panel component. */
46
+ _setHeaderElement(el) {
47
+ this.headerEl.set(el);
28
48
  }
29
- // @HostListener('window:resize', ['$event'])
30
- onWindowResize(ev) {
31
- if (!window)
49
+ /** @internal */
50
+ _setFooterElement(el) {
51
+ this.footerEl.set(el);
52
+ }
53
+ /** @internal */
54
+ _setBodyElement(el) {
55
+ this.bodyEl.set(el);
56
+ }
57
+ /** @internal */
58
+ _setPanelElement(el) {
59
+ this.panelEl.set(el);
60
+ }
61
+ /** Closes the dialog and emits `result` on `afterClosed` once torn down. Idempotent. */
62
+ close(result) {
63
+ if (this.closing() || this.closed()) {
32
64
  return;
33
- let headerH = 0;
34
- let footerH = 0;
35
- let dialogH = window.innerHeight;
36
- if (this._dialogRef.header) {
37
- headerH = this._dialogRef.header.nativeElement.offsetHeight;
38
65
  }
39
- if (this._dialogRef.footer) {
40
- footerH = this._dialogRef.footer.nativeElement.offsetHeight;
41
- }
42
- if (this._dialogRef.dialog && this._dialogRef.dialog.nativeElement.offsetHeight < dialogH) {
43
- dialogH = this._dialogRef.dialog.nativeElement.offsetHeight;
66
+ this.closing.set(true);
67
+ this.result = result;
68
+ this.overlayRef?.close();
69
+ }
70
+ /** @internal called by NgxDialogService's `onClosed` callback once the overlay is fully torn down. */
71
+ _finalizeClose() {
72
+ if (this.closed()) {
73
+ return;
44
74
  }
45
- this.height = dialogH - headerH - footerH;
46
- this._renderer.setStyle(this._el.nativeElement, 'max-height', this.height + 'px');
47
- // console.log(this.height, ':', 'windowHeight', dialogH, 'h', headerH, 'f', footerH);
75
+ this.closed.set(true);
76
+ this._afterClosed.next(this.result);
77
+ this._afterClosed.complete();
48
78
  }
49
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogBodyDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
50
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.4", type: NgxDialogBodyDirective, isStandalone: false, selector: "ngx-dialog-body,[ngxDialogBody]", host: { classAttribute: "dialog-body" }, exportAs: ["ngxDialogBody"], ngImport: i0 });
51
79
  }
52
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogBodyDirective, decorators: [{
53
- type: Directive,
54
- args: [{
55
- standalone: false,
56
- selector: 'ngx-dialog-body,[ngxDialogBody]',
57
- host: {
58
- class: 'dialog-body',
59
- },
60
- exportAs: 'ngxDialogBody',
61
- }]
62
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }] });
63
80
 
64
- class NgxDialogFooterDirective {
65
- _el;
66
- align = 'end';
67
- _dialogRef = inject(DIALOG_REF);
68
- constructor(_el) {
69
- this._el = _el;
81
+ /**
82
+ * BREAKING CHANGE from the previous version of this config:
83
+ * - `allowCloseOnOutsideClick` -> `closeOnOutsideClick` (naming now matches
84
+ * `ngx-kit/overlay`'s options, which this service is built directly on).
85
+ * - `header`/`footer` are now actually wired up (previously declared but
86
+ * unused) - set `enable: true` to get an automatic header/footer without
87
+ * having to place the `ngxDialogHeader`/`ngxDialogFooter` directives
88
+ * yourself inside the content component.
89
+ */
90
+ class NgxDialogConfig {
91
+ /** Data made available to the content component (and to `ngx-dialog-panel`
92
+ * itself) via the `DIALOG_DATA` injection token. */
93
+ data = {};
94
+ /** Named size preset - sets sensible min/max width bounds. Combine with
95
+ * `width`/`maxWidth`/... for full manual control. */
96
+ size;
97
+ width;
98
+ minWidth;
99
+ maxWidth;
100
+ height;
101
+ minHeight;
102
+ maxHeight;
103
+ /** Extra class(es) on the dialog panel (the `ngx-dialog-panel` host). */
104
+ panelClass = 'ngx-kit';
105
+ /** Extra class(es) on the backdrop element behind the panel. */
106
+ backdropClass = 'ngx-dialog-backdrop';
107
+ header = {
108
+ enable: false,
109
+ showCloseButton: true,
110
+ showMaximizeButton: true,
111
+ };
112
+ footer = { enable: false, align: 'end' };
113
+ /** Close when clicking outside the panel. Default: false (modal by default). */
114
+ closeOnOutsideClick = false;
115
+ /** Close on Escape. Default: true. */
116
+ closeOnEscape = true;
117
+ /** Shorthand for `closeOnOutsideClick: false, closeOnEscape: false` - the
118
+ * dialog can then only be closed programmatically (e.g. via its own
119
+ * buttons calling `dialogRef.close()`). */
120
+ disableClose = false;
121
+ /** Synchronous guard consulted before Escape/outside-click would close the
122
+ * dialog - return `false` to block it (e.g. unsaved changes). Does not
123
+ * affect a programmatic `dialogRef.close()` call. */
124
+ beforeClose;
125
+ /** Prevent the page behind the dialog from scrolling while it's open. Default: true. */
126
+ lockBodyScroll = true;
127
+ /** Move focus into the dialog on open. Default: true. */
128
+ autoFocus = true;
129
+ /** Restore focus to the previously focused element on close. Default: true. */
130
+ restoreFocus = true;
131
+ /** Render via the native Popover API when supported. Default: true. */
132
+ usePopover = true;
133
+ role = 'dialog';
134
+ ariaLabel;
135
+ ariaLabelledby;
136
+ ariaDescribedby;
137
+ /** Entry animation for the panel. Default: 'zoom'. */
138
+ animation = 'zoom';
139
+ /** Parent injector for the content component (and `ngx-dialog-panel`
140
+ * itself). Defaults to the root injector. */
141
+ injector;
142
+ constructor(init) {
143
+ Object.assign(this, init);
70
144
  }
145
+ }
146
+
147
+ const DIALOG_DATA = new InjectionToken('NGX_DIALOG_DATA');
148
+ const DIALOG_REF = new InjectionToken('NGX_DIALOG_REF');
149
+ /** The resolved config for the dialog currently being rendered. */
150
+ const NGX_DIALOG_DEFAULT_CONFIG = new NgxDialogConfig();
151
+ const NGX_DIALOG_CONFIG = new InjectionToken('NGX_NGX_DIALOG_CONFIG');
152
+ /** The arbitrary content component passed to `open()`, projected via `*ngComponentOutlet`. */
153
+ const DIALOG_CONTENT = new InjectionToken('NGX_DIALOG_CONTENT');
154
+
155
+ class NgxDialogFooter {
156
+ align = input('end', /* @ts-ignore */
157
+ ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
158
+ el = inject((ElementRef));
159
+ dialogRef = inject(DIALOG_REF);
71
160
  ngOnInit() {
72
- this._dialogRef.footer = this._el;
161
+ this.dialogRef._setFooterElement(this.el.nativeElement);
73
162
  }
74
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogFooterDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
75
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.4", type: NgxDialogFooterDirective, isStandalone: false, selector: "ngx-dialog-footer,[ngxDialogFooter]", inputs: { align: "align" }, host: { properties: { "class.align-start": "align===\"start\"", "class.align-end": "align===\"end\"", "class.align-space-between": "align===\"space-between\"", "class.align-center": "align===\"center\"", "class.align-space-around": "align===\"space-around\"" }, classAttribute: "dialog-footer" }, exportAs: ["ngxDialogFooter"], ngImport: i0 });
163
+ ngOnDestroy() {
164
+ this.dialogRef._setFooterElement(null);
165
+ }
166
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogFooter, deps: [], target: i0.ɵɵFactoryTarget.Directive });
167
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.4", type: NgxDialogFooter, isStandalone: true, selector: "ngx-dialog-footer,[ngxDialogFooter]", inputs: { align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.align-start": "align() === \"start\"", "class.align-end": "align() === \"end\"", "class.align-space-between": "align() === \"space-between\"", "class.align-center": "align() === \"center\"", "class.align-space-around": "align() === \"space-around\"" }, classAttribute: "dialog-footer" }, exportAs: ["ngxDialogFooter"], ngImport: i0 });
76
168
  }
77
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogFooterDirective, decorators: [{
169
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogFooter, decorators: [{
78
170
  type: Directive,
79
171
  args: [{
80
- standalone: false,
81
172
  selector: 'ngx-dialog-footer,[ngxDialogFooter]',
173
+ standalone: true,
82
174
  host: {
83
175
  class: 'dialog-footer',
84
- '[class.align-start]': 'align==="start"',
85
- '[class.align-end]': 'align==="end"',
86
- '[class.align-space-between]': 'align==="space-between"',
87
- '[class.align-center]': 'align==="center"',
88
- '[class.align-space-around]': 'align==="space-around"',
176
+ '[class.align-start]': 'align() === "start"',
177
+ '[class.align-end]': 'align() === "end"',
178
+ '[class.align-space-between]': 'align() === "space-between"',
179
+ '[class.align-center]': 'align() === "center"',
180
+ '[class.align-space-around]': 'align() === "space-around"',
89
181
  },
90
182
  exportAs: 'ngxDialogFooter',
91
183
  }]
92
- }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { align: [{
93
- type: Input
94
- }] } });
184
+ }], propDecorators: { align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }] } });
95
185
 
96
- class NgxDialogHeaderDirective {
97
- _el;
98
- _document;
99
- showCloseButton = true;
100
- _dialogRef = inject(DIALOG_REF);
101
- constructor(_el, _document) {
102
- this._el = _el;
103
- this._document = _document;
104
- }
186
+ const CLOSE_ICON_SVG = `<svg width="16" height="16" fill="currentColor" viewBox="0 0 320 512" aria-hidden="true">
187
+ <path d="M312.1 375c9.369 9.369 9.369 24.57 0 33.94s-24.57 9.369-33.94 0L160 289.9l-119 119c-9.369 9.369-24.57 9.369-33.94 0s-9.369-24.57 0-33.94L126.1 256L7.027 136.1c-9.369-9.369-9.369-24.57 0-33.94s24.57-9.369 33.94 0L160 222.1l119-119c9.369-9.369 24.57-9.369 33.94 0s9.369 24.57 0 33.94L193.9 256L312.1 375z"/>
188
+ </svg>`;
189
+ const MAXIMIZE_ICON_SVG = `<svg name="maximize" stroke="currentColor" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
190
+ <path d="M7.4852 16.5149C6.9104 15.9401 7.00595 13.4982 7.00595 13.4982M7.4852 16.5149C8.06001 17.0897 10.5019 16.994 10.5019 16.994M7.4852 16.5149L11 13M16.5149 7.48512C15.9401 6.91031 13.4982 7.00596 13.4982 7.00596M16.5149 7.48512C17.0897 8.05993 16.994 10.5018 16.994 10.5018M16.5149 7.48512L13 11" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
191
+ <path d="M2.5 12C2.5 7.52166 2.5 5.28249 3.89124 3.89124C5.28249 2.5 7.52166 2.5 12 2.5C16.4783 2.5 18.7175 2.5 20.1088 3.89124C21.5 5.28249 21.5 7.52166 21.5 12C21.5 16.4783 21.5 18.7175 20.1088 20.1088C18.7175 21.5 16.4783 21.5 12 21.5C7.52166 21.5 5.28249 21.5 3.89124 20.1088C2.5 18.7175 2.5 16.4783 2.5 12Z" stroke-width="1.5"/>
192
+ </svg>`;
193
+ const RESTORE_ICON_SVG = `<svg name="restore" stroke="currentColor" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
194
+ <path d="M2.5 12C2.5 7.52166 2.5 5.28249 3.89124 3.89124C5.28249 2.5 7.52166 2.5 12 2.5C16.4783 2.5 18.7175 2.5 20.1088 3.89124C21.5 5.28249 21.5 7.52166 21.5 12C21.5 16.4783 21.5 18.7175 20.1088 20.1088C18.7175 21.5 16.4783 21.5 12 21.5C7.52166 21.5 5.28249 21.5 3.89124 20.1088C2.5 18.7175 2.5 16.4783 2.5 12Z" stroke-width="1.5"/>
195
+ <path d="M12.9833 11.0167C12.4085 10.4419 12.5041 8 12.5041 8M12.9833 11.0167C13.5581 11.5915 16 11.4958 16 11.4958M12.9833 11.0167L17 7M11.0131 12.9868C10.4383 12.412 7.99641 12.5077 7.99641 12.5077M11.0131 12.9868C11.5879 13.5616 11.4922 16.0035 11.4922 16.0035M11.0131 12.9868L7 16.9999" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
196
+ </svg>`;
197
+ class NgxDialogHeader {
198
+ config = inject(NGX_DIALOG_CONFIG);
199
+ showCloseButton = input(this.config.header?.showCloseButton ?? true, /* @ts-ignore */
200
+ ...(ngDevMode ? [{ debugName: "showCloseButton" }] : /* istanbul ignore next */ []));
201
+ showMaximizeButton = input(this.config.header?.showMaximizeButton ?? true, /* @ts-ignore */
202
+ ...(ngDevMode ? [{ debugName: "showMaximizeButton" }] : /* istanbul ignore next */ []));
203
+ el = inject((ElementRef));
204
+ document = inject(DOCUMENT);
205
+ dialogRef = inject(DIALOG_REF);
206
+ drag = inject(NgxDraggable);
207
+ isMaximized = false;
105
208
  ngOnInit() {
106
- this._el.nativeElement.innerHTML = '<span>' + this._el.nativeElement.innerHTML + '</span>';
107
- if (this.showCloseButton) {
108
- let closeBtn = this._document.createElement('button');
109
- closeBtn.className = 'close-btn';
110
- closeBtn.innerHTML =
111
- '<svg width="20" height="20" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M312.1 375c9.369 9.369 9.369 24.57 0 33.94s-24.57 9.369-33.94 0L160 289.9l-119 119c-9.369 9.369-24.57 9.369-33.94 0s-9.369-24.57 0-33.94L126.1 256L7.027 136.1c-9.369-9.369-9.369-24.57 0-33.94s24.57-9.369 33.94 0L160 222.1l119-119c9.369-9.369 24.57-9.369 33.94 0s9.369 24.57 0 33.94L193.9 256L312.1 375z"/></svg>';
112
- closeBtn.onclick = closeBtn.ontouchend = () => {
113
- this._dialogRef.close();
114
- };
115
- this._el.nativeElement.appendChild(closeBtn);
209
+ this.drag.dragRootElement.set('.ngx-ui-overlay');
210
+ this.drag.dragHandle.set('.dialog-header-title');
211
+ // Wrap the existing (Angular-rendered) header content in a title span by
212
+ // MOVING the actual DOM nodes, not by re-serializing/re-parsing
213
+ // `innerHTML`. The original implementation did
214
+ // `el.innerHTML = '<span>' + el.innerHTML + '</span>'`, which silently
215
+ // destroys any event listeners or component state living inside the
216
+ // header content (anything beyond static text) because the browser
217
+ // throws away and re-parses the whole subtree.
218
+ const titleWrapper = this.document.createElement('span');
219
+ titleWrapper.className = 'dialog-header-title';
220
+ while (this.el.nativeElement.firstChild) {
221
+ titleWrapper.appendChild(this.el.nativeElement.firstChild);
222
+ }
223
+ this.el.nativeElement.appendChild(titleWrapper);
224
+ if (this.showMaximizeButton()) {
225
+ const fullScreenBtn = this.document.createElement('button');
226
+ fullScreenBtn.type = 'button';
227
+ fullScreenBtn.className = 'ngx-dialog-action-btn';
228
+ fullScreenBtn.setAttribute('aria-label', 'Maximaize');
229
+ fullScreenBtn.setAttribute('title', 'Maximaize');
230
+ fullScreenBtn.innerHTML = MAXIMIZE_ICON_SVG;
231
+ fullScreenBtn.addEventListener('click', (ev) => this.fullScreen(ev));
232
+ this.el.nativeElement.appendChild(fullScreenBtn);
233
+ }
234
+ if (this.showCloseButton()) {
235
+ const closeBtn = this.document.createElement('button');
236
+ closeBtn.type = 'button';
237
+ closeBtn.className = 'ngx-dialog-action-btn';
238
+ closeBtn.setAttribute('aria-label', 'Close');
239
+ closeBtn.setAttribute('title', 'Close');
240
+ closeBtn.innerHTML = CLOSE_ICON_SVG;
241
+ closeBtn.addEventListener('click', () => this.dialogRef.close());
242
+ this.el.nativeElement.appendChild(closeBtn);
243
+ }
244
+ this.dialogRef._setHeaderElement(this.el.nativeElement);
245
+ }
246
+ fullScreen(ev) {
247
+ const overlay = this.el.nativeElement.closest(`.${DIALOG_OVERLAY_CLASSNAME}`);
248
+ this.isMaximized = !this.isMaximized;
249
+ this.drag.disabled.set(this.isMaximized);
250
+ if (overlay) {
251
+ overlay.classList.toggle('ngx-dialog-fullscreen');
252
+ const btn = ev.currentTarget;
253
+ btn.innerHTML = this.isMaximized ? RESTORE_ICON_SVG : MAXIMIZE_ICON_SVG;
254
+ btn.setAttribute('aria-label', this.isMaximized ? 'Restore' : 'Maximaize');
255
+ btn.setAttribute('title', this.isMaximized ? 'Restore' : 'Maximaize');
116
256
  }
117
- this._dialogRef.header = this._el;
118
257
  }
119
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogHeaderDirective, deps: [{ token: i0.ElementRef }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Directive });
120
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.4", type: NgxDialogHeaderDirective, isStandalone: false, selector: "ngx-dialog-header,[ngxDialogHeader]", inputs: { showCloseButton: "showCloseButton" }, host: { classAttribute: "dialog-header" }, exportAs: ["ngxDialogHeader"], ngImport: i0 });
258
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogHeader, deps: [], target: i0.ɵɵFactoryTarget.Directive });
259
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.4", type: NgxDialogHeader, isStandalone: true, selector: "ngx-dialog-header,[ngxDialogHeader]", inputs: { showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, showMaximizeButton: { classPropertyName: "showMaximizeButton", publicName: "showMaximizeButton", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "dialog-header" }, exportAs: ["ngxDialogHeader"], hostDirectives: [{ directive: i1.NgxDraggable }], ngImport: i0 });
121
260
  }
122
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogHeaderDirective, decorators: [{
261
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogHeader, decorators: [{
123
262
  type: Directive,
124
263
  args: [{
125
- standalone: false,
126
264
  selector: 'ngx-dialog-header,[ngxDialogHeader]',
127
- host: {
128
- class: 'dialog-header',
129
- },
265
+ standalone: true,
266
+ hostDirectives: [NgxDraggable],
267
+ host: { class: 'dialog-header' },
130
268
  exportAs: 'ngxDialogHeader',
131
269
  }]
132
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: Document, decorators: [{
133
- type: Inject,
134
- args: [DOCUMENT]
135
- }] }], propDecorators: { showCloseButton: [{
136
- type: Input
137
- }] } });
270
+ }], propDecorators: { showCloseButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCloseButton", required: false }] }], showMaximizeButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showMaximizeButton", required: false }] }] } });
138
271
 
272
+ /**
273
+ * The dialog "panel" shell. It no longer owns the backdrop, centering,
274
+ * focus trap, Escape handling or outside-click handling - all of that now
275
+ * lives in `OverlayService`, which this component is rendered inside of.
276
+ * This is intentionally a thin, fully signal-driven shell: no
277
+ * `AfterViewInit`, no manual `ChangeDetectorRef.detectChanges()`, no
278
+ * imperative style writes. Angular schedules change detection automatically
279
+ * whenever a signal read from the template changes, including in zoneless
280
+ * apps.
281
+ */
139
282
  class NgxDialogComponent {
140
- config;
141
- component;
142
- _onClose = new Subject();
143
- onClose = this._onClose.asObservable();
144
- ngxDialog;
145
- _dialogRef = inject(DIALOG_REF);
146
- cd = inject(ChangeDetectorRef);
147
- constructor() { }
148
- ngOnInit() { }
149
- ngAfterViewInit() {
150
- this._dialogRef.dialog = this.ngxDialog;
151
- this.setStyle();
152
- this.cd.detectChanges();
153
- }
154
- ngOnDestroy() { }
155
- onOverlayClicked(evt) {
156
- if (this.config?.allowCloseOnOutsideClick) {
157
- this._dialogRef.close();
158
- }
159
- }
160
- onDialogClicked(evt) {
161
- evt.stopPropagation();
162
- }
163
- close() {
164
- this._onClose.next();
165
- }
166
- setStyle() {
167
- if (this.ngxDialog) {
168
- if (this.config?.width) {
169
- this.ngxDialog.nativeElement.style.width = this.config.width;
170
- }
171
- if (this.config?.maxWidth) {
172
- this.ngxDialog.nativeElement.style.maxWidth = this.config.maxWidth;
173
- }
174
- else {
175
- this.ngxDialog.nativeElement.style.maxWidth = '100%';
176
- }
177
- if (this.config?.minWidth) {
178
- this.ngxDialog.nativeElement.style.minWidth = this.config.minWidth;
179
- }
180
- if (this.config?.height) {
181
- this.ngxDialog.nativeElement.style.height = this.config.height;
182
- }
183
- if (this.config?.maxHeight) {
184
- this.ngxDialog.nativeElement.style.maxHeight = this.config.maxHeight;
185
- }
186
- else {
187
- this.ngxDialog.nativeElement.style.maxHeight = '100%';
188
- }
189
- if (this.config?.minHeight) {
190
- this.ngxDialog.nativeElement.style.minHeight = this.config.minHeight;
191
- }
192
- }
283
+ dialogRef = inject(DIALOG_REF);
284
+ config = inject(NGX_DIALOG_CONFIG);
285
+ content = inject(DIALOG_CONTENT);
286
+ sizeClass = computed(() => this.config.size ? `ngx-dialog-size-${this.config.size}` : '', /* @ts-ignore */
287
+ ...(ngDevMode ? [{ debugName: "sizeClass" }] : /* istanbul ignore next */ []));
288
+ constructor() {
289
+ this.dialogRef._setPanelElement(inject((ElementRef)).nativeElement);
193
290
  }
194
291
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
195
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.4", type: NgxDialogComponent, isStandalone: false, selector: "ng-component", viewQueries: [{ propertyName: "ngxDialog", first: true, predicate: ["ngxDialog"], descendants: true }], ngImport: i0, template: "<div class=\"ngx-dialog-overlay\" (click)=\"onOverlayClicked($event)\">\n <div class=\"ngx-dialog\" (click)=\"onDialogClicked($event)\" #ngxDialog>\n <ng-container *ngComponentOutlet=\"component\"></ng-container>\n </div>\n</div>\n", styles: [":host{--ngx-dialog-bg: light-dark(#ffffff, #1c1c22);--ngx-dialog-fg: light-dark(#000000, #f0f0f5);--ngx-dialog-header-bg: light-dark(#ffffff, #1c1c22);--ngx-dialog-header-fg: light-dark(#1c1c22, #ffffff);--ngx-dialog-corner-radius: 1rem;--ngx-dialog-min-width: 50rem}.ngx-dialog-overlay{display:flex;flex-direction:column;position:fixed;inset:0;background:#0000004d;align-items:center;justify-content:center;transition:opacity .4s cubic-bezier(.25,.8,.25,1);z-index:999}::ng-deep .ngx-dialog{box-shadow:0 0 20px light-dark(#797979,rgba(2,2,2,.7411764706));display:flex;flex-direction:column;min-width:var(--ngx-dialog-min-width);border-radius:var(--ngx-dialog-corner-radius);overflow:hidden;background-color:var(--panel-bg, var(--ngx-dialog-bg));color:var(--side-config-fg, var(--ngx-dialog-fg));box-sizing:border-box;animation:ShowDialog .2s cubic-bezier(.25,.8,.25,1)}::ng-deep .ngx-dialog .dialog-header{display:block;background:var(--ngx-dialog-header-bg);display:flex;align-items:center;justify-content:space-between;padding:0 15px;color:var(--ngx-dialog-header-fg);font-size:.8rem;box-sizing:border-box;height:50px;border-bottom:1px rgba(107,107,107,.2) solid}::ng-deep .ngx-dialog .dialog-header .close-btn{background:none;cursor:pointer;border:none;color:var(--ngx-dialog-header-fg)}::ng-deep .ngx-dialog .dialog-body{display:block;overflow:auto;padding:20px;box-sizing:border-box}::ng-deep .ngx-dialog .dialog-footer{display:block;box-shadow:0 0 10px #72727252;padding:0 15px;display:flex;align-items:center;min-height:44px}::ng-deep .ngx-dialog .dialog-footer.align-start{justify-content:flex-start}::ng-deep .ngx-dialog .dialog-footer.align-end{justify-content:flex-end}::ng-deep .ngx-dialog .dialog-footer.align-space-between{justify-content:space-between}::ng-deep .ngx-dialog .dialog-footer.align-center{justify-content:center}::ng-deep .ngx-dialog .dialog-footer.align-space-around{justify-content:space-around}@keyframes ShowDialog{0%{transform:translate(0) scale(0)}to{transform:translate(0) scale(1)}}\n"], dependencies: [{ kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
292
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NgxDialogComponent, isStandalone: true, selector: "ngx-dialog-panel", host: { properties: { "class": "sizeClass()" }, classAttribute: "ngx-dialog-panel" }, ngImport: i0, template: "@if (config.header?.enable) {\n <div\n ngxDialogHeader\n [showCloseButton]=\"config.header?.showCloseButton ?? true\"\n [showMaximizeButton]=\"config.header?.showMaximizeButton ?? true\">\n {{ config.header?.title }}\n </div>\n}\n\n<ng-container *ngComponentOutlet=\"content\" />\n\n@if (config.footer?.enable) {\n <div ngxDialogFooter [align]=\"config.footer?.align ?? 'end'\">\n <button type=\"button\" class=\"ngx-dialog-default-close-btn\" (click)=\"dialogRef.close()\">\n {{ config.footer?.closeText ?? 'Close' }}\n </button>\n </div>\n}\n", styles: [":host{--ngx-dialog-bg: light-dark(#ffffff, #1c1c22);--ngx-dialog-fg: light-dark(#000000, #f0f0f5);--ngx-dialog-header-bg: light-dark(#ffffff, #1c1c22);--ngx-dialog-header-fg: light-dark(#1c1c22, #ffffff);display:flex;flex-direction:column;box-sizing:border-box;width:100%;height:100%;overflow:hidden;background-color:var(--panel-bg, var(--ngx-dialog-bg));color:var(--side-config-fg, var(--ngx-dialog-fg));animation:ngxDialogZoomIn .18s cubic-bezier(.25,.8,.25,1);max-height:100dvh}:host(.ngx-dialog-size-sm){--ngx-dialog-min-width: 20rem;max-width:24rem}:host(.ngx-dialog-size-md){--ngx-dialog-min-width: 28rem;max-width:36rem}:host(.ngx-dialog-size-lg){--ngx-dialog-min-width: 36rem;max-width:56rem}:host(.ngx-dialog-size-xl){--ngx-dialog-min-width: 44rem;max-width:72rem}:host(.ngx-dialog-size-full){width:100%;height:100%;max-width:none;border-radius:0}::ng-deep .dialog-header{display:flex;align-items:center;justify-content:space-between;gap:8px;flex:0 0 auto;padding:0 15px;height:50px;box-sizing:border-box;color:var(--ngx-dialog-header-fg);background:var(--ngx-dialog-header-bg);font-size:.95rem;font-weight:600;border-bottom:1px solid rgba(107,107,107,.2)}::ng-deep .dialog-header .dialog-header-title{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;height:100%;display:flex;align-items:center}::ng-deep .dialog-header:not(.disable-drag) .dialog-header-title{cursor:move}::ng-deep .dialog-header .ngx-dialog-action-btn{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;background:none;border:none;cursor:pointer;color:inherit;padding:1px;border-radius:6px;width:24px;height:24px;background:light-dark(#efeff1,#2b2b33)}::ng-deep .dialog-header .ngx-dialog-action-btn svg{width:100%}::ng-deep .dialog-header .ngx-dialog-action-btn:hover{background:light-dark(#e2e2e6,#34343d)}::ng-deep .dialog-body{display:block;overflow:auto;padding:20px;box-sizing:border-box}::ng-deep .dialog-footer{flex:0 0 auto;display:flex;align-items:center;gap:8px;padding:12px 15px;box-shadow:0 -1px #72727233}::ng-deep .dialog-footer.align-start{justify-content:flex-start}::ng-deep .dialog-footer.align-end{justify-content:flex-end}::ng-deep .dialog-footer.align-center{justify-content:center}::ng-deep .dialog-footer.align-space-between{justify-content:space-between}::ng-deep .dialog-footer.align-space-around{justify-content:space-around}::ng-deep .ngx-dialog-backdrop{background:light-dark(rgba(71,71,71,.5490196078),rgba(39,38,38,.4509803922))!important;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px)}::ng-deep .ngx-dialog-fullscreen{width:100dvw!important;height:100dvh!important;max-height:unset!important;max-width:unset!important;transform:none!important;inset:0!important}@keyframes ngxDialogZoomIn{0%{transform:scale(.92);opacity:0}to{transform:scale(1);opacity:1}}@media(prefers-reduced-motion:reduce){:host{animation:none}}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: NgxDialogHeader, selector: "ngx-dialog-header,[ngxDialogHeader]", inputs: ["showCloseButton", "showMaximizeButton"], exportAs: ["ngxDialogHeader"] }, { kind: "directive", type: NgxDialogFooter, selector: "ngx-dialog-footer,[ngxDialogFooter]", inputs: ["align"], exportAs: ["ngxDialogFooter"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
196
293
  }
197
294
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogComponent, decorators: [{
198
295
  type: Component,
199
- args: [{ standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ngx-dialog-overlay\" (click)=\"onOverlayClicked($event)\">\n <div class=\"ngx-dialog\" (click)=\"onDialogClicked($event)\" #ngxDialog>\n <ng-container *ngComponentOutlet=\"component\"></ng-container>\n </div>\n</div>\n", styles: [":host{--ngx-dialog-bg: light-dark(#ffffff, #1c1c22);--ngx-dialog-fg: light-dark(#000000, #f0f0f5);--ngx-dialog-header-bg: light-dark(#ffffff, #1c1c22);--ngx-dialog-header-fg: light-dark(#1c1c22, #ffffff);--ngx-dialog-corner-radius: 1rem;--ngx-dialog-min-width: 50rem}.ngx-dialog-overlay{display:flex;flex-direction:column;position:fixed;inset:0;background:#0000004d;align-items:center;justify-content:center;transition:opacity .4s cubic-bezier(.25,.8,.25,1);z-index:999}::ng-deep .ngx-dialog{box-shadow:0 0 20px light-dark(#797979,rgba(2,2,2,.7411764706));display:flex;flex-direction:column;min-width:var(--ngx-dialog-min-width);border-radius:var(--ngx-dialog-corner-radius);overflow:hidden;background-color:var(--panel-bg, var(--ngx-dialog-bg));color:var(--side-config-fg, var(--ngx-dialog-fg));box-sizing:border-box;animation:ShowDialog .2s cubic-bezier(.25,.8,.25,1)}::ng-deep .ngx-dialog .dialog-header{display:block;background:var(--ngx-dialog-header-bg);display:flex;align-items:center;justify-content:space-between;padding:0 15px;color:var(--ngx-dialog-header-fg);font-size:.8rem;box-sizing:border-box;height:50px;border-bottom:1px rgba(107,107,107,.2) solid}::ng-deep .ngx-dialog .dialog-header .close-btn{background:none;cursor:pointer;border:none;color:var(--ngx-dialog-header-fg)}::ng-deep .ngx-dialog .dialog-body{display:block;overflow:auto;padding:20px;box-sizing:border-box}::ng-deep .ngx-dialog .dialog-footer{display:block;box-shadow:0 0 10px #72727252;padding:0 15px;display:flex;align-items:center;min-height:44px}::ng-deep .ngx-dialog .dialog-footer.align-start{justify-content:flex-start}::ng-deep .ngx-dialog .dialog-footer.align-end{justify-content:flex-end}::ng-deep .ngx-dialog .dialog-footer.align-space-between{justify-content:space-between}::ng-deep .ngx-dialog .dialog-footer.align-center{justify-content:center}::ng-deep .ngx-dialog .dialog-footer.align-space-around{justify-content:space-around}@keyframes ShowDialog{0%{transform:translate(0) scale(0)}to{transform:translate(0) scale(1)}}\n"] }]
200
- }], ctorParameters: () => [], propDecorators: { ngxDialog: [{
201
- type: ViewChild,
202
- args: ['ngxDialog']
203
- }] } });
296
+ args: [{ selector: 'ngx-dialog-panel', standalone: true, imports: [NgComponentOutlet, NgxDialogHeader, NgxDialogFooter], changeDetection: ChangeDetectionStrategy.OnPush, host: {
297
+ class: 'ngx-dialog-panel',
298
+ '[class]': 'sizeClass()',
299
+ }, template: "@if (config.header?.enable) {\n <div\n ngxDialogHeader\n [showCloseButton]=\"config.header?.showCloseButton ?? true\"\n [showMaximizeButton]=\"config.header?.showMaximizeButton ?? true\">\n {{ config.header?.title }}\n </div>\n}\n\n<ng-container *ngComponentOutlet=\"content\" />\n\n@if (config.footer?.enable) {\n <div ngxDialogFooter [align]=\"config.footer?.align ?? 'end'\">\n <button type=\"button\" class=\"ngx-dialog-default-close-btn\" (click)=\"dialogRef.close()\">\n {{ config.footer?.closeText ?? 'Close' }}\n </button>\n </div>\n}\n", styles: [":host{--ngx-dialog-bg: light-dark(#ffffff, #1c1c22);--ngx-dialog-fg: light-dark(#000000, #f0f0f5);--ngx-dialog-header-bg: light-dark(#ffffff, #1c1c22);--ngx-dialog-header-fg: light-dark(#1c1c22, #ffffff);display:flex;flex-direction:column;box-sizing:border-box;width:100%;height:100%;overflow:hidden;background-color:var(--panel-bg, var(--ngx-dialog-bg));color:var(--side-config-fg, var(--ngx-dialog-fg));animation:ngxDialogZoomIn .18s cubic-bezier(.25,.8,.25,1);max-height:100dvh}:host(.ngx-dialog-size-sm){--ngx-dialog-min-width: 20rem;max-width:24rem}:host(.ngx-dialog-size-md){--ngx-dialog-min-width: 28rem;max-width:36rem}:host(.ngx-dialog-size-lg){--ngx-dialog-min-width: 36rem;max-width:56rem}:host(.ngx-dialog-size-xl){--ngx-dialog-min-width: 44rem;max-width:72rem}:host(.ngx-dialog-size-full){width:100%;height:100%;max-width:none;border-radius:0}::ng-deep .dialog-header{display:flex;align-items:center;justify-content:space-between;gap:8px;flex:0 0 auto;padding:0 15px;height:50px;box-sizing:border-box;color:var(--ngx-dialog-header-fg);background:var(--ngx-dialog-header-bg);font-size:.95rem;font-weight:600;border-bottom:1px solid rgba(107,107,107,.2)}::ng-deep .dialog-header .dialog-header-title{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;height:100%;display:flex;align-items:center}::ng-deep .dialog-header:not(.disable-drag) .dialog-header-title{cursor:move}::ng-deep .dialog-header .ngx-dialog-action-btn{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;background:none;border:none;cursor:pointer;color:inherit;padding:1px;border-radius:6px;width:24px;height:24px;background:light-dark(#efeff1,#2b2b33)}::ng-deep .dialog-header .ngx-dialog-action-btn svg{width:100%}::ng-deep .dialog-header .ngx-dialog-action-btn:hover{background:light-dark(#e2e2e6,#34343d)}::ng-deep .dialog-body{display:block;overflow:auto;padding:20px;box-sizing:border-box}::ng-deep .dialog-footer{flex:0 0 auto;display:flex;align-items:center;gap:8px;padding:12px 15px;box-shadow:0 -1px #72727233}::ng-deep .dialog-footer.align-start{justify-content:flex-start}::ng-deep .dialog-footer.align-end{justify-content:flex-end}::ng-deep .dialog-footer.align-center{justify-content:center}::ng-deep .dialog-footer.align-space-between{justify-content:space-between}::ng-deep .dialog-footer.align-space-around{justify-content:space-around}::ng-deep .ngx-dialog-backdrop{background:light-dark(rgba(71,71,71,.5490196078),rgba(39,38,38,.4509803922))!important;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px)}::ng-deep .ngx-dialog-fullscreen{width:100dvw!important;height:100dvh!important;max-height:unset!important;max-width:unset!important;transform:none!important;inset:0!important}@keyframes ngxDialogZoomIn{0%{transform:scale(.92);opacity:0}to{transform:scale(1);opacity:1}}@media(prefers-reduced-motion:reduce){:host{animation:none}}\n"] }]
300
+ }], ctorParameters: () => [] });
204
301
 
205
- class NgxDialogConfig {
302
+ class NgxDialogService {
303
+ overlay = inject(OverlayService);
304
+ injector = inject(Injector);
305
+ _openRefs = signal([], /* @ts-ignore */
306
+ ...(ngDevMode ? [{ debugName: "_openRefs" }] : /* istanbul ignore next */ []));
307
+ /** Every currently open dialog, oldest first. */
308
+ openDialogs = this._openRefs.asReadonly();
309
+ /** How many dialogs are currently open. */
310
+ openCount = computed(() => this._openRefs().length, /* @ts-ignore */
311
+ ...(ngDevMode ? [{ debugName: "openCount" }] : /* istanbul ignore next */ []));
312
+ defaultConfig = inject(NGX_DIALOG_CONFIG);
206
313
  /**
207
- * pass data to dialog
314
+ * Opens `content` inside a dialog panel and returns a ref you can use to
315
+ * close it and read the result back (`afterClosed`).
208
316
  */
209
- data = {};
210
- /** close dialog on outside click
211
- * - default false */
212
- allowCloseOnOutsideClick = false;
213
- /**
214
- * container class
215
- * - You can separate the list of classes with a space
216
- * - for example:"`my class one two three ...`"
217
- *
218
- * TODO: must set with public config setter
219
- */
220
- containerClass = 'ngx-kit';
221
- header;
222
- footer;
223
- width = '';
224
- minWidth = '';
225
- maxWidth = '';
226
- height = '';
227
- minHeight = '';
228
- maxHeight = '';
229
- /** parent injector */
230
- injector;
231
- constructor() { }
232
- }
233
-
234
- class NgxDialogRef {
235
- dialog;
236
- header;
237
- footer;
238
- body;
239
- _afterClosed = new Subject();
240
- afterClosed = this._afterClosed.asObservable();
241
- id;
242
- close(result) {
243
- this._afterClosed.next(result);
244
- }
245
- }
246
-
247
- class NgxOverlayService {
248
- appRef;
249
- injector;
250
- envInjector;
251
- dialogComponentRefs = [];
252
- _defaultOptions;
253
- constructor(appRef, injector, envInjector) {
254
- this.appRef = appRef;
255
- this.injector = injector;
256
- this.envInjector = envInjector;
257
- }
258
- open(component, config) {
259
- const dialogRef = this._open(component, config);
260
- return dialogRef;
261
- }
262
- _open(component, config) {
263
- config = { ...(this._defaultOptions || new NgxDialogConfig()), ...config };
264
- const map = new WeakMap();
265
- map.set(NgxDialogConfig, config);
317
+ open(content, config) {
318
+ const resolvedConfig = { ...this.defaultConfig, ...config };
266
319
  const dialogRef = new NgxDialogRef();
267
- dialogRef.id = this.getDialogId;
268
- map.set(NgxDialogRef, dialogRef);
269
- const sub = dialogRef.afterClosed.subscribe(() => {
270
- // close the dialog
271
- this.removeDialogComponentFromBody(dialogRef.id);
272
- sub.unsubscribe();
273
- });
274
- // ✅ ساخت Injector اختصاصی با DestroyRef
320
+ dialogRef.beforeClose = resolvedConfig.beforeClose;
275
321
  const componentInjector = Injector.create({
276
322
  providers: [
277
- NgxDialogRef,
278
- { provide: DIALOG_DATA, useValue: config.data },
279
- { provide: DIALOG_REF, useValue: dialogRef, multi: false },
323
+ { provide: DIALOG_DATA, useValue: resolvedConfig.data },
324
+ { provide: DIALOG_REF, useValue: dialogRef },
325
+ { provide: NGX_DIALOG_CONFIG, useValue: resolvedConfig },
326
+ { provide: DIALOG_CONTENT, useValue: content },
280
327
  ],
281
- parent: config?.injector ? config.injector : this.envInjector,
328
+ parent: resolvedConfig.injector ?? this.injector,
282
329
  });
283
- const componentRef = runInInjectionContext(componentInjector, () => createComponent(NgxDialogComponent, {
284
- elementInjector: componentInjector,
285
- environmentInjector: this.envInjector,
286
- }));
287
- this.appRef.attachView(componentRef.hostView);
288
- this.appendDialogComponentToBody(componentRef, config);
289
- componentRef.instance.config = config;
290
- componentRef.instance.component = component;
291
- //componentRef.instance._dialogRef = dialogRef;
292
- this.dialogComponentRefs.push(componentRef);
330
+ const disableClose = resolvedConfig.disableClose ?? false;
331
+ const overlayRef = this.overlay.open({
332
+ component: NgxDialogComponent,
333
+ injector: componentInjector,
334
+ placement: 'center',
335
+ alignment: 'center',
336
+ margin: 0,
337
+ role: resolvedConfig.role ?? 'dialog',
338
+ ariaModal: true,
339
+ ariaLabel: resolvedConfig.ariaLabel,
340
+ ariaLabelledby: resolvedConfig.ariaLabelledby,
341
+ ariaDescribedby: resolvedConfig.ariaDescribedby,
342
+ usePopover: resolvedConfig.usePopover ?? true,
343
+ closeOnEscape: disableClose ? false : (resolvedConfig.closeOnEscape ?? true),
344
+ closeOnOutsideClick: disableClose ? false : (resolvedConfig.closeOnOutsideClick ?? false),
345
+ canClose: () => dialogRef.beforeClose?.() ?? true,
346
+ restoreFocus: resolvedConfig.restoreFocus ?? true,
347
+ autoFocus: resolvedConfig.autoFocus ?? true,
348
+ lockBodyScroll: resolvedConfig.lockBodyScroll ?? true,
349
+ backdropClass: resolvedConfig.backdropClass,
350
+ panelClass: resolvedConfig.panelClass,
351
+ configure: (_instance, ref) => this.applySizing(ref.nativeElement, resolvedConfig),
352
+ onClosed: () => {
353
+ this._openRefs.update((refs) => refs.filter((r) => r !== dialogRef));
354
+ dialogRef._finalizeClose();
355
+ },
356
+ });
357
+ dialogRef._attachOverlayRef(overlayRef);
358
+ this._openRefs.update((refs) => [...refs, dialogRef]);
293
359
  return dialogRef;
294
360
  }
295
- removeDialogComponentFromBody(id) {
296
- if (!id) {
297
- return;
298
- }
299
- const index = this.dialogComponentRefs.findIndex((x) => x.instance._dialogRef.id == id);
300
- if (index > -1 && this.dialogComponentRefs[index]) {
301
- this.appRef.detachView(this.dialogComponentRefs[index].hostView);
302
- this.dialogComponentRefs[index].destroy();
303
- this.dialogComponentRefs.splice(index, 1);
304
- }
305
- }
306
- appendDialogComponentToBody(componentRef, config) {
307
- const domElem = componentRef.hostView.rootNodes[0];
308
- if (config.containerClass) {
309
- for (let c of config.containerClass.split(' ')) {
310
- if (c.trim())
311
- domElem.classList.add(c);
312
- }
313
- }
314
- document.body.appendChild(domElem);
315
- }
361
+ /** Closes every currently open dialog (ignores `disableClose`/guards - use sparingly, e.g. on logout). */
316
362
  closeAll() {
317
- for (let index = 0; index < this.dialogComponentRefs.length; index++) {
318
- if (this.dialogComponentRefs[index]) {
319
- this.appRef.detachView(this.dialogComponentRefs[index].hostView);
320
- this.dialogComponentRefs[index].destroy();
321
- }
322
- }
323
- this.dialogComponentRefs = [];
363
+ [...this._openRefs()].forEach((ref) => ref.close());
324
364
  }
325
- get getDialogId() {
326
- return randomStrnig(10, true);
365
+ applySizing(el, config) {
366
+ if (!el)
367
+ return;
368
+ if (config.width)
369
+ el.style.width = config.width;
370
+ if (config.minWidth)
371
+ el.style.minWidth = config.minWidth;
372
+ if (config.maxWidth)
373
+ el.style.maxWidth = config.maxWidth;
374
+ if (config.height)
375
+ el.style.height = config.height;
376
+ if (config.minHeight)
377
+ el.style.minHeight = config.minHeight;
378
+ if (config.maxHeight)
379
+ el.style.maxHeight = config.maxHeight;
327
380
  }
328
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxOverlayService, deps: [{ token: i0.ApplicationRef }, { token: i0.Injector }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable });
329
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxOverlayService });
381
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
382
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogService, providedIn: 'root' });
330
383
  }
331
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxOverlayService, decorators: [{
332
- type: Injectable
333
- }], ctorParameters: () => [{ type: i0.ApplicationRef }, { type: i0.Injector }, { type: i0.EnvironmentInjector }] });
384
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogService, decorators: [{
385
+ type: Injectable,
386
+ args: [{ providedIn: 'root' }]
387
+ }] });
334
388
 
389
+ const NOT_INITIALIZED_MESSAGE = '[ngx-kit/dialog] Dialog.* was called before provideNgxDialog() ran. ' +
390
+ 'Add provideNgxDialog() to your app providers, or inject NgxDialogService directly instead of using the static Dialog API.';
391
+ /**
392
+ * Static convenience API over `NgxDialogService`, so you can call
393
+ * `Dialog.open(...)` from anywhere without injecting the service manually.
394
+ *
395
+ * SSR note: the instance backing this static class is process-wide, not
396
+ * per-request, so it is deliberately left unset on the server (see
397
+ * `provideNgxDialog()`). Inject `NgxDialogService` directly in SSR code paths.
398
+ */
335
399
  class Dialog {
336
400
  static serviceInstance = null;
401
+ /** @internal set by `provideNgxDialog()`'s environment initializer. */
337
402
  static _setService(svc) {
338
403
  this.serviceInstance = svc;
339
404
  }
340
- static open(component, config) {
405
+ static get service() {
341
406
  if (!this.serviceInstance) {
342
- throw Error('ngx-dialog: service not initialized. Ensure NgxDialogModule is imported.');
407
+ throw new Error(NOT_INITIALIZED_MESSAGE);
343
408
  }
344
- return this.serviceInstance.open(component, config);
409
+ return this.serviceInstance;
410
+ }
411
+ static open(component, config) {
412
+ return this.service.open(component, config);
413
+ }
414
+ static closeAll() {
415
+ this.service.closeAll();
345
416
  }
346
417
  }
347
418
 
348
- class NgxDialogModule {
349
- platformId = inject(PLATFORM_ID);
350
- constructor(parentModule, service) {
351
- if (parentModule) {
352
- return;
353
- }
354
- // API استاتیک Dialog.open(...) روی یک static field کلاسی پیاده شده تا
355
- // بدون تزریق دستی سرویس هم قابل استفاده باشه. این static field برای کل
356
- // پروسه‌ی Node.js مشترکه، نه به‌ازای هر درخواست — پس در Angular SSR،
357
- // چند درخواست هم‌زمان می‌تونستن instance همدیگه رو overwrite کنن و
358
- // دیالوگ یک کاربر با ApplicationRef اشتباه (کاربر دیگه) کار کنه.
359
- // به‌جای این‌که این باگ به‌صورت خاموش رخ بده، روی سرور اصلاً static
360
- // instance رو ست نمی‌کنیم؛ Dialog.open() روی سرور با همون خطای
361
- // «service not initialized» که از قبل وجود داشت fail می‌کنه (fail-loud
362
- // به‌جای corrupt خاموش). برای SSR باید NgxOverlayService رو مستقیم
363
- // inject کرد (که per-request/per-injector امنه)، نه از API استاتیک
364
- // استفاده کرد. رفتار کلاینت (که ۹۹٪ کاربردهاست) کاملاً بدون تغییره.
365
- if (isPlatformServer(this.platformId)) {
366
- return;
419
+ function provideNgxDialog(config) {
420
+ return makeEnvironmentProviders([
421
+ {
422
+ provide: NGX_DIALOG_CONFIG,
423
+ useValue: { ...NGX_DIALOG_DEFAULT_CONFIG, ...(config || {}) },
424
+ },
425
+ NgxDialogService,
426
+ provideEnvironmentInitializer(() => {
427
+ if (isPlatformServer(inject(PLATFORM_ID))) {
428
+ return;
429
+ }
430
+ Dialog._setService(inject(NgxDialogService));
431
+ }),
432
+ ]);
433
+ }
434
+
435
+ /**
436
+ * Why this can't be pure CSS flexbox: the header/body/footer elements are
437
+ * *grandchildren* of the dialog panel (panel -> `*ngComponentOutlet`'s host
438
+ * element -> header/body/footer), not direct children, because the content
439
+ * component that hosts them is arbitrary and we don't control its own host
440
+ * styling. `display:flex;flex-direction:column` on the panel therefore can't
441
+ * size the body against the header/footer through that extra layer, so we
442
+ * measure and set an explicit `max-height` instead, driven by a
443
+ * `ResizeObserver` on the panel (not a `window:resize` listener, so it also
444
+ * reacts to the dialog itself changing size, e.g. via `config.size`).
445
+ */
446
+ class NgxDialogBody {
447
+ el = inject((ElementRef));
448
+ renderer = inject(Renderer2);
449
+ dialogRef = inject(DIALOG_REF);
450
+ destroyRef = inject(DestroyRef);
451
+ constructor() {
452
+ this.dialogRef._setBodyElement(this.el.nativeElement);
453
+ this.destroyRef.onDestroy(() => this.dialogRef._setBodyElement(null));
454
+ effect((onCleanup) => {
455
+ const panel = this.dialogRef.panelEl();
456
+ if (!panel || typeof ResizeObserver === 'undefined') {
457
+ return;
458
+ }
459
+ const recompute = () => this.recomputeHeight(panel);
460
+ const observer = new ResizeObserver(recompute);
461
+ observer.observe(panel);
462
+ recompute();
463
+ onCleanup(() => observer.disconnect());
464
+ });
465
+ }
466
+ recomputeHeight(panel) {
467
+ const headerHeight = this.dialogRef.headerEl()?.offsetHeight ?? 0;
468
+ const footerHeight = this.dialogRef.footerEl()?.offsetHeight ?? 0;
469
+ const panelHeight = Math.min(panel.clientHeight, window.innerHeight);
470
+ const available = panelHeight - headerHeight - footerHeight;
471
+ console.log('available', available);
472
+ if (available > 0) {
473
+ this.renderer.setStyle(this.el.nativeElement, 'max-height', `${available}px`);
367
474
  }
368
- Dialog._setService(service);
369
475
  }
370
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogModule, deps: [{ token: NgxDialogModule, optional: true, skipSelf: true }, { token: NgxOverlayService }], target: i0.ɵɵFactoryTarget.NgModule });
371
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogModule, declarations: [NgxDialogComponent,
372
- NgxDialogHeaderDirective,
373
- NgxDialogFooterDirective,
374
- NgxDialogBodyDirective], imports: [CommonModule], exports: [NgxDialogComponent,
375
- NgxDialogHeaderDirective,
376
- NgxDialogFooterDirective,
377
- NgxDialogBodyDirective] });
378
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogModule, providers: [NgxOverlayService], imports: [CommonModule] });
476
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogBody, deps: [], target: i0.ɵɵFactoryTarget.Directive });
477
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.4", type: NgxDialogBody, isStandalone: true, selector: "ngx-dialog-body,[ngxDialogBody]", host: { classAttribute: "dialog-body" }, exportAs: ["ngxDialogBody"], ngImport: i0 });
478
+ }
479
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogBody, decorators: [{
480
+ type: Directive,
481
+ args: [{
482
+ selector: 'ngx-dialog-body,[ngxDialogBody]',
483
+ standalone: true,
484
+ host: { class: 'dialog-body' },
485
+ exportAs: 'ngxDialogBody',
486
+ }]
487
+ }], ctorParameters: () => [] });
488
+
489
+ class NgxDialogModule {
490
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
491
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogModule, imports: [NgxDialogComponent, NgxDialogHeader, NgxDialogFooter, NgxDialogBody], exports: [NgxDialogComponent, NgxDialogHeader, NgxDialogFooter, NgxDialogBody] });
492
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogModule });
379
493
  }
380
494
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDialogModule, decorators: [{
381
495
  type: NgModule,
382
496
  args: [{
383
- declarations: [
384
- NgxDialogComponent,
385
- NgxDialogHeaderDirective,
386
- NgxDialogFooterDirective,
387
- NgxDialogBodyDirective,
388
- ],
389
- imports: [CommonModule],
390
- exports: [
391
- NgxDialogComponent,
392
- NgxDialogHeaderDirective,
393
- NgxDialogFooterDirective,
394
- NgxDialogBodyDirective,
395
- ],
396
- providers: [NgxOverlayService],
497
+ declarations: [],
498
+ imports: [NgxDialogComponent, NgxDialogHeader, NgxDialogFooter, NgxDialogBody],
499
+ exports: [NgxDialogComponent, NgxDialogHeader, NgxDialogFooter, NgxDialogBody],
397
500
  }]
398
- }], ctorParameters: () => [{ type: NgxDialogModule, decorators: [{
399
- type: Optional
400
- }, {
401
- type: SkipSelf
402
- }] }, { type: NgxOverlayService }] });
501
+ }] });
403
502
 
404
503
  /**
405
504
  * Generated bundle index. Do not edit.
406
505
  */
407
506
 
408
- export { DIALOG_DATA, DIALOG_REF, Dialog, NgxDialogBodyDirective, NgxDialogComponent, NgxDialogConfig, NgxDialogFooterDirective, NgxDialogHeaderDirective, NgxDialogModule };
507
+ export { DIALOG_CONTENT, DIALOG_DATA, DIALOG_REF, Dialog, NGX_DIALOG_CONFIG, NGX_DIALOG_DEFAULT_CONFIG, NgxDialogBody, NgxDialogComponent, NgxDialogConfig, NgxDialogFooter, NgxDialogHeader, NgxDialogModule, NgxDialogService, provideNgxDialog };
409
508
  //# sourceMappingURL=ngx-kit-dialog.mjs.map