fix flasher rtl support

This commit is contained in:
Younes ENNAJI
2025-03-23 14:54:56 +00:00
parent 6d162c7f95
commit 8e6f0e8c88
21 changed files with 114 additions and 32 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"dist/main.css": "/dist/main.cfa0ed56.css", "dist/main.css": "/dist/main.98f9c826.css",
"dist/main.js": "/dist/main.896f6a93.js", "dist/main.js": "/dist/main.8b056786.js",
"dist/455.3a7b4474.css": "/dist/455.3a7b4474.css", "dist/455.3a7b4474.css": "/dist/455.3a7b4474.css",
"dist/455.095e6545.js": "/dist/455.095e6545.js", "dist/455.095e6545.js": "/dist/455.095e6545.js",
"dist/411.29cd993e.css": "/dist/411.29cd993e.css", "dist/411.29cd993e.css": "/dist/411.29cd993e.css",
+18 -8
View File
@@ -146,6 +146,7 @@
<option value="10000">10 seconds</option> <option value="10000">10 seconds</option>
<option value="5000">5 seconds</option> <option value="5000">5 seconds</option>
<option value="3000">3 seconds</option> <option value="3000">3 seconds</option>
<option value="false">Sticky</option>
</select> </select>
<div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-slate-400"> <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-slate-400">
<i class="fas fa-chevron-down text-xs"></i> <i class="fas fa-chevron-down text-xs"></i>
@@ -1038,7 +1039,7 @@ async function checkStatus() {
document.getElementById("title-input").value = state.title || ""; document.getElementById("title-input").value = state.title || "";
document.getElementById("message-input").value = state.message || ""; document.getElementById("message-input").value = state.message || "";
document.getElementById("position-select").value = state.position || ""; document.getElementById("position-select").value = state.position || "";
document.getElementById("timeout-select").value = state.timeout || ""; document.getElementById("timeout-select").value = state.timeout === false ? "false" : (state.timeout || "");
document.getElementById("theme-select").value = state.theme || ""; document.getElementById("theme-select").value = state.theme || "";
document.getElementById("direction-select").value = state.direction || ""; document.getElementById("direction-select").value = state.direction || "";
document.getElementById("rtl-check").checked = !!state.rtl; document.getElementById("rtl-check").checked = !!state.rtl;
@@ -1116,8 +1117,8 @@ async function checkStatus() {
if (state.position) { if (state.position) {
options.position = state.position; options.position = state.position;
} }
if (state.timeout) { if (state.timeout !== undefined && state.timeout !== "") {
options.timeout = parseInt(state.timeout); options.timeout = state.timeout;
} }
if (state.theme) { if (state.theme) {
options.theme = state.theme; options.theme = state.theme;
@@ -1153,8 +1154,9 @@ async function checkStatus() {
if (state.position) { if (state.position) {
lines.push(`${indent} ->option('position', '${state.position}')`); lines.push(`${indent} ->option('position', '${state.position}')`);
} }
if (state.timeout) { if (state.timeout !== undefined && state.timeout !== "") {
lines.push(`${indent} ->option('timeout', ${state.timeout})`); const timeoutValue = state.timeout === false ? 'false' : state.timeout;
lines.push(`${indent} ->option('timeout', ${timeoutValue})`);
} }
if (state.direction) { if (state.direction) {
lines.push(`${indent} ->option('direction', '${state.direction}')`); lines.push(`${indent} ->option('direction', '${state.direction}')`);
@@ -1311,8 +1313,8 @@ async function checkStatus() {
if (state.position) { if (state.position) {
options.position = state.position; options.position = state.position;
} }
if (state.timeout) { if (state.timeout !== undefined && state.timeout !== "") {
options.timeout = parseInt(state.timeout); options.timeout = state.timeout;
} }
if (state.direction) { if (state.direction) {
options.direction = state.direction; options.direction = state.direction;
@@ -1324,6 +1326,8 @@ async function checkStatus() {
options.escapeHtml = state.escapeHtml; options.escapeHtml = state.escapeHtml;
} }
console.log("Showing notification with options:", options);
try { try {
if (typeof flasher !== "undefined") { if (typeof flasher !== "undefined") {
if (state.theme) { if (state.theme) {
@@ -1380,7 +1384,13 @@ async function checkStatus() {
state.position = e.target.value; state.position = e.target.value;
}); });
document.getElementById("timeout-select").addEventListener("change", (e) => { document.getElementById("timeout-select").addEventListener("change", (e) => {
state.timeout = e.target.value ? parseInt(e.target.value) : ""; if (e.target.value === "false") {
state.timeout = false;
} else if (e.target.value) {
state.timeout = parseInt(e.target.value);
} else {
state.timeout = "";
}
}); });
document.getElementById("theme-select").addEventListener("change", (e) => { document.getElementById("theme-select").addEventListener("change", (e) => {
state.theme = e.target.value; state.theme = e.target.value;
+2 -2
View File
@@ -2,10 +2,10 @@
"entrypoints": { "entrypoints": {
"main": { "main": {
"css": [ "css": [
"/dist/main.cfa0ed56.css" "/dist/main.98f9c826.css"
], ],
"js": [ "js": [
"/dist/main.896f6a93.js" "/dist/main.8b056786.js"
] ]
} }
} }
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
-1
View File
File diff suppressed because one or more lines are too long
+38 -2
View File
@@ -60,6 +60,7 @@ export default class FlasherPlugin extends AbstractPlugin {
*/ */
private options: FlasherPluginOptions = { private options: FlasherPluginOptions = {
// Default or type-specific timeout (milliseconds, null = use type-specific) // Default or type-specific timeout (milliseconds, null = use type-specific)
// Use false for sticky notifications, or any negative number
timeout: null, timeout: null,
// Type-specific timeout durations // Type-specific timeout durations
@@ -132,7 +133,7 @@ export default class FlasherPlugin extends AbstractPlugin {
const mergedOptions = { const mergedOptions = {
...this.options, ...this.options,
...envelope.options, ...envelope.options,
timeout: envelope.options.timeout ?? typeTimeout, timeout: this.normalizeTimeout(envelope.options.timeout ?? typeTimeout),
escapeHtml: (envelope.options.escapeHtml ?? this.options.escapeHtml) as boolean, escapeHtml: (envelope.options.escapeHtml ?? this.options.escapeHtml) as boolean,
} }
@@ -271,12 +272,47 @@ export default class FlasherPlugin extends AbstractPlugin {
}) })
} }
// Add timer if timeout is specified // Add timer if timeout is greater than 0 (not sticky)
if (options.timeout > 0) { if (options.timeout > 0) {
this.addTimer(notification, options) this.addTimer(notification, options)
} else {
// For sticky notifications, we might want to add a class
notification.classList.add('fl-sticky')
// For sticky notifications with progress bar, set it to full width
const progressBarContainer = notification.querySelector('.fl-progress-bar')
if (progressBarContainer) {
// Create progress bar element that stays at 100%
const progressBar = document.createElement('span')
progressBar.classList.add('fl-progress', 'fl-sticky-progress')
progressBar.style.width = '100%'
progressBarContainer.append(progressBar)
}
} }
} }
/**
* 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)) {
return 0
}
// Handle null or undefined
if (timeout == null) {
return 0
}
// Convert to number (handles string numbers too)
return Number(timeout) || 0
}
/** /**
* Adds a progress timer to the notification. * Adds a progress timer to the notification.
* *
@@ -31,7 +31,6 @@
* For languages that read from right to left * For languages that read from right to left
*/ */
&.fl-rtl { &.fl-rtl {
direction: rtl;
text-align: right; text-align: right;
} }
} }
@@ -78,8 +78,6 @@
*/ */
@mixin rtl-support { @mixin rtl-support {
&.fl-rtl { &.fl-rtl {
direction: rtl;
.fl-content { .fl-content {
flex-direction: row-reverse; flex-direction: row-reverse;
} }
+1 -1
View File
@@ -365,7 +365,7 @@ export type FlasherPluginOptions = {
* Default timeout in milliseconds (0 for no timeout). * Default timeout in milliseconds (0 for no timeout).
* Set to null to use type-specific timeouts. * Set to null to use type-specific timeouts.
*/ */
timeout: number | null timeout: number | boolean | null
/** Type-specific timeouts in milliseconds */ /** Type-specific timeouts in milliseconds */
timeouts: Record<string, number> timeouts: Record<string, number>
+1
View File
@@ -9,6 +9,7 @@ export default class FlasherPlugin extends AbstractPlugin {
renderOptions(options: Options): void; renderOptions(options: Options): void;
private createContainer; private createContainer;
private addToContainer; private addToContainer;
private normalizeTimeout;
private addTimer; private addTimer;
private removeNotification; private removeNotification;
private stringToHTML; private stringToHTML;
+20 -1
View File
@@ -153,7 +153,7 @@ class FlasherPlugin extends AbstractPlugin {
var _a, _b, _c, _d; var _a, _b, _c, _d;
try { try {
const typeTimeout = (_b = (_a = this.options.timeout) !== null && _a !== void 0 ? _a : this.options.timeouts[envelope.type]) !== null && _b !== void 0 ? _b : 10000; const typeTimeout = (_b = (_a = this.options.timeout) !== null && _a !== void 0 ? _a : this.options.timeouts[envelope.type]) !== null && _b !== void 0 ? _b : 10000;
const mergedOptions = Object.assign(Object.assign(Object.assign({}, this.options), envelope.options), { timeout: (_c = envelope.options.timeout) !== null && _c !== void 0 ? _c : typeTimeout, escapeHtml: ((_d = envelope.options.escapeHtml) !== null && _d !== void 0 ? _d : this.options.escapeHtml) }); const mergedOptions = Object.assign(Object.assign(Object.assign({}, this.options), envelope.options), { timeout: this.normalizeTimeout((_c = envelope.options.timeout) !== null && _c !== void 0 ? _c : typeTimeout), escapeHtml: ((_d = envelope.options.escapeHtml) !== null && _d !== void 0 ? _d : this.options.escapeHtml) });
const container = this.createContainer(mergedOptions); const container = this.createContainer(mergedOptions);
const containerOptions = { const containerOptions = {
direction: mergedOptions.direction, direction: mergedOptions.direction,
@@ -225,6 +225,25 @@ class FlasherPlugin extends AbstractPlugin {
if (options.timeout > 0) { if (options.timeout > 0) {
this.addTimer(notification, options); this.addTimer(notification, options);
} }
else {
notification.classList.add('fl-sticky');
const progressBarContainer = notification.querySelector('.fl-progress-bar');
if (progressBarContainer) {
const progressBar = document.createElement('span');
progressBar.classList.add('fl-progress', 'fl-sticky-progress');
progressBar.style.width = '100%';
progressBarContainer.append(progressBar);
}
}
}
normalizeTimeout(timeout) {
if (timeout === false || (typeof timeout === 'number' && timeout < 0)) {
return 0;
}
if (timeout == null) {
return 0;
}
return Number(timeout) || 0;
} }
addTimer(notification, { timeout, fps }) { addTimer(notification, { timeout, fps }) {
if (timeout <= 0) { if (timeout <= 0) {
+20 -1
View File
@@ -159,7 +159,7 @@
var _a, _b, _c, _d; var _a, _b, _c, _d;
try { try {
const typeTimeout = (_b = (_a = this.options.timeout) !== null && _a !== void 0 ? _a : this.options.timeouts[envelope.type]) !== null && _b !== void 0 ? _b : 10000; const typeTimeout = (_b = (_a = this.options.timeout) !== null && _a !== void 0 ? _a : this.options.timeouts[envelope.type]) !== null && _b !== void 0 ? _b : 10000;
const mergedOptions = Object.assign(Object.assign(Object.assign({}, this.options), envelope.options), { timeout: (_c = envelope.options.timeout) !== null && _c !== void 0 ? _c : typeTimeout, escapeHtml: ((_d = envelope.options.escapeHtml) !== null && _d !== void 0 ? _d : this.options.escapeHtml) }); const mergedOptions = Object.assign(Object.assign(Object.assign({}, this.options), envelope.options), { timeout: this.normalizeTimeout((_c = envelope.options.timeout) !== null && _c !== void 0 ? _c : typeTimeout), escapeHtml: ((_d = envelope.options.escapeHtml) !== null && _d !== void 0 ? _d : this.options.escapeHtml) });
const container = this.createContainer(mergedOptions); const container = this.createContainer(mergedOptions);
const containerOptions = { const containerOptions = {
direction: mergedOptions.direction, direction: mergedOptions.direction,
@@ -231,6 +231,25 @@
if (options.timeout > 0) { if (options.timeout > 0) {
this.addTimer(notification, options); this.addTimer(notification, options);
} }
else {
notification.classList.add('fl-sticky');
const progressBarContainer = notification.querySelector('.fl-progress-bar');
if (progressBarContainer) {
const progressBar = document.createElement('span');
progressBar.classList.add('fl-progress', 'fl-sticky-progress');
progressBar.style.width = '100%';
progressBarContainer.append(progressBar);
}
}
}
normalizeTimeout(timeout) {
if (timeout === false || (typeof timeout === 'number' && timeout < 0)) {
return 0;
}
if (timeout == null) {
return 0;
}
return Number(timeout) || 0;
} }
addTimer(notification, { timeout, fps }) { addTimer(notification, { timeout, fps }) {
if (timeout <= 0) { if (timeout <= 0) {
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -39,7 +39,7 @@ export type Asset = {
type: AssetType; type: AssetType;
}; };
export type FlasherPluginOptions = { export type FlasherPluginOptions = {
timeout: number | null; timeout: number | boolean | null;
timeouts: Record<string, number>; timeouts: Record<string, number>;
fps: number; fps: number;
position: string; position: string;
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long