From 71b21855c147366a909bc2b1058fa3bb6c35f9a9 Mon Sep 17 00:00:00 2001 From: Younes ENNAJI Date: Sat, 8 Mar 2025 11:58:00 +0000 Subject: [PATCH] refactor notyf plugin and improve code documentation --- src/Notyf/Prime/Resources/assets/index.ts | 38 ++++++ src/Notyf/Prime/Resources/assets/notyf.scss | 17 +++ src/Notyf/Prime/Resources/assets/notyf.ts | 142 +++++++++++++++++--- 3 files changed, 182 insertions(+), 15 deletions(-) diff --git a/src/Notyf/Prime/Resources/assets/index.ts b/src/Notyf/Prime/Resources/assets/index.ts index 49ba1acf..cae5219d 100644 --- a/src/Notyf/Prime/Resources/assets/index.ts +++ b/src/Notyf/Prime/Resources/assets/index.ts @@ -1,9 +1,47 @@ +/** + * @file Notyf Plugin Entry Point + * @description Registers the Notyf plugin with PHPFlasher + * @author yoeunes + */ import './notyf.scss' import flasher from '@flasher/flasher' import NotyfPlugin from './notyf' +/** + * Create and register the Notyf plugin with PHPFlasher. + * + * This enables using Notyf for displaying notifications through + * the PHPFlasher API. + * + * @example + * ```typescript + * // With the plugin already registered + * import flasher from '@flasher/flasher'; + * + * flasher.use('notyf').success('Operation completed'); + * + * // With custom options + * flasher.use('notyf').info('This notification has custom options', null, { + * duration: 3000, + * ripple: true, + * dismissible: true + * }); + * ``` + */ const notyf = new NotyfPlugin() flasher.addPlugin('notyf', notyf) +/** + * Export the Notyf plugin instance. + * + * This allows direct access to the plugin if needed. + * + * @example + * ```typescript + * import notyf from '@flasher/flasher-notyf'; + * + * notyf.success('Operation completed'); + * ``` + */ export default notyf diff --git a/src/Notyf/Prime/Resources/assets/notyf.scss b/src/Notyf/Prime/Resources/assets/notyf.scss index 4e52c93e..5abf2d78 100644 --- a/src/Notyf/Prime/Resources/assets/notyf.scss +++ b/src/Notyf/Prime/Resources/assets/notyf.scss @@ -1,4 +1,15 @@ +/** + * Notyf custom styles for PHPFlasher + * + * These styles define custom icons for additional notification types + * (info and warning) beyond the default success and error types + * provided by Notyf. + * + * @author yoeunes + */ + .notyf { + // Common styles for custom icons &__icon { &--warning, &--info { @@ -21,6 +32,7 @@ } } + // Info icon (i) &--info { &::before, &::after { @@ -31,11 +43,13 @@ transform: translateX(-50%); } + // Vertical line &::before { top: 0.4em; height: 0.38em; } + // Dot and shadow &::after { top: 0.21em; height: 0.13em; @@ -43,6 +57,7 @@ } } + // Warning icon (!) &--warning { &::before, &::after { @@ -53,11 +68,13 @@ transform: translateX(-50%); } + // Exclamation vertical line &::before { top: 0.21em; height: 0.38em; } + // Exclamation dot &::after { top: 0.65em; height: 0.13em; diff --git a/src/Notyf/Prime/Resources/assets/notyf.ts b/src/Notyf/Prime/Resources/assets/notyf.ts index 2951cf41..c91ecfbd 100644 --- a/src/Notyf/Prime/Resources/assets/notyf.ts +++ b/src/Notyf/Prime/Resources/assets/notyf.ts @@ -1,3 +1,8 @@ +/** + * @file Notyf Plugin Implementation + * @description PHPFlasher integration with the Notyf notification library + * @author yoeunes + */ import { AbstractPlugin } from '@flasher/flasher/dist/plugin' import type { Envelope, Options } from '@flasher/flasher/dist/types' @@ -5,49 +10,156 @@ import { Notyf } from 'notyf' import type { INotyfOptions } from 'notyf/notyf.options' import 'notyf/notyf.min.css' +/** + * Plugin implementation for Notyf notification library. + * + * The NotyfPlugin integrates the lightweight Notyf library with PHPFlasher, + * allowing for simple, responsive, and customizable toast notifications. + * + * @example + * ```typescript + * import flasher from '@flasher/flasher'; + * import NotyfPlugin from '@flasher/flasher-notyf'; + * + * // Register the plugin + * flasher.addPlugin('notyf', new NotyfPlugin()); + * + * // Show a notification + * flasher.use('notyf').success('Operation completed'); + * ``` + */ export default class NotyfPlugin extends AbstractPlugin { - notyf?: Notyf + /** + * The Notyf instance used to display notifications. + * Lazy-initialized when first needed. + * + * @private + */ + private notyf?: Notyf + /** + * Creates Notyf notifications from envelopes. + * + * This method transforms PHPFlasher envelopes into Notyf notifications + * and displays them using the Notyf library. + * + * @param envelopes - Array of notification envelopes to render + */ public renderEnvelopes(envelopes: Envelope[]): void { + if (!this.notyf) { + this.initializeNotyf() + } + envelopes.forEach((envelope) => { - const options = { ...envelope, ...envelope.options } - this.notyf?.open(options) + try { + // Merge envelope properties with its options for Notyf compatibility + const options = { ...envelope, ...envelope.options } + this.notyf?.open(options) + } catch (error) { + console.error('PHPFlasher Notyf: Error rendering notification', error, envelope) + } }) - // @ts-expect-error - this.notyf.view.container.dataset.turboTemporary = '' - // @ts-expect-error - this.notyf.view.a11yContainer.dataset.turboTemporary = '' + // Ensure compatibility with Turbo/Hotwire by marking containers + // as temporary elements that should be preserved during page transitions + try { + if (this.notyf) { + // @ts-expect-error - Accessing internal Notyf properties + const container = this.notyf.view.container + // @ts-expect-error - Accessing internal Notyf properties + const a11yContainer = this.notyf.view.a11yContainer + + if (container && container.dataset) { + container.dataset.turboTemporary = '' + } + + if (a11yContainer && a11yContainer.dataset) { + a11yContainer.dataset.turboTemporary = '' + } + } + } catch (error) { + console.error('PHPFlasher Notyf: Error setting Turbo compatibility', error) + } } + /** + * Apply global options to Notyf. + * + * This method configures the Notyf library with the provided options, + * which will affect all subsequently created notifications. It also + * adds support for additional notification types beyond the default + * success and error types. + * + * @param options - Configuration options for Notyf + */ public renderOptions(options: Options): void { - const nOptions = { - duration: options.duration || 5000, + if (!options) { + return + } + + const notyfOptions = { + duration: options.duration || 10000, // Default timeout of 10 seconds ...options, } as unknown as INotyfOptions - nOptions.types = nOptions.types || [] + // Initialize types array if not present + notyfOptions.types = notyfOptions.types || [] - nOptions.types.push({ + // Add support for info notifications with custom icon + this.addTypeIfNotExists(notyfOptions.types, { type: 'info', className: 'notyf__toast--info', - background: '#5784E5', + background: '#5784E5', // Blue color icon: { className: 'notyf__icon--info', tagName: 'i', }, }) - nOptions.types.push({ + // Add support for warning notifications with custom icon + this.addTypeIfNotExists(notyfOptions.types, { type: 'warning', className: 'notyf__toast--warning', - background: '#E3A008', + background: '#E3A008', // Amber color icon: { className: 'notyf__icon--warning', tagName: 'i', }, }) - this.notyf = this.notyf || new Notyf(nOptions as Partial) + // Create or update Notyf instance with new options + this.notyf = this.notyf || new Notyf(notyfOptions) + } + + /** + * Initialize the Notyf instance with default options if not already created. + * + * @private + */ + private initializeNotyf(): void { + if (!this.notyf) { + // Default configuration with info and warning types + this.renderOptions({ + duration: 10000, // 10 seconds + position: { x: 'right', y: 'top' }, + dismissible: true, + }) + } + } + + /** + * Add a notification type to Notyf if it doesn't already exist. + * Prevents duplicate type definitions. + * + * @param types - Array of notification types + * @param newType - New type to add + * @private + */ + private addTypeIfNotExists(types: any[], newType: any): void { + // Check if type already exists + const exists = types.some((type) => type.type === newType.type) + if (!exists) { + types.push(newType) + } } }