codexly-ui 0.0.77 → 0.0.78

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,16 +1,13 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, computed, ChangeDetectionStrategy, ViewEncapsulation, Component, effect, signal, inject, ElementRef, InjectionToken, PLATFORM_ID, Injectable, Renderer2, ApplicationRef, EnvironmentInjector, DestroyRef, createComponent, Directive, output, contentChildren, NgZone, model, untracked, forwardRef, viewChild, HostListener, ViewChildren, contentChild, Injector, ViewChild, ChangeDetectorRef, ContentChildren, Input, numberAttribute, booleanAttribute, runInInjectionContext } from '@angular/core';
2
+ import { input, computed, ChangeDetectionStrategy, ViewEncapsulation, Component, effect, signal, inject, ElementRef, InjectionToken, PLATFORM_ID, Injectable, Renderer2, ApplicationRef, EnvironmentInjector, DestroyRef, createComponent, Directive, output, contentChildren, NgZone, model, untracked, forwardRef, viewChild, HostListener, ViewChildren, contentChild, Injector, ViewChild, ChangeDetectorRef, ContentChildren, Input, numberAttribute, booleanAttribute } from '@angular/core';
3
3
  import { isPlatformBrowser, CurrencyPipe, NgTemplateOutlet, DecimalPipe, NgStyle, DOCUMENT } from '@angular/common';
4
4
  import * as i1 from '@angular/forms';
5
5
  import { NG_VALUE_ACCESSOR, FormsModule, NgControl, FormControl, ReactiveFormsModule, FormGroup, Validators } from '@angular/forms';
6
6
  import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
7
7
  import { startWith, map, debounceTime, distinctUntilChanged, switchMap, of, catchError } from 'rxjs';
8
8
  import * as i1$1 from '@angular/cdk/overlay';
9
- import { ScrollStrategyOptions, OverlayModule, Overlay, OverlayConfig, OverlayContainer } from '@angular/cdk/overlay';
9
+ import { ScrollStrategyOptions, OverlayModule } from '@angular/cdk/overlay';
10
10
  import { Chart, LineController, BarController, PieController, DoughnutController, RadarController, PolarAreaController, CategoryScale, LinearScale, RadialLinearScale, BarElement, LineElement, PointElement, ArcElement, Filler, Tooltip, Legend } from 'chart.js';
11
- import * as i1$2 from '@angular/cdk/portal';
12
- import { PortalModule, ComponentPortal } from '@angular/cdk/portal';
13
- import { FocusTrapFactory } from '@angular/cdk/a11y';
14
11
  import { CdkScrollable } from '@angular/cdk/scrolling';
15
12
  import { RouterLink, RouterLinkActive } from '@angular/router';
16
13
 
@@ -8906,122 +8903,100 @@ const EDITOR_SIZE_MAP = {
8906
8903
  };
8907
8904
 
8908
8905
  /**
8909
- * Internal shell componentmounted via ComponentPortal onto the CDK overlay.
8910
- * Renders the user's component via a second ComponentPortal inside cdkPortalOutlet.
8911
- * Owns the enter / exit animation so every modal gets consistent motion.
8906
+ * Minimal overlay engineno CDK, no stacking context wars.
8907
+ * Creates a fixed container div in document.body with explicit z-index.
8912
8908
  */
8913
- class ClxModalWrapperComponent {
8914
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
8915
- portal = model(null, ...(ngDevMode ? [{ debugName: "portal" }] : /* istanbul ignore next */ []));
8916
- _animate = inject(ClxAnimateService);
8917
- _el = inject((ElementRef));
8918
- _animConfig = inject(CLX_MODAL_ANIM_CONFIG, { optional: true })
8919
- ?? MODAL_ANIM_DEFAULTS;
8920
- /** Resolved by ClxModalService so closeWithAnimation can call through */
8921
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
8922
- onClose;
8923
- ngOnInit() {
8924
- const target = this._panel();
8925
- if (target) {
8926
- this._animate.animate(target, {
8927
- animation: this._animConfig.animationIn,
8928
- duration: this._animConfig.animationDuration,
8929
- trigger: 'manual',
8930
- });
8931
- }
8909
+ class ClxNativeOverlayService {
8910
+ _appRef = inject(ApplicationRef);
8911
+ _injector = inject(Injector);
8912
+ /** Block body scroll like CDK used to */
8913
+ _scrollBlocked = 0;
8914
+ mount(component, injector, options) {
8915
+ // ── backdrop ────────────────────────────────────────────────────────────
8916
+ let backdropEl = null;
8917
+ if (options.backdrop) {
8918
+ backdropEl = document.createElement('div');
8919
+ backdropEl.style.cssText =
8920
+ `position:fixed;inset:0;z-index:${options.zIndex};`;
8921
+ if (options.backdropClass)
8922
+ backdropEl.className = options.backdropClass;
8923
+ document.body.appendChild(backdropEl);
8924
+ }
8925
+ // ── container ────────────────────────────────────────────────────────────
8926
+ const container = document.createElement('div');
8927
+ container.style.cssText =
8928
+ `position:fixed;inset:0;z-index:${options.zIndex + 1};pointer-events:none;display:flex;align-items:center;justify-content:center;padding:1rem;box-sizing:border-box;`;
8929
+ if (options.containerStyle) {
8930
+ Object.assign(container.style, options.containerStyle);
8931
+ }
8932
+ document.body.appendChild(container);
8933
+ // ── component ────────────────────────────────────────────────────────────
8934
+ const compRef = createComponent(component, {
8935
+ environmentInjector: this._appRef.injector,
8936
+ elementInjector: injector,
8937
+ });
8938
+ this._appRef.attachView(compRef.hostView);
8939
+ const el = compRef.location.nativeElement;
8940
+ el.style.pointerEvents = 'auto';
8941
+ container.appendChild(el);
8942
+ // ── scroll block ─────────────────────────────────────────────────────────
8943
+ this._blockScroll();
8944
+ const overlayRef = {
8945
+ backdrop: backdropEl,
8946
+ container,
8947
+ destroy: () => {
8948
+ compRef.destroy();
8949
+ backdropEl?.remove();
8950
+ container.remove();
8951
+ this._unblockScroll();
8952
+ },
8953
+ };
8954
+ return { compRef, overlayRef };
8932
8955
  }
8933
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
8934
- closeWithAnimation(result) {
8935
- const target = this._panel();
8936
- if (!target) {
8937
- this.onClose?.(result);
8938
- return;
8956
+ _blockScroll() {
8957
+ this._scrollBlocked++;
8958
+ if (this._scrollBlocked === 1) {
8959
+ document.body.style.overflow = 'hidden';
8939
8960
  }
8940
- this._animate
8941
- .animate(target, {
8942
- animation: this._animConfig.animationOut,
8943
- duration: this._animConfig.animationDuration,
8944
- trigger: 'manual',
8945
- fillMode: 'forwards',
8946
- })
8947
- .then(() => this.onClose?.(result));
8948
8961
  }
8949
- /**
8950
- * Returns the first real element child of this wrapper — which is the
8951
- * rendered panel (clx-modal host) inserted by cdkPortalOutlet.
8952
- * The wrapper itself is display:contents so the panel is its direct child.
8953
- */
8954
- _panel() {
8955
- return this._el.nativeElement.firstElementChild;
8962
+ _unblockScroll() {
8963
+ this._scrollBlocked = Math.max(0, this._scrollBlocked - 1);
8964
+ if (this._scrollBlocked === 0) {
8965
+ document.body.style.overflow = '';
8966
+ }
8956
8967
  }
8957
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxModalWrapperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8958
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.15", type: ClxModalWrapperComponent, isStandalone: true, selector: "clx-modal-wrapper", inputs: { portal: { classPropertyName: "portal", publicName: "portal", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { portal: "portalChange" }, host: { styleAttribute: "display:contents" }, ngImport: i0, template: `<ng-container [cdkPortalOutlet]="portal()" />`, isInline: true, dependencies: [{ kind: "ngmodule", type: PortalModule }, { kind: "directive", type: i1$2.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
8968
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxNativeOverlayService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
8969
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxNativeOverlayService, providedIn: 'root' });
8959
8970
  }
8960
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxModalWrapperComponent, decorators: [{
8961
- type: Component,
8962
- args: [{
8963
- selector: 'clx-modal-wrapper',
8964
- standalone: true,
8965
- imports: [PortalModule],
8966
- template: `<ng-container [cdkPortalOutlet]="portal()" />`,
8967
- encapsulation: ViewEncapsulation.None,
8968
- changeDetection: ChangeDetectionStrategy.OnPush,
8969
- host: { style: 'display:contents' },
8970
- }]
8971
- }], propDecorators: { portal: [{ type: i0.Input, args: [{ isSignal: true, alias: "portal", required: false }] }, { type: i0.Output, args: ["portalChange"] }] } });
8971
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxNativeOverlayService, decorators: [{
8972
+ type: Injectable,
8973
+ args: [{ providedIn: 'root' }]
8974
+ }] });
8972
8975
 
8976
+ const SIZE_MAX_WIDTH = {
8977
+ sm: '480px',
8978
+ md: '680px',
8979
+ lg: '900px',
8980
+ xl: '1200px',
8981
+ full: '100vw',
8982
+ };
8973
8983
  class ClxModalService {
8974
- _overlay;
8975
- _injector;
8976
- _focusTrapFactory;
8977
- constructor() {
8978
- this._overlay = inject(Overlay);
8979
- this._injector = inject(Injector);
8980
- this._focusTrapFactory = inject(FocusTrapFactory);
8981
- }
8984
+ _overlay = inject(ClxNativeOverlayService);
8985
+ _animate = inject(ClxAnimateService);
8986
+ _injector = inject(Injector);
8982
8987
  open(
8983
8988
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
8984
8989
  component, config = {}) {
8985
- const { hasBackdrop = true, disableClose = false, panelClass = [], size = 'md', data, animationIn = MODAL_ANIM_DEFAULTS.animationIn, animationOut = MODAL_ANIM_DEFAULTS.animationOut, animationDuration = MODAL_ANIM_DEFAULTS.animationDuration, } = config;
8990
+ const { hasBackdrop = true, disableClose = false, size = 'md', data, animationIn = MODAL_ANIM_DEFAULTS.animationIn, animationOut = MODAL_ANIM_DEFAULTS.animationOut, animationDuration = MODAL_ANIM_DEFAULTS.animationDuration, } = config;
8986
8991
  const animConfig = { animationIn, animationOut, animationDuration };
8992
+ const maxWidth = SIZE_MAX_WIDTH[size] ?? '680px';
8987
8993
  let _resolve;
8988
8994
  const _afterClosed = new Promise(res => (_resolve = res));
8989
- let _focusTrap = null;
8990
8995
  let _closing = false;
8991
- /** Plays exit animation then tears down the overlay. */
8992
- const closeViaAnimation = (result) => {
8993
- if (_closing)
8994
- return;
8995
- _closing = true;
8996
- wrapperRef.instance.closeWithAnimation(result);
8997
- };
8998
8996
  const modalRef = {
8999
8997
  close(result) { closeViaAnimation(result); },
9000
8998
  afterClosed() { return _afterClosed; },
9001
8999
  };
9002
- const extraClasses = Array.isArray(panelClass) ? panelClass : [panelClass];
9003
- const sizeMaxWidth = {
9004
- sm: '480px',
9005
- md: '680px',
9006
- lg: '900px',
9007
- xl: '1200px',
9008
- full: '100vw',
9009
- };
9010
- const maxWidth = sizeMaxWidth[size] ?? '600px';
9011
- const overlayRef = this._overlay.create(new OverlayConfig({
9012
- hasBackdrop,
9013
- backdropClass: 'clx-modal-backdrop',
9014
- panelClass: extraClasses,
9015
- scrollStrategy: this._overlay.scrollStrategies.block(),
9016
- positionStrategy: this._overlay.position().global().centerHorizontally().centerVertically(),
9017
- width: `min(calc(100vw - 2rem), ${maxWidth})`,
9018
- maxWidth: maxWidth,
9019
- maxHeight: '90vh',
9020
- }));
9021
- Object.assign(overlayRef.overlayElement.style, {
9022
- display: 'flex',
9023
- flexDirection: 'column',
9024
- });
9025
9000
  const innerInjector = Injector.create({
9026
9001
  parent: this._injector,
9027
9002
  providers: [
@@ -9031,27 +9006,49 @@ class ClxModalService {
9031
9006
  { provide: CLX_MODAL_SIZE, useValue: size },
9032
9007
  ],
9033
9008
  });
9034
- // Attach wrapper CDK creates the backdrop on attach()
9035
- const wrapperPortal = new ComponentPortal(ClxModalWrapperComponent, null, innerInjector);
9036
- const wrapperRef = overlayRef.attach(wrapperPortal);
9037
- // Wire the actual teardown through the wrapper instance
9038
- wrapperRef.instance.onClose = (result) => {
9039
- _focusTrap?.destroy();
9040
- overlayRef.dispose();
9041
- _resolve(result);
9009
+ const { compRef, overlayRef } = this._overlay.mount(component, innerInjector, {
9010
+ zIndex: 1000,
9011
+ backdrop: hasBackdrop,
9012
+ backdropClass: 'clx-modal-backdrop',
9013
+ });
9014
+ const panelEl = compRef.location.nativeElement;
9015
+ panelEl.style.width = `min(calc(100vw - 2rem), ${maxWidth})`;
9016
+ panelEl.style.maxWidth = maxWidth;
9017
+ panelEl.style.maxHeight = '90vh';
9018
+ // Enter animation
9019
+ this._animate.animate(panelEl, {
9020
+ animation: animationIn,
9021
+ duration: animationDuration,
9022
+ trigger: 'manual',
9023
+ });
9024
+ const closeViaAnimation = (result) => {
9025
+ if (_closing)
9026
+ return;
9027
+ _closing = true;
9028
+ this._animate.animate(panelEl, {
9029
+ animation: animationOut,
9030
+ duration: animationDuration,
9031
+ trigger: 'manual',
9032
+ fillMode: 'forwards',
9033
+ }).then(() => {
9034
+ overlayRef.destroy();
9035
+ _resolve(result);
9036
+ });
9042
9037
  };
9043
- // Mount user component inside the wrapper via a second portal
9044
- const contentPortal = new ComponentPortal(component, null, innerInjector);
9045
- wrapperRef.instance.portal.set(contentPortal);
9046
- if (hasBackdrop && !disableClose) {
9047
- overlayRef.backdropClick().subscribe(() => closeViaAnimation());
9038
+ // Backdrop click
9039
+ if (hasBackdrop && !disableClose && overlayRef.backdrop) {
9040
+ overlayRef.backdrop.addEventListener('click', () => closeViaAnimation());
9048
9041
  }
9042
+ // Escape key
9049
9043
  if (!disableClose) {
9050
- overlayRef.keydownEvents().subscribe(e => { if (e.key === 'Escape')
9051
- closeViaAnimation(); });
9044
+ const onKey = (e) => {
9045
+ if (e.key === 'Escape') {
9046
+ closeViaAnimation();
9047
+ document.removeEventListener('keydown', onKey);
9048
+ }
9049
+ };
9050
+ document.addEventListener('keydown', onKey);
9052
9051
  }
9053
- _focusTrap = this._focusTrapFactory.create(overlayRef.overlayElement);
9054
- _focusTrap.focusInitialElementWhenReady();
9055
9052
  return modalRef;
9056
9053
  }
9057
9054
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxModalService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
@@ -9060,7 +9057,7 @@ class ClxModalService {
9060
9057
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxModalService, decorators: [{
9061
9058
  type: Injectable,
9062
9059
  args: [{ providedIn: 'root' }]
9063
- }], ctorParameters: () => [] });
9060
+ }] });
9064
9061
 
9065
9062
  let _clxEditorId = 0;
9066
9063
  const TOOLBAR_GROUPS = [
@@ -13795,45 +13792,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13795
13792
  }] } });
13796
13793
 
13797
13794
  class ClxAlertService {
13798
- _overlay;
13799
- _injector;
13800
- _focusTrapFactory;
13801
- constructor() {
13802
- this._overlay = inject(Overlay);
13803
- this._injector = inject(Injector);
13804
- this._focusTrapFactory = inject(FocusTrapFactory);
13805
- }
13806
- // ─── Core open ────────────────────────────────────────────────────────────
13795
+ _overlay = inject(ClxNativeOverlayService);
13796
+ _injector = inject(Injector);
13807
13797
  open(options = {}) {
13808
13798
  const backdrop = options.backdrop ?? ALERT_DEFAULTS.backdrop;
13809
13799
  const disableClose = options.disableClose ?? ALERT_DEFAULTS.disableClose;
13810
13800
  let _resolve;
13811
13801
  const promise = new Promise(res => (_resolve = res));
13812
- let _focusTrap = null;
13813
- // Wrap resolve so we can dispose the overlay after the exit animation
13814
13802
  const resolve = (result) => {
13815
- _focusTrap?.destroy();
13816
- overlayRef.dispose();
13803
+ overlayRef.destroy();
13817
13804
  _resolve(result);
13818
13805
  };
13819
- const overlayRef = this._overlay.create(new OverlayConfig({
13820
- hasBackdrop: backdrop,
13821
- backdropClass: 'clx-alert-backdrop',
13822
- scrollStrategy: this._overlay.scrollStrategies.block(),
13823
- positionStrategy: this._overlay.position().global().centerHorizontally().centerVertically(),
13824
- }));
13825
- // Make the overlay pane a flex centering layer
13826
- Object.assign(overlayRef.overlayElement.style, {
13827
- position: 'fixed',
13828
- inset: '0',
13829
- width: '100vw',
13830
- height: '100vh',
13831
- display: 'flex',
13832
- alignItems: 'center',
13833
- justifyContent: 'center',
13834
- padding: '1rem',
13835
- boxSizing: 'border-box',
13836
- });
13837
13806
  const innerInjector = Injector.create({
13838
13807
  parent: this._injector,
13839
13808
  providers: [
@@ -13841,19 +13810,25 @@ class ClxAlertService {
13841
13810
  { provide: CLX_ALERT_RESOLVE, useValue: resolve },
13842
13811
  ],
13843
13812
  });
13844
- overlayRef.attach(new ComponentPortal(ClxAlertComponent, null, innerInjector));
13845
- if (backdrop && !disableClose) {
13846
- overlayRef.backdropClick().subscribe(() => resolve(false));
13813
+ const { overlayRef } = this._overlay.mount(ClxAlertComponent, innerInjector, {
13814
+ zIndex: 1000,
13815
+ backdrop,
13816
+ backdropClass: 'clx-alert-backdrop',
13817
+ });
13818
+ if (backdrop && !disableClose && overlayRef.backdrop) {
13819
+ overlayRef.backdrop.addEventListener('click', () => resolve(false));
13847
13820
  }
13848
13821
  if (!disableClose) {
13849
- overlayRef.keydownEvents().subscribe(e => { if (e.key === 'Escape')
13850
- resolve(false); });
13822
+ const onKey = (e) => {
13823
+ if (e.key === 'Escape') {
13824
+ resolve(false);
13825
+ document.removeEventListener('keydown', onKey);
13826
+ }
13827
+ };
13828
+ document.addEventListener('keydown', onKey);
13851
13829
  }
13852
- _focusTrap = this._focusTrapFactory.create(overlayRef.overlayElement);
13853
- _focusTrap.focusInitialElementWhenReady();
13854
13830
  return promise;
13855
13831
  }
13856
- // ─── Convenience shortcuts ────────────────────────────────────────────────
13857
13832
  success(title, message, opts = {}) {
13858
13833
  return this.open({ type: 'success', title, message, ...opts });
13859
13834
  }
@@ -13867,13 +13842,7 @@ class ClxAlertService {
13867
13842
  return this.open({ type: 'info', title, message, ...opts });
13868
13843
  }
13869
13844
  confirm(title, message, opts = {}) {
13870
- return this.open({
13871
- type: 'confirm',
13872
- title,
13873
- message,
13874
- showCancelButton: true,
13875
- ...opts,
13876
- });
13845
+ return this.open({ type: 'confirm', title, message, showCancelButton: true, ...opts });
13877
13846
  }
13878
13847
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxAlertService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
13879
13848
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxAlertService, providedIn: 'root' });
@@ -13881,42 +13850,23 @@ class ClxAlertService {
13881
13850
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxAlertService, decorators: [{
13882
13851
  type: Injectable,
13883
13852
  args: [{ providedIn: 'root' }]
13884
- }], ctorParameters: () => [] });
13853
+ }] });
13885
13854
 
13886
13855
  class ClxDrawerService {
13887
- _overlay;
13888
- _injector;
13889
- _focusTrapFactory;
13890
- constructor() {
13891
- this._overlay = inject(Overlay);
13892
- this._injector = inject(Injector);
13893
- this._focusTrapFactory = inject(FocusTrapFactory);
13894
- }
13856
+ _overlay = inject(ClxNativeOverlayService);
13857
+ _animate = inject(ClxAnimateService);
13858
+ _injector = inject(Injector);
13895
13859
  open(
13896
13860
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
13897
13861
  component, config = {}) {
13898
- const { hasBackdrop = false, disableClose = false, panelClass = [], size = 'md', data, } = config;
13862
+ const { hasBackdrop = false, disableClose = false, size = 'md', data, } = config;
13899
13863
  let _resolve;
13900
13864
  const _afterClosed = new Promise(res => (_resolve = res));
13901
- let _focusTrap = null;
13865
+ let _closing = false;
13902
13866
  const drawerRef = {
13903
- close(result) {
13904
- _focusTrap?.destroy();
13905
- overlayRef.dispose();
13906
- _resolve(result);
13907
- },
13908
- afterClosed() {
13909
- return _afterClosed;
13910
- },
13867
+ close(result) { closeViaAnimation(result); },
13868
+ afterClosed() { return _afterClosed; },
13911
13869
  };
13912
- const extraClasses = Array.isArray(panelClass) ? panelClass : [panelClass];
13913
- const overlayRef = this._overlay.create(new OverlayConfig({
13914
- hasBackdrop,
13915
- backdropClass: 'clx-modal-backdrop',
13916
- panelClass: extraClasses,
13917
- scrollStrategy: this._overlay.scrollStrategies.block(),
13918
- positionStrategy: this._overlay.position().global().right('0').top('0'),
13919
- }));
13920
13870
  const innerInjector = Injector.create({
13921
13871
  parent: this._injector,
13922
13872
  providers: [
@@ -13925,26 +13875,51 @@ class ClxDrawerService {
13925
13875
  { provide: CLX_DRAWER_SIZE, useValue: size },
13926
13876
  ],
13927
13877
  });
13928
- // Attach wrapper via ComponentPortal CDK creates backdrop on attach()
13929
- const wrapperPortal = new ComponentPortal(ClxModalWrapperComponent, null, innerInjector);
13930
- const wrapperRef = overlayRef.attach(wrapperPortal);
13931
- // El pane ya tiene width/height del OverlayConfig.
13932
- // Solo desactivamos pointer-events en el overlay element (no en el pane)
13933
- // para que el click-through funcione cuando no hay backdrop.
13934
- overlayRef.overlayElement.style.pointerEvents = 'none';
13935
- wrapperRef.location.nativeElement.style.pointerEvents = 'auto';
13936
- // Mount user component inside the wrapper via a second portal
13937
- const contentPortal = new ComponentPortal(component, null, innerInjector);
13938
- wrapperRef.instance.portal.set(contentPortal);
13939
- if (hasBackdrop && !disableClose) {
13940
- overlayRef.backdropClick().subscribe(() => drawerRef.close());
13878
+ const { compRef, overlayRef } = this._overlay.mount(component, innerInjector, {
13879
+ zIndex: 1000,
13880
+ backdrop: hasBackdrop,
13881
+ backdropClass: 'clx-modal-backdrop',
13882
+ containerStyle: {
13883
+ alignItems: 'flex-start',
13884
+ justifyContent: 'flex-end',
13885
+ padding: '0',
13886
+ },
13887
+ });
13888
+ const panelEl = compRef.location.nativeElement;
13889
+ panelEl.style.height = '100vh';
13890
+ panelEl.style.pointerEvents = 'auto';
13891
+ // Slide in from right
13892
+ this._animate.animate(panelEl, {
13893
+ animation: 'fadeInRight',
13894
+ duration: 300,
13895
+ trigger: 'manual',
13896
+ });
13897
+ const closeViaAnimation = (result) => {
13898
+ if (_closing)
13899
+ return;
13900
+ _closing = true;
13901
+ this._animate.animate(panelEl, {
13902
+ animation: 'fadeOutRight',
13903
+ duration: 300,
13904
+ trigger: 'manual',
13905
+ fillMode: 'forwards',
13906
+ }).then(() => {
13907
+ overlayRef.destroy();
13908
+ _resolve(result);
13909
+ });
13910
+ };
13911
+ if (hasBackdrop && !disableClose && overlayRef.backdrop) {
13912
+ overlayRef.backdrop.addEventListener('click', () => closeViaAnimation());
13941
13913
  }
13942
13914
  if (!disableClose) {
13943
- overlayRef.keydownEvents().subscribe(e => { if (e.key === 'Escape')
13944
- drawerRef.close(); });
13915
+ const onKey = (e) => {
13916
+ if (e.key === 'Escape') {
13917
+ closeViaAnimation();
13918
+ document.removeEventListener('keydown', onKey);
13919
+ }
13920
+ };
13921
+ document.addEventListener('keydown', onKey);
13945
13922
  }
13946
- _focusTrap = this._focusTrapFactory.create(overlayRef.overlayElement);
13947
- _focusTrap.focusInitialElementWhenReady();
13948
13923
  return drawerRef;
13949
13924
  }
13950
13925
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxDrawerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
@@ -13953,47 +13928,16 @@ class ClxDrawerService {
13953
13928
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxDrawerService, decorators: [{
13954
13929
  type: Injectable,
13955
13930
  args: [{ providedIn: 'root' }]
13956
- }], ctorParameters: () => [] });
13931
+ }] });
13957
13932
 
13958
- /** Dedicated OverlayContainer for toasts — lives in its own div above all modals */
13959
- class ToastOverlayContainer extends OverlayContainer {
13960
- _createContainer() {
13961
- const el = document.createElement('div');
13962
- el.classList.add('clx-toast-overlay-container');
13963
- el.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:0;z-index:99999;pointer-events:none;';
13964
- document.body.appendChild(el);
13965
- this._containerElement = el;
13966
- }
13967
- }
13968
13933
  class ClxToastService {
13934
+ _appRef = inject(ApplicationRef);
13969
13935
  _injector = inject(Injector);
13970
- _toastOverlay = null;
13936
+ // Each position has its own container div at z-index 9000 (above modals)
13971
13937
  _containers = new Map();
13972
- _getOverlay() {
13973
- if (this._toastOverlay)
13974
- return this._toastOverlay;
13975
- const childInjector = Injector.create({
13976
- parent: this._injector,
13977
- providers: [
13978
- {
13979
- provide: OverlayContainer,
13980
- useFactory: () => runInInjectionContext(this._injector, () => new ToastOverlayContainer()),
13981
- },
13982
- { provide: Overlay },
13983
- ],
13984
- });
13985
- this._toastOverlay = childInjector.get(Overlay);
13986
- return this._toastOverlay;
13987
- }
13988
- // ─── Core show ─────────────────────────────────────────────────────────────
13989
13938
  show(options) {
13990
13939
  const position = options.position ?? TOAST_DEFAULTS.position;
13991
13940
  const container = this._getOrCreateContainer(position);
13992
- // Move our dedicated overlay container to the end of body on every show
13993
- // so it always appears after any modal cdk-overlay-container
13994
- const el = container.overlayRef.overlayElement.closest('.clx-toast-overlay-container');
13995
- if (el)
13996
- document.body.appendChild(el);
13997
13941
  const entry = {
13998
13942
  id: this._uid(),
13999
13943
  type: options.type ?? TOAST_DEFAULTS.type,
@@ -14014,7 +13958,6 @@ class ClxToastService {
14014
13958
  const list = container.instance.entries();
14015
13959
  container.instance.entries.set(isBottom ? [...list, entry] : [entry, ...list]);
14016
13960
  }
14017
- // ─── Convenience shortcuts ─────────────────────────────────────────────────
14018
13961
  success(message, opts = {}) {
14019
13962
  this.show({ ...opts, type: 'green', message });
14020
13963
  }
@@ -14030,25 +13973,26 @@ class ClxToastService {
14030
13973
  dismissAll() {
14031
13974
  this._containers.forEach(c => c.instance.entries.set([]));
14032
13975
  }
14033
- // ─── Container management ──────────────────────────────────────────────────
14034
13976
  _getOrCreateContainer(position) {
14035
13977
  const existing = this._containers.get(position);
14036
13978
  if (existing)
14037
13979
  return existing;
14038
- const overlay = this._getOverlay();
14039
- const overlayRef = overlay.create(new OverlayConfig({
14040
- hasBackdrop: false,
14041
- scrollStrategy: overlay.scrollStrategies.noop(),
14042
- positionStrategy: overlay.position().global(),
14043
- }));
14044
- const portal = new ComponentPortal(ClxToastContainerComponent, null, Injector.create({ parent: this._injector, providers: [] }));
14045
- const compRef = overlayRef.attach(portal);
14046
- compRef.setInput('position', position);
14047
- const entry = { overlayRef, instance: compRef.instance };
13980
+ // Dedicated div — completely separate from modal's DOM tree
13981
+ const el = document.createElement('div');
13982
+ el.style.cssText = 'position:fixed;inset:0;z-index:9000;pointer-events:none;';
13983
+ document.body.appendChild(el);
13984
+ const ref = createComponent(ClxToastContainerComponent, {
13985
+ environmentInjector: this._appRef.injector,
13986
+ elementInjector: this._injector,
13987
+ });
13988
+ ref.setInput('position', position);
13989
+ this._appRef.attachView(ref.hostView);
13990
+ const compEl = ref.location.nativeElement;
13991
+ el.appendChild(compEl);
13992
+ const entry = { el, instance: ref.instance };
14048
13993
  this._containers.set(position, entry);
14049
13994
  return entry;
14050
13995
  }
14051
- // ─── Utilities ─────────────────────────────────────────────────────────────
14052
13996
  _uid() {
14053
13997
  return `toast-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
14054
13998
  }