ngx-custom-modal
Version:
A custom Modal / Dialog (with inner component support) for Angular 17-20 projects with full version compatibility
432 lines (427 loc) • 14.5 kB
TypeScript
import * as _angular_core from '@angular/core';
import { OnInit, OnDestroy, ElementRef, TemplateRef, EventEmitter } from '@angular/core';
/**
* Configuration options for the ngx-custom-modal component.
* @public
*/
interface ModalOptions {
/** Close modal when clicking outside the modal content. @default true */
closeOnOutsideClick?: boolean;
/** Close modal when pressing the Escape key. @default true */
closeOnEscape?: boolean;
/** Additional CSS class to apply to the modal container */
customClass?: string;
/** Hide the default close button (×) in the header. @default false */
hideCloseButton?: boolean;
/**
* Backdrop behavior configuration
* - 'static': Prevents closing when clicking outside
* - 'dynamic': Allows closing when clicking outside (if closeOnOutsideClick is true)
* @default 'dynamic'
*/
backdrop?: 'static' | 'dynamic';
/** Enable keyboard interactions (Tab navigation, Escape key). @default true */
keyboard?: boolean;
/** Enable automatic focus management. @default true */
focus?: boolean;
/**
* Modal size preset
* - 'sm': Small (300px max-width)
* - 'md': Medium (500px max-width)
* - 'lg': Large (800px max-width)
* - 'xl': Extra Large (1140px max-width)
* @default 'md'
*/
size?: 'sm' | 'md' | 'lg' | 'xl';
/** Center modal vertically in viewport. @default false */
centered?: boolean;
/** Make modal body scrollable when content overflows. @default false */
scrollable?: boolean;
/** Enable CSS transition animations. @default true */
animation?: boolean;
/** Animation duration in milliseconds. @default 200 */
animationDuration?: number;
}
/**
* Button configuration for modal footers.
* @public
*/
interface ModalButton {
/** Unique identifier for the button */
id: string;
/** Display text for the button */
text: string;
/** CSS classes to apply to the button */
class: string;
/** HTML button type attribute. @default 'button' */
type?: 'button' | 'submit' | 'reset';
/** Click event handler function */
handler?: () => void;
/** Disable the button. @default false */
disabled?: boolean;
}
/**
* Internal state interface for modal component.
* Used by signals for reactive state management.
* @internal
*/
interface ModalState {
/** Whether the modal is currently visible */
isVisible: boolean;
/** Whether the modal is currently animating (opening/closing) */
isAnimating: boolean;
/** Current z-index value for stacking */
zIndex: number;
/** Element that had focus before modal opened (for restoration) */
previousFocusedElement?: HTMLElement;
}
/**
* A feature-rich, accessible modal component for Angular 17+ applications.
*
* Features:
* - Signal-based reactivity for optimal performance
* - Advanced modal stacking with z-index management
* - Full WCAG accessibility compliance
* - Bootstrap 3, 4 & 5 compatibility
* - Touch-optimized for mobile devices
* - Customizable animations and styling
* - Cross-version compatibility (Angular 17-20+)
*
* @example
* ```html
* <ngx-custom-modal #modal [size]="'lg'" [centered]="true">
* <ng-template #modalHeader>
* <h2>Modal Title</h2>
* </ng-template>
* <ng-template #modalBody>
* <p>Modal content</p>
* </ng-template>
* </ngx-custom-modal>
* ```
*
* @public
*/
declare class NgxCustomModalComponent implements OnInit, OnDestroy {
private elementRef;
private document;
private lifecycleService;
modalDialog: ElementRef<HTMLDialogElement>;
/** Template reference for modal header content */
header: TemplateRef<any> | null;
/** Template reference for modal body content */
body: TemplateRef<any> | null;
/** Template reference for modal footer content */
footer: TemplateRef<any> | null;
/** Close modal when clicking outside the modal content. @default true */
closeOnOutsideClick: boolean;
/** Close modal when pressing the Escape key. @default true */
closeOnEscape: boolean;
/** Additional CSS class to apply to the modal container */
customClass?: string;
/** Hide the default close button (×) in the header. @default false */
hideCloseButton: boolean;
/** Configuration options object that overrides individual properties */
options: ModalOptions;
/** Modal size preset. @default 'md' */
size: 'sm' | 'md' | 'lg' | 'xl';
/** Center modal vertically in viewport. @default false */
centered: boolean;
/** Make modal body scrollable when content overflows. @default false */
scrollable: boolean;
/** Enable CSS transition animations. @default true */
animation: boolean;
/** Backdrop behavior configuration. @default 'dynamic' */
backdrop: 'static' | 'dynamic';
/** Enable keyboard interactions. @default true */
keyboard: boolean;
/** Enable automatic focus management. @default true */
focus: boolean;
/** Emitted when modal starts opening */
opened: EventEmitter<void>;
/** Emitted when modal is fully closed */
closed: EventEmitter<void>;
/** Emitted before modal starts opening */
opening: EventEmitter<void>;
/** Emitted before modal starts closing */
closing: EventEmitter<void>;
private modalState;
private animationDuration;
private modalStack;
/** Computed signal for modal visibility state */
visible: _angular_core.Signal<boolean>;
/** Signal for animation state */
visibleAnimate: _angular_core.WritableSignal<boolean>;
/** Computed signal for animation state */
isAnimating: _angular_core.Signal<boolean>;
/** Unique ID for modal title (ARIA) */
titleId: _angular_core.WritableSignal<string>;
/** Unique ID for modal description (ARIA) */
descriptionId: _angular_core.WritableSignal<string>;
private previouslyFocusedElement;
private modalStackService;
private afterRenderCleanup;
private afterNextRenderCleanup;
constructor();
ngOnInit(): void;
ngOnDestroy(): void;
/**
* Opens the modal with proper accessibility and focus management.
*
* Automatically handles:
* - Focus management (saves current focus, sets focus to modal)
* - Body scroll locking
* - Z-index management for stacking
* - Screen reader announcements
*
* @public
* @fires opening - Before modal animation starts
* @fires opened - After modal is fully visible
*/
open(): void;
/**
* Closes the modal and restores previous state.
*
* Automatically handles:
* - Focus restoration to previously focused element
* - Body scroll unlock (if no other modals open)
* - Cleanup of event listeners
*
* @public
* @fires closing - Before modal animation starts
* @fires closed - After modal is fully hidden
*/
close(): void;
/**
* Toggles the modal visibility state.
* @public
*/
toggle(): void;
/**
* Handles clicks on the modal container for outside click detection.
* @param event - The mouse click event
* @private
*/
onContainerClicked(event: MouseEvent): void;
/**
* Handles global keyboard events for modal functionality.
* @param event - The keyboard event
* @private
*/
onKeyDownHandler(event: KeyboardEvent): void;
/**
* Checks if this modal is the topmost in the stack.
* Used for proper event handling in nested modals.
*
* @returns {boolean} True if this modal is on top of the stack
* @public
*/
isTopMost(): boolean;
/**
* Gets the combined custom CSS classes for the modal.
* @returns {string} Space-separated CSS classes
* @public
*/
getCustomClass(): string;
/**
* Gets the CSS classes for the modal dialog container.
* @returns {string} Space-separated CSS classes
* @public
*/
getDialogClasses(): string;
/**
* Determines if the close button should be hidden.
* @returns {boolean} True if close button should be hidden
* @public
*/
shouldHideCloseButton(): boolean;
/**
* Gets the ARIA label for the close button.
* @returns {string} Localized close button label
* @public
*/
getCloseButtonLabel(): string;
/**
* Checks if header content is available.
* @returns {boolean} True if header template exists
* @public
*/
hasHeaderContent(): boolean;
/**
* Checks if footer content is available.
* @returns {boolean} True if footer template exists
* @public
*/
hasFooterContent(): boolean;
/**
* Sets up lifecycle hooks with version compatibility.
* @private
*/
private setupLifecycleHooks;
/**
* Cleans up lifecycle hook subscriptions.
* @private
*/
private cleanupLifecycleHooks;
/**
* Logs version information for debugging.
* @private
*/
private logVersionInfo;
/**
* Handles modal opening side effects.
* @private
*/
private handleModalOpen;
/**
* Handles modal closing side effects.
* @private
*/
private handleModalClose;
/**
* Sets up accessibility attributes and ARIA labels.
* @private
*/
private setupAccessibility;
/**
* Sets up keyboard navigation handlers.
* @private
*/
private setupKeyboardNavigation;
/**
* Sets up focus management systems.
* @private
*/
private setupFocusManagement;
/**
* Adjusts modal position and size based on viewport.
* @private
*/
private adjustModalPosition;
/**
* Ensures proper z-index for modal stacking.
* @private
*/
private ensureProperZIndex;
/**
* Stores the currently focused element for later restoration.
* @private
*/
private storePreviousFocus;
/**
* Restores focus to the previously focused element.
* @private
*/
private restoreFocus;
/**
* Manages focus within the modal for accessibility.
* Focuses first focusable element or close button as fallback.
* @private
*/
private focusFirstElement;
/**
* Handles tab key navigation to trap focus within the modal.
* Implements circular focus trapping as per WCAG guidelines.
* @param event - The keyboard event
* @private
*/
private handleTabKey;
/**
* Adds modal-open class to body to prevent scrolling.
* @private
*/
private addBodyClass;
/**
* Removes modal-open class from body when no modals are open.
* @private
*/
private removeBodyClass;
/**
* Gets the CSS class for modal size.
* @returns {string} Size-specific CSS class
* @private
*/
private getSizeClass;
/**
* Gets the CSS class for animation state.
* @returns {string} Animation-specific CSS class
* @private
*/
private getAnimationClass;
/**
* Updates CSS custom property for animation duration.
* @param duration - Animation duration in milliseconds
* @private
*/
private updateCSSAnimationDuration;
/**
* Registers this modal instance with the modal stack service.
* @private
*/
private registerInModalStack;
/**
* Unregisters this modal instance from the modal stack service.
* @private
*/
private unregisterFromModalStack;
/**
* Announces messages to screen readers for accessibility.
* @param message - Message to announce
* @private
*/
private announceToScreenReader;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgxCustomModalComponent, never>;
static ɵcmp: _angular_core.ɵɵComponentDeclaration<NgxCustomModalComponent, "ngx-custom-modal", never, { "closeOnOutsideClick": { "alias": "closeOnOutsideClick"; "required": false; }; "closeOnEscape": { "alias": "closeOnEscape"; "required": false; }; "customClass": { "alias": "customClass"; "required": false; }; "hideCloseButton": { "alias": "hideCloseButton"; "required": false; }; "options": { "alias": "options"; "required": false; }; "size": { "alias": "size"; "required": false; }; "centered": { "alias": "centered"; "required": false; }; "scrollable": { "alias": "scrollable"; "required": false; }; "animation": { "alias": "animation"; "required": false; }; "backdrop": { "alias": "backdrop"; "required": false; }; "keyboard": { "alias": "keyboard"; "required": false; }; "focus": { "alias": "focus"; "required": false; }; }, { "opened": "opened"; "closed": "closed"; "opening": "opening"; "closing": "closing"; }, ["header", "body", "footer"], never, true, never>;
}
/**
* Service for managing multiple modal instances and their stacking order.
*
* Handles:
* - Z-index calculation for proper stacking
* - Modal registration/unregistration
* - Top-most modal identification
* - Body class management
*
* @injectable
* @public
*/
declare class NgxModalStackService {
private modals;
private baseZIndex;
/**
* Registers a modal instance with the stack service.
* @param modal - The modal component to register
* @public
*/
register(modal: NgxCustomModalComponent): void;
/**
* Unregisters a modal instance from the stack service.
* @param modal - The modal component to unregister
* @public
*/
unregister(modal: NgxCustomModalComponent): void;
/**
* Determines if the given modal is the topmost visible modal.
* Used for proper event handling and accessibility.
* @param modal - The modal instance to check
* @returns {boolean} True if the modal is topmost
* @public
*/
isTopMost(modal: NgxCustomModalComponent): boolean;
/**
* Calculates the next z-index value for a new modal.
* Each modal gets a z-index 10 units higher than the previous.
* @returns {number} The z-index value to use
* @public
*/
getNextZIndex(): number;
/**
* Gets the count of currently active (visible) modals.
* @returns {number} Number of active modals
* @public
*/
getActiveModalsCount(): number;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgxModalStackService, never>;
static ɵprov: _angular_core.ɵɵInjectableDeclaration<NgxModalStackService>;
}
export { NgxCustomModalComponent, NgxModalStackService };
export type { ModalButton, ModalOptions, ModalState };