mirror of
https://github.com/php-flasher/php-flasher.git
synced 2026-03-31 15:07:47 +01:00
Simplify JSDoc and comments in TypeScript and SCSS files
Removes verbose documentation and examples from: - flasher.ts (main orchestration class) - flasher-plugin.ts (default plugin implementation) - types.ts (type definitions) - flasher.scss (default theme styles) - mixins.scss (reusable SASS mixins) Keeps essential type annotations and parameter documentation.
This commit is contained in:
@@ -1,101 +1,28 @@
|
||||
/**
|
||||
* @file FlasherPlugin Implementation
|
||||
* @description Default implementation for displaying notifications using custom themes
|
||||
* @author Younes ENNAJI
|
||||
*/
|
||||
import './themes/index.scss'
|
||||
|
||||
import type { Properties } from 'csstype'
|
||||
import type { Envelope, FlasherPluginOptions, Options, Theme } from './types'
|
||||
import { AbstractPlugin } from './plugin'
|
||||
|
||||
/**
|
||||
* Default FlasherPlugin implementation using custom themes.
|
||||
*
|
||||
* FlasherPlugin is the built-in renderer for PHPFlasher that creates DOM-based
|
||||
* notifications with a customizable appearance. It uses themes to determine
|
||||
* the HTML structure and styling of notifications.
|
||||
*
|
||||
* Features:
|
||||
* - Theme-based notification rendering
|
||||
* - Container management for different positions
|
||||
* - Auto-dismissal with progress bars
|
||||
* - RTL language support
|
||||
* - HTML escaping for security
|
||||
* - Mouse-over pause of auto-dismissal
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Create a simple theme
|
||||
* const myTheme: Theme = {
|
||||
* styles: ['my-theme.css'],
|
||||
* render: (envelope) => `
|
||||
* <div class="my-notification my-notification-${envelope.type}">
|
||||
* <h4>${envelope.title}</h4>
|
||||
* <p>${envelope.message}</p>
|
||||
* <button class="fl-close">×</button>
|
||||
* <div class="fl-progress-bar"></div>
|
||||
* </div>
|
||||
* `
|
||||
* };
|
||||
*
|
||||
* // Create a plugin with the theme
|
||||
* const plugin = new FlasherPlugin(myTheme);
|
||||
*
|
||||
* // Show a notification
|
||||
* plugin.success('Operation completed');
|
||||
* ```
|
||||
*/
|
||||
export default class FlasherPlugin extends AbstractPlugin {
|
||||
/**
|
||||
* Theme configuration used for rendering notifications.
|
||||
* @private
|
||||
*/
|
||||
private theme: Theme
|
||||
|
||||
/**
|
||||
* Default configuration options for notifications.
|
||||
* These can be overridden globally or per notification.
|
||||
* @private
|
||||
*/
|
||||
private options: FlasherPluginOptions = {
|
||||
// Default or type-specific timeout (milliseconds, null = use type-specific)
|
||||
// Use false for sticky notifications, or any negative number
|
||||
timeout: null,
|
||||
|
||||
// Type-specific timeout durations
|
||||
timeouts: {
|
||||
success: 10000,
|
||||
info: 10000,
|
||||
error: 10000,
|
||||
warning: 10000,
|
||||
},
|
||||
|
||||
// Animation frames per second (higher = smoother but more CPU intensive)
|
||||
fps: 30,
|
||||
|
||||
// Default position on screen
|
||||
position: 'top-right',
|
||||
|
||||
// Stacking direction (top = newest first, bottom = newest last)
|
||||
direction: 'top',
|
||||
|
||||
// Right-to-left text direction
|
||||
rtl: false,
|
||||
|
||||
// Custom container styles
|
||||
style: {} as Properties,
|
||||
|
||||
// Whether to escape HTML in message content (security feature)
|
||||
escapeHtml: false,
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FlasherPlugin with a specific theme.
|
||||
*
|
||||
* @param theme - Theme configuration to use for rendering notifications
|
||||
* @throws {Error} If theme is missing or invalid
|
||||
*/
|
||||
constructor(theme: Theme) {
|
||||
super()
|
||||
|
||||
@@ -110,14 +37,6 @@ export default class FlasherPlugin extends AbstractPlugin {
|
||||
this.theme = theme
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders notification envelopes using the configured theme.
|
||||
*
|
||||
* This method creates and displays notifications in the DOM based on
|
||||
* the provided envelopes and the plugin's theme.
|
||||
*
|
||||
* @param envelopes - Array of notification envelopes to render
|
||||
*/
|
||||
public renderEnvelopes(envelopes: Envelope[]): void {
|
||||
if (!envelopes?.length) {
|
||||
return
|
||||
@@ -165,11 +84,6 @@ export default class FlasherPlugin extends AbstractPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the plugin options.
|
||||
*
|
||||
* @param options - New options to apply
|
||||
*/
|
||||
public renderOptions(options: Options): void {
|
||||
if (!options) {
|
||||
return
|
||||
@@ -177,16 +91,6 @@ export default class FlasherPlugin extends AbstractPlugin {
|
||||
this.options = { ...this.options, ...options }
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or gets the container for notifications.
|
||||
*
|
||||
* This method ensures that each position has its own container for notifications.
|
||||
* If a container for the specified position doesn't exist yet, it creates one.
|
||||
*
|
||||
* @param options - Options containing position and style information
|
||||
* @returns The container element
|
||||
* @private
|
||||
*/
|
||||
private createContainer(options: { position: string, style: Properties }): HTMLDivElement {
|
||||
// Look for existing container for this position
|
||||
let container = document.querySelector(`.fl-wrapper[data-position="${options.position}"]`) as HTMLDivElement
|
||||
@@ -213,20 +117,6 @@ export default class FlasherPlugin extends AbstractPlugin {
|
||||
return container
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a notification to the container.
|
||||
*
|
||||
* This method:
|
||||
* 1. Creates a notification element using the theme's render function
|
||||
* 2. Adds necessary classes and event listeners
|
||||
* 3. Appends it to the container in the right position
|
||||
* 4. Sets up auto-dismissal if a timeout is specified
|
||||
*
|
||||
* @param container - Container to add the notification to
|
||||
* @param envelope - Notification information
|
||||
* @param options - Display options
|
||||
* @private
|
||||
*/
|
||||
private addToContainer(
|
||||
container: HTMLDivElement,
|
||||
envelope: Envelope,
|
||||
@@ -291,13 +181,6 @@ export default class FlasherPlugin extends AbstractPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes timeout value to handle different formats (number, boolean, null)
|
||||
*
|
||||
* @param timeout - The timeout value to normalize
|
||||
* @returns A number representing milliseconds, or 0 for sticky notifications
|
||||
* @private
|
||||
*/
|
||||
private normalizeTimeout(timeout: any): number {
|
||||
// Handle false or negative numbers as sticky notifications (0)
|
||||
if (timeout === false || (typeof timeout === 'number' && timeout < 0)) {
|
||||
@@ -313,16 +196,6 @@ export default class FlasherPlugin extends AbstractPlugin {
|
||||
return Number(timeout) || 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a progress timer to the notification.
|
||||
*
|
||||
* This method creates a visual progress bar that shows the remaining time
|
||||
* before auto-dismissal. The timer pauses when the user hovers over the notification.
|
||||
*
|
||||
* @param notification - Notification element
|
||||
* @param options - Timer options
|
||||
* @private
|
||||
*/
|
||||
private addTimer(notification: HTMLElement, { timeout, fps }: { timeout: number, fps: number }): void {
|
||||
if (timeout <= 0) {
|
||||
return
|
||||
@@ -368,18 +241,6 @@ export default class FlasherPlugin extends AbstractPlugin {
|
||||
notification.addEventListener('mouseover', () => clearInterval(intervalId))
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a notification with animation.
|
||||
*
|
||||
* This method:
|
||||
* 1. Removes the 'show' class to trigger the hide animation
|
||||
* 2. Waits for the animation to complete
|
||||
* 3. Removes the notification from the DOM
|
||||
* 4. Cleans up the container if it's now empty
|
||||
*
|
||||
* @param notification - Notification element to remove
|
||||
* @private
|
||||
*/
|
||||
private removeNotification(notification: HTMLElement): void {
|
||||
if (!notification) {
|
||||
return
|
||||
@@ -398,29 +259,12 @@ export default class FlasherPlugin extends AbstractPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an HTML string to a DOM element.
|
||||
*
|
||||
* @param str - HTML string to convert
|
||||
* @returns The created DOM element
|
||||
* @private
|
||||
*/
|
||||
private stringToHTML(str: string): HTMLElement {
|
||||
const template = document.createElement('template')
|
||||
template.innerHTML = str.trim()
|
||||
return template.content.firstElementChild as HTMLElement
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely escapes HTML special characters.
|
||||
*
|
||||
* This method replaces special characters with their HTML entities
|
||||
* to prevent XSS attacks when displaying user-provided content.
|
||||
*
|
||||
* @param str - String to escape
|
||||
* @returns Escaped string
|
||||
* @private
|
||||
*/
|
||||
private escapeHtml(str: string | null | undefined): string {
|
||||
if (str == null) {
|
||||
return ''
|
||||
|
||||
@@ -1,98 +1,13 @@
|
||||
/**
|
||||
* @file Flasher Core
|
||||
* @description Main orchestration class for the PHPFlasher notification system
|
||||
* @author Younes ENNAJI
|
||||
*/
|
||||
import type { Asset, Context, Envelope, Options, PluginInterface, Response, Theme } from './types'
|
||||
import { AbstractPlugin } from './plugin'
|
||||
import FlasherPlugin from './flasher-plugin'
|
||||
|
||||
/**
|
||||
* Main Flasher class that manages plugins, themes, and notifications.
|
||||
*
|
||||
* Flasher is the central orchestration class for PHPFlasher. It handles:
|
||||
* 1. Plugin registration and management
|
||||
* 2. Theme registration and resolution
|
||||
* 3. Asset loading (JS and CSS)
|
||||
* 4. Routing notifications to the appropriate plugin
|
||||
* 5. Response processing and normalization
|
||||
*
|
||||
* This class follows the façade pattern, providing a simple interface to the
|
||||
* underlying plugin ecosystem.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Create a flasher instance
|
||||
* const flasher = new Flasher();
|
||||
*
|
||||
* // Register a plugin
|
||||
* flasher.addPlugin('toastr', new ToastrPlugin());
|
||||
*
|
||||
* // Show a notification
|
||||
* flasher.use('toastr').success('Operation completed successfully');
|
||||
*
|
||||
* // Process server response
|
||||
* flasher.render(response);
|
||||
* ```
|
||||
*/
|
||||
export default class Flasher extends AbstractPlugin {
|
||||
/**
|
||||
* Default plugin to use when none is specified.
|
||||
* This plugin will be used when displaying notifications without
|
||||
* explicitly specifying a plugin.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private defaultPlugin = 'flasher'
|
||||
|
||||
/**
|
||||
* Map of registered plugins.
|
||||
* Stores plugin instances by name for easy lookup.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private plugins: Map<string, PluginInterface> = new Map<string, PluginInterface>()
|
||||
|
||||
/**
|
||||
* Map of registered themes.
|
||||
* Stores theme configurations by name.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private themes: Map<string, Theme> = new Map<string, Theme>()
|
||||
|
||||
/**
|
||||
* Set of assets that have been loaded.
|
||||
* Used to prevent duplicate loading of the same asset.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private loadedAssets: Set<string> = new Set<string>()
|
||||
|
||||
/**
|
||||
* Renders notifications from a response.
|
||||
*
|
||||
* This method processes a server response containing notifications and configuration.
|
||||
* It handles asset loading, option application, and notification rendering in a
|
||||
* coordinated sequence.
|
||||
*
|
||||
* @param response - The response containing notifications and configuration
|
||||
* @returns A promise that resolves when all operations are complete
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // From an AJAX response
|
||||
* const response = await fetch('/api/notifications').then(r => r.json());
|
||||
* await flasher.render(response);
|
||||
*
|
||||
* // With a partial response
|
||||
* flasher.render({
|
||||
* envelopes: [
|
||||
* { message: 'Hello world', type: 'info', title: 'Greeting', options: {}, metadata: {} }
|
||||
* ]
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
public async render(response: Partial<Response>): Promise<void> {
|
||||
const resolved = this.resolveResponse(response)
|
||||
|
||||
@@ -119,34 +34,6 @@ export default class Flasher extends AbstractPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders multiple notification envelopes.
|
||||
*
|
||||
* This method groups envelopes by plugin and delegates rendering to each plugin.
|
||||
* This ensures that each notification is processed by the appropriate plugin.
|
||||
*
|
||||
* @param envelopes - Array of notification envelopes to render
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* flasher.renderEnvelopes([
|
||||
* {
|
||||
* message: 'Operation completed',
|
||||
* type: 'success',
|
||||
* title: 'Success',
|
||||
* options: {},
|
||||
* metadata: { plugin: 'toastr' }
|
||||
* },
|
||||
* {
|
||||
* message: 'An error occurred',
|
||||
* type: 'error',
|
||||
* title: 'Error',
|
||||
* options: {},
|
||||
* metadata: { plugin: 'sweetalert' }
|
||||
* }
|
||||
* ]);
|
||||
* ```
|
||||
*/
|
||||
public renderEnvelopes(envelopes: Envelope[]): void {
|
||||
if (!envelopes?.length) {
|
||||
return
|
||||
@@ -171,22 +58,6 @@ export default class Flasher extends AbstractPlugin {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies options to each plugin.
|
||||
*
|
||||
* This method distributes options to the appropriate plugins based on the keys
|
||||
* in the options object. Each plugin receives only its specific options.
|
||||
*
|
||||
* @param options - Object mapping plugin names to their specific options
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* flasher.renderOptions({
|
||||
* toastr: { timeOut: 3000, closeButton: true },
|
||||
* sweetalert: { confirmButtonColor: '#3085d6' }
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
public renderOptions(options: Options): void {
|
||||
if (!options) {
|
||||
return
|
||||
@@ -202,26 +73,6 @@ export default class Flasher extends AbstractPlugin {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new plugin.
|
||||
*
|
||||
* Plugins are the notification renderers that actually display notifications.
|
||||
* Each plugin typically integrates with a specific notification library like
|
||||
* Toastr, SweetAlert, etc.
|
||||
*
|
||||
* @param name - Unique identifier for the plugin
|
||||
* @param plugin - Plugin instance that implements the PluginInterface
|
||||
* @throws {Error} If name or plugin is invalid
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Register a custom plugin
|
||||
* flasher.addPlugin('myplugin', new MyCustomPlugin());
|
||||
*
|
||||
* // Use the registered plugin
|
||||
* flasher.use('myplugin').info('Hello world');
|
||||
* ```
|
||||
*/
|
||||
public addPlugin(name: string, plugin: PluginInterface): void {
|
||||
if (!name || !plugin) {
|
||||
throw new Error('Both plugin name and instance are required')
|
||||
@@ -229,33 +80,6 @@ export default class Flasher extends AbstractPlugin {
|
||||
this.plugins.set(name, plugin)
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new theme.
|
||||
*
|
||||
* Themes define the visual appearance of notifications when using
|
||||
* the default FlasherPlugin. They provide HTML templates and CSS styles.
|
||||
*
|
||||
* @param name - Unique identifier for the theme
|
||||
* @param theme - Theme configuration object
|
||||
* @throws {Error} If name or theme is invalid
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Register a bootstrap theme
|
||||
* flasher.addTheme('bootstrap', {
|
||||
* styles: ['bootstrap.min.css'],
|
||||
* render: (envelope) => `
|
||||
* <div class="alert alert-${envelope.type}">
|
||||
* <h4>${envelope.title}</h4>
|
||||
* <p>${envelope.message}</p>
|
||||
* </div>
|
||||
* `
|
||||
* });
|
||||
*
|
||||
* // Use the theme
|
||||
* flasher.use('theme.bootstrap').success('Hello world');
|
||||
* ```
|
||||
*/
|
||||
public addTheme(name: string, theme: Theme): void {
|
||||
if (!name || !theme) {
|
||||
throw new Error('Both theme name and definition are required')
|
||||
@@ -263,27 +87,6 @@ export default class Flasher extends AbstractPlugin {
|
||||
this.themes.set(name, theme)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a plugin by name.
|
||||
*
|
||||
* This method resolves plugin aliases and creates theme-based plugins
|
||||
* on demand. If a theme-based plugin is requested but doesn't exist yet,
|
||||
* it will be created automatically.
|
||||
*
|
||||
* @param name - Name of the plugin to retrieve
|
||||
* @returns The requested plugin instance
|
||||
* @throws {Error} If the plugin cannot be resolved
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Get and use a plugin
|
||||
* const toastr = flasher.use('toastr');
|
||||
* toastr.success('Operation completed');
|
||||
*
|
||||
* // Use a theme as a plugin (automatically creates a FlasherPlugin)
|
||||
* flasher.use('theme.bootstrap').error('Something went wrong');
|
||||
* ```
|
||||
*/
|
||||
public use(name: string): PluginInterface {
|
||||
const resolvedName = this.resolvePluginAlias(name)
|
||||
this.resolvePlugin(resolvedName)
|
||||
@@ -296,29 +99,10 @@ export default class Flasher extends AbstractPlugin {
|
||||
return plugin
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for use().
|
||||
*
|
||||
* @param name - Name of the plugin to retrieve
|
||||
* @returns The requested plugin instance
|
||||
*/
|
||||
public create(name: string): PluginInterface {
|
||||
return this.use(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves and normalizes a response object.
|
||||
*
|
||||
* This method:
|
||||
* 1. Fills in default values for missing properties
|
||||
* 2. Resolves plugin aliases for envelopes
|
||||
* 3. Converts string functions to actual functions
|
||||
* 4. Adds theme styles to the response
|
||||
*
|
||||
* @param response - Partial response object
|
||||
* @returns Fully resolved response object
|
||||
* @private
|
||||
*/
|
||||
private resolveResponse(response: Partial<Response>): Response {
|
||||
const resolved = {
|
||||
envelopes: [],
|
||||
@@ -350,16 +134,6 @@ export default class Flasher extends AbstractPlugin {
|
||||
return resolved
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves string functions to actual function objects.
|
||||
*
|
||||
* This allows options to include functions serialized as strings,
|
||||
* which is useful for passing functions from the server to the client.
|
||||
*
|
||||
* @param options - Options object that may contain string functions
|
||||
* @returns Options object with string functions converted to actual functions
|
||||
* @private
|
||||
*/
|
||||
private resolveOptions(options: Options): Options {
|
||||
if (!options) {
|
||||
return {}
|
||||
@@ -374,18 +148,6 @@ export default class Flasher extends AbstractPlugin {
|
||||
return resolved
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string function representation to an actual function.
|
||||
*
|
||||
* Supports both traditional and arrow function syntax:
|
||||
* - `function(a, b) { return a + b; }`
|
||||
* - `(a, b) => a + b`
|
||||
* - `a => a * 2`
|
||||
*
|
||||
* @param func - Value to check and potentially convert
|
||||
* @returns Function if conversion was successful, otherwise the original value
|
||||
* @private
|
||||
*/
|
||||
private resolveFunction(func: unknown): unknown {
|
||||
if (typeof func !== 'string') {
|
||||
return func
|
||||
@@ -416,15 +178,6 @@ export default class Flasher extends AbstractPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates theme-based plugins on demand.
|
||||
*
|
||||
* This method automatically creates a FlasherPlugin instance for a theme
|
||||
* when a theme-based plugin is requested but doesn't exist yet.
|
||||
*
|
||||
* @param alias - Plugin alias to resolve
|
||||
* @private
|
||||
*/
|
||||
private resolvePlugin(alias: string): void {
|
||||
const factory = this.plugins.get(alias)
|
||||
if (factory || !alias.includes('theme.')) {
|
||||
@@ -441,15 +194,6 @@ export default class Flasher extends AbstractPlugin {
|
||||
this.addPlugin(alias, new FlasherPlugin(theme))
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a plugin name to its actual implementation name.
|
||||
*
|
||||
* This method handles the default plugin and theme aliases.
|
||||
*
|
||||
* @param alias - Plugin alias to resolve
|
||||
* @returns Resolved plugin name
|
||||
* @private
|
||||
*/
|
||||
private resolvePluginAlias(alias?: string): string {
|
||||
alias = alias || this.defaultPlugin
|
||||
|
||||
@@ -457,16 +201,6 @@ export default class Flasher extends AbstractPlugin {
|
||||
return alias === 'flasher' ? 'theme.flasher' : alias
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds CSS and JavaScript assets to the page.
|
||||
*
|
||||
* This method efficiently loads assets, respecting the order for scripts
|
||||
* which is crucial for libraries with dependencies like jQuery plugins.
|
||||
*
|
||||
* @param assets - Array of assets to load
|
||||
* @returns Promise that resolves when all assets are loaded
|
||||
* @private
|
||||
*/
|
||||
private async addAssets(assets: Asset[]): Promise<void> {
|
||||
try {
|
||||
// Process CSS files in parallel (order doesn't matter for CSS)
|
||||
@@ -513,15 +247,6 @@ export default class Flasher extends AbstractPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a single asset (CSS or JavaScript) into the document.
|
||||
*
|
||||
* @param url - URL of the asset to load
|
||||
* @param nonce - CSP nonce for the asset
|
||||
* @param type - Type of asset ('style' or 'script')
|
||||
* @returns Promise that resolves when the asset is loaded
|
||||
* @private
|
||||
*/
|
||||
private loadAsset(url: string, nonce: string, type: 'style' | 'script'): Promise<void> {
|
||||
// Check if asset is already loaded
|
||||
if (document.querySelector(`${type === 'style' ? 'link' : 'script'}[src="${url}"]`)) {
|
||||
@@ -553,16 +278,6 @@ export default class Flasher extends AbstractPlugin {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds theme styles to the list of assets to load.
|
||||
*
|
||||
* This method extracts style URLs from theme definitions and adds them
|
||||
* to the response styles array.
|
||||
*
|
||||
* @param response - Response object to modify
|
||||
* @param plugin - Plugin name that may reference a theme
|
||||
* @private
|
||||
*/
|
||||
private addThemeStyles(response: Response, plugin: string): void {
|
||||
// Only process theme plugins
|
||||
if (plugin !== 'flasher' && !plugin.includes('theme.')) {
|
||||
|
||||
@@ -1,16 +1,6 @@
|
||||
/**
|
||||
* @file PHPFlasher Default Theme
|
||||
* @description Classic bordered notification style with colorful accents
|
||||
* @author Younes ENNAJI
|
||||
*/
|
||||
|
||||
@use "sass:color";
|
||||
@use '../mixins' as *;
|
||||
|
||||
/**
|
||||
* Animation for flasher theme
|
||||
* Slides in from the left with a fade effect
|
||||
*/
|
||||
@keyframes flasherIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
@@ -22,7 +12,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* RTL animation */
|
||||
@keyframes flasherInRtl {
|
||||
from {
|
||||
opacity: 0;
|
||||
@@ -34,10 +23,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base theme styling
|
||||
* The default PHPFlasher notification appearance
|
||||
*/
|
||||
.fl-flasher {
|
||||
/* Base appearance */
|
||||
line-height: 1.5;
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
/**
|
||||
* @file PHPFlasher SASS Mixins
|
||||
* @description Reusable styling patterns for notification themes
|
||||
* @author Younes ENNAJI
|
||||
*/
|
||||
|
||||
@use "sass:color";
|
||||
|
||||
/**
|
||||
* @mixin variants
|
||||
*
|
||||
* Apply styles to each notification type (success, info, warning, error).
|
||||
* Passes the type name to the content block for use in selectors.
|
||||
*
|
||||
* @example
|
||||
* ```scss
|
||||
* @include variants using($type) {
|
||||
* background-color: var(--#{\$type}-color);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@mixin variants {
|
||||
@each $type in success, info, warning, error {
|
||||
&.fl-#{$type} {
|
||||
@@ -27,19 +8,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @mixin close-button
|
||||
*
|
||||
* Standard close button styling used across themes.
|
||||
* Creates a close button with hover effects and positioning.
|
||||
*
|
||||
* @example
|
||||
* ```scss
|
||||
* .my-notification {
|
||||
* @include close-button;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@mixin close-button {
|
||||
.fl-close {
|
||||
position: absolute;
|
||||
@@ -63,19 +31,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @mixin rtl-support
|
||||
*
|
||||
* Add support for right-to-left languages.
|
||||
* Adjusts layout, alignment, and button positioning for RTL display.
|
||||
*
|
||||
* @example
|
||||
* ```scss
|
||||
* .my-notification {
|
||||
* @include rtl-support;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@mixin rtl-support {
|
||||
&.fl-rtl {
|
||||
.fl-content {
|
||||
@@ -89,21 +44,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @mixin progress-bar
|
||||
*
|
||||
* Add a progress bar with type-specific colors.
|
||||
* Shows remaining time before notification is automatically closed.
|
||||
*
|
||||
* @param {Length} $height - Height of the progress bar (default: 0.125em)
|
||||
*
|
||||
* @example
|
||||
* ```scss
|
||||
* .my-notification {
|
||||
* @include progress-bar(0.2em);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@mixin progress-bar($height: 0.125em) {
|
||||
.fl-progress-bar {
|
||||
display: flex;
|
||||
@@ -128,22 +68,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @mixin dark-mode
|
||||
*
|
||||
* Add dark mode styling support.
|
||||
* Applies styles when dark mode is active (either via media query or class).
|
||||
*
|
||||
* @example
|
||||
* ```scss
|
||||
* .my-notification {
|
||||
* @include dark-mode {
|
||||
* background-color: #222;
|
||||
* color: white;
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@mixin dark-mode {
|
||||
@media (prefers-color-scheme: dark) {
|
||||
&.fl-auto-dark {
|
||||
|
||||
@@ -1,397 +1,59 @@
|
||||
/**
|
||||
* @file PHPFlasher Type Definitions
|
||||
* @description Core types and interfaces for the PHPFlasher notification system.
|
||||
* @author Younes ENNAJI
|
||||
*/
|
||||
import type { Properties } from 'csstype'
|
||||
|
||||
/**
|
||||
* Generic options object used throughout the application.
|
||||
*
|
||||
* This type represents a collection of key-value pairs that can be passed
|
||||
* to customize the behavior of notifications.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const options: Options = {
|
||||
* timeout: 5000,
|
||||
* position: 'top-right',
|
||||
* closeOnClick: true
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export type Options = Record<string, unknown>
|
||||
|
||||
/**
|
||||
* Context data that can be passed to notifications.
|
||||
*
|
||||
* Context provides additional data that can be utilized by notification
|
||||
* templates or handling logic.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const context: Context = {
|
||||
* userId: 123,
|
||||
* requestId: 'abc-123',
|
||||
* csrfToken: 'xyz'
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export type Context = Record<string, unknown>
|
||||
|
||||
/**
|
||||
* Represents a notification message to be displayed.
|
||||
*
|
||||
* An envelope encapsulates all the information needed to render a notification,
|
||||
* including its content, type, styling options, and metadata.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const envelope: Envelope = {
|
||||
* message: 'Operation completed successfully',
|
||||
* title: 'Success',
|
||||
* type: 'success',
|
||||
* options: { timeout: 5000 },
|
||||
* metadata: { plugin: 'toastr' }
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export type Envelope = {
|
||||
/** The main content of the notification */
|
||||
message: string
|
||||
|
||||
/**
|
||||
* Optional title for the notification.
|
||||
* If not provided, defaults to the capitalized notification type.
|
||||
*/
|
||||
title: string
|
||||
|
||||
/**
|
||||
* Notification type that determines its appearance and behavior.
|
||||
* Common types include: success, error, info, warning
|
||||
*/
|
||||
type: string
|
||||
|
||||
/**
|
||||
* Additional configuration options specific to this notification.
|
||||
* These will override global and plugin-specific defaults.
|
||||
*/
|
||||
options: Options
|
||||
|
||||
/**
|
||||
* Metadata about the notification, including which plugin should handle it.
|
||||
* The plugin field determines which renderer will process this notification.
|
||||
*/
|
||||
metadata: {
|
||||
plugin: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional context data accessible during notification rendering.
|
||||
* This can contain request-specific information or user data.
|
||||
*/
|
||||
context?: Context
|
||||
}
|
||||
|
||||
/**
|
||||
* Response from the server containing notifications and configuration.
|
||||
*
|
||||
* This structure is typically returned from backend endpoints and contains
|
||||
* all the information needed to render notifications, including assets to load.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const response: Response = {
|
||||
* envelopes: [{ message: 'Success', title: 'Done', type: 'success', options: {}, metadata: { plugin: 'toastr' } }],
|
||||
* options: { toastr: { closeButton: true } },
|
||||
* scripts: ['/assets/toastr.min.js'],
|
||||
* styles: ['/assets/toastr.min.css'],
|
||||
* context: { csp_nonce: 'random123' }
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export type Response = {
|
||||
/** Array of notification envelopes to be displayed */
|
||||
envelopes: Envelope[]
|
||||
|
||||
/**
|
||||
* Plugin-specific options that should be applied globally.
|
||||
* Organized by plugin name for selective application.
|
||||
*/
|
||||
options: Record<string, Options>
|
||||
|
||||
/** JavaScript files that should be loaded */
|
||||
scripts: string[]
|
||||
|
||||
/** CSS files that should be loaded */
|
||||
styles: string[]
|
||||
|
||||
/** Global context data shared across all notifications */
|
||||
context: Context
|
||||
}
|
||||
|
||||
/**
|
||||
* Core interface that all notification plugins must implement.
|
||||
*
|
||||
* This interface defines the contract for any notification library integration.
|
||||
* Each plugin represents a different notification library (Toastr, SweetAlert, etc.)
|
||||
* but exposes the same consistent API.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* class MyCustomPlugin implements PluginInterface {
|
||||
* // Implementation of required methods
|
||||
* }
|
||||
*
|
||||
* // Usage
|
||||
* const plugin = new MyCustomPlugin();
|
||||
* plugin.success('Operation completed');
|
||||
* ```
|
||||
*/
|
||||
export interface PluginInterface {
|
||||
/**
|
||||
* Display a success notification.
|
||||
*
|
||||
* @param message - Notification content or options object
|
||||
* @param title - Optional title or options object
|
||||
* @param options - Optional configuration options
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Simple usage
|
||||
* plugin.success('Data saved successfully');
|
||||
*
|
||||
* // With title
|
||||
* plugin.success('Changes applied', 'Success');
|
||||
*
|
||||
* // With options
|
||||
* plugin.success('Profile updated', 'Success', { timeOut: 3000 });
|
||||
*
|
||||
* // Using object syntax
|
||||
* plugin.success({
|
||||
* message: 'Operation completed',
|
||||
* title: 'Success',
|
||||
* timeout: 5000
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
success: (message: string | Options, title?: string | Options, options?: Options) => void
|
||||
|
||||
/**
|
||||
* Display an error notification.
|
||||
*
|
||||
* @param message - Notification content or options object
|
||||
* @param title - Optional title or options object
|
||||
* @param options - Optional configuration options
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Simple usage
|
||||
* plugin.error('An error occurred while processing your request');
|
||||
*
|
||||
* // With title
|
||||
* plugin.error('Could not connect to server', 'Connection Error');
|
||||
*
|
||||
* // With options
|
||||
* plugin.error('Invalid form data', 'Validation Error', { timeOut: 0 });
|
||||
* ```
|
||||
*/
|
||||
error: (message: string | Options, title?: string | Options, options?: Options) => void
|
||||
|
||||
/**
|
||||
* Display an information notification.
|
||||
*
|
||||
* @param message - Notification content or options object
|
||||
* @param title - Optional title or options object
|
||||
* @param options - Optional configuration options
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Simple usage
|
||||
* plugin.info('Your session will expire in 5 minutes');
|
||||
*
|
||||
* // With title and options
|
||||
* plugin.info('New updates are available', 'Information', {
|
||||
* closeButton: true,
|
||||
* timeOut: 10000
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
info: (message: string | Options, title?: string | Options, options?: Options) => void
|
||||
|
||||
/**
|
||||
* Display a warning notification.
|
||||
*
|
||||
* @param message - Notification content or options object
|
||||
* @param title - Optional title or options object
|
||||
* @param options - Optional configuration options
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Simple usage
|
||||
* plugin.warning('You have unsaved changes');
|
||||
*
|
||||
* // With title
|
||||
* plugin.warning('Your subscription will expire soon', 'Warning');
|
||||
* ```
|
||||
*/
|
||||
warning: (message: string | Options, title?: string | Options, options?: Options) => void
|
||||
|
||||
/**
|
||||
* Display any type of notification.
|
||||
*
|
||||
* This is a generic method that allows displaying notifications of any type,
|
||||
* including custom types beyond the standard success/error/info/warning.
|
||||
*
|
||||
* @param type - Notification type or options object
|
||||
* @param message - Notification content or options object
|
||||
* @param title - Optional title or options object
|
||||
* @param options - Optional configuration options
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Custom notification type
|
||||
* plugin.flash('question', 'Do you want to continue?', 'Confirmation');
|
||||
*
|
||||
* // Using object syntax
|
||||
* plugin.flash({
|
||||
* type: 'custom',
|
||||
* message: 'Something happened',
|
||||
* title: 'Notice',
|
||||
* icon: 'bell'
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
flash: (type: string | Options, message: string | Options, title?: string | Options, options?: Options) => void
|
||||
|
||||
/**
|
||||
* Render multiple notification envelopes.
|
||||
*
|
||||
* This is typically used internally to process batches of notifications
|
||||
* received from the server.
|
||||
*
|
||||
* @param envelopes - Array of notification envelopes to render
|
||||
*/
|
||||
renderEnvelopes: (envelopes: Envelope[]) => void
|
||||
|
||||
/**
|
||||
* Apply plugin-specific options.
|
||||
*
|
||||
* This method configures the underlying notification library
|
||||
* with the provided options.
|
||||
*
|
||||
* @param options - Configuration options for the plugin
|
||||
*/
|
||||
renderOptions: (options: Options) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme configuration for rendering notifications.
|
||||
*
|
||||
* A theme defines how notifications are visually presented to users,
|
||||
* including HTML structure, styling, and asset dependencies.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const bootstrapTheme: Theme = {
|
||||
* styles: ['bootstrap-notifications.css'],
|
||||
* render: (envelope) => `
|
||||
* <div class="alert alert-${envelope.type}">
|
||||
* <strong>${envelope.title}</strong>
|
||||
* <p>${envelope.message}</p>
|
||||
* </div>
|
||||
* `
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export type Theme = {
|
||||
/**
|
||||
* CSS styles to apply (string URL or array of URLs).
|
||||
* These will be automatically loaded when the theme is used.
|
||||
*/
|
||||
styles?: string | string[]
|
||||
|
||||
/**
|
||||
* Render function that converts an envelope to HTML string.
|
||||
* This function is responsible for generating the HTML structure
|
||||
* of the notification.
|
||||
*
|
||||
* @param envelope - The notification envelope to render
|
||||
* @returns HTML string representation of the notification
|
||||
*/
|
||||
render: (envelope: Envelope) => string
|
||||
}
|
||||
|
||||
/**
|
||||
* Asset types that can be loaded dynamically.
|
||||
* Used to distinguish between scripts and stylesheets.
|
||||
*/
|
||||
export type AssetType = 'style' | 'script'
|
||||
|
||||
/**
|
||||
* Configuration for an asset to be loaded.
|
||||
* Contains all information needed to load external resources.
|
||||
*/
|
||||
export type Asset = {
|
||||
/** URLs to load */
|
||||
urls: string[]
|
||||
|
||||
/** Content Security Policy nonce (if required) */
|
||||
nonce: string
|
||||
|
||||
/** Type of asset (style or script) */
|
||||
type: AssetType
|
||||
}
|
||||
|
||||
/**
|
||||
* FlasherPlugin specific options.
|
||||
*
|
||||
* These options control the behavior and appearance of notifications
|
||||
* rendered by the default FlasherPlugin.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const options: FlasherPluginOptions = {
|
||||
* position: 'bottom-left',
|
||||
* timeout: 8000,
|
||||
* rtl: true,
|
||||
* fps: 60
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export type FlasherPluginOptions = {
|
||||
/**
|
||||
* Default timeout in milliseconds (0 for no timeout).
|
||||
* Set to null to use type-specific timeouts.
|
||||
*/
|
||||
timeout: number | boolean | null
|
||||
|
||||
/** Type-specific timeouts in milliseconds */
|
||||
timeouts: Record<string, number>
|
||||
|
||||
/** Animation frames per second for the progress bar */
|
||||
fps: number
|
||||
|
||||
/**
|
||||
* Notification position on screen.
|
||||
* Common values: 'top-right', 'top-left', 'bottom-right', 'bottom-left', 'center'
|
||||
*/
|
||||
position: string
|
||||
|
||||
/**
|
||||
* Stacking direction of notifications.
|
||||
* 'top' means newer notifications appear above older ones.
|
||||
* 'bottom' means newer notifications appear below older ones.
|
||||
*/
|
||||
direction: 'top' | 'bottom'
|
||||
|
||||
/** Right-to-left text direction for RTL languages */
|
||||
rtl: boolean
|
||||
|
||||
/** Custom CSS styles applied to the notification container */
|
||||
style: Properties
|
||||
|
||||
/** Whether to escape HTML in messages for security */
|
||||
escapeHtml: boolean
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user