fix(widgets): harden minimize transitionend with fallback and property filter
- Filter transitionend by propertyName=opacity to prevent double-fire - Add 350ms fallback setTimeout for prefers-reduced-motion / zero-duration - Initialize _minimizing: false in create() for clean state - Dispatch events after save() for consistent state in listeners Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+22
-7
@@ -52,7 +52,7 @@ const WidgetManager = {
|
||||
const el = this._buildDOM(state);
|
||||
document.body.appendChild(el);
|
||||
|
||||
this._widgets.set(id, { el, type, state });
|
||||
this._widgets.set(id, { el, type, state, _minimizing: false });
|
||||
this._initDrag(el);
|
||||
this._initResize(el);
|
||||
this.bringToFront(id);
|
||||
@@ -170,7 +170,9 @@ const WidgetManager = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Widget minimieren (aus DOM verstecken, bleibt im Notebook)
|
||||
* Widget minimieren (aus DOM verstecken, bleibt im Notebook).
|
||||
* Nutzt transitionend statt setTimeout — _minimizing Flag verhindert Race Condition
|
||||
* mit openWidget(). Fallback-Timer fuer prefers-reduced-motion / fehlende Transition.
|
||||
* @param {string} id
|
||||
*/
|
||||
async minimize(id) {
|
||||
@@ -180,17 +182,30 @@ const WidgetManager = {
|
||||
entry._minimizing = true;
|
||||
entry.el.classList.add('widget-minimized');
|
||||
|
||||
entry.el.addEventListener('transitionend', function onEnd(e) {
|
||||
if (e.target !== entry.el) return;
|
||||
const MINIMIZE_FALLBACK_MS = 350;
|
||||
|
||||
function onEnd(e) {
|
||||
if (e.target !== entry.el || e.propertyName !== 'opacity') return;
|
||||
clearTimeout(fallbackTimer);
|
||||
entry.el.removeEventListener('transitionend', onEnd);
|
||||
if (entry._minimizing) {
|
||||
entry.el.style.display = 'none';
|
||||
}
|
||||
entry._minimizing = false;
|
||||
});
|
||||
}
|
||||
|
||||
entry.el.addEventListener('transitionend', onEnd);
|
||||
|
||||
const fallbackTimer = setTimeout(() => {
|
||||
entry.el.removeEventListener('transitionend', onEnd);
|
||||
if (entry._minimizing) {
|
||||
entry.el.style.display = 'none';
|
||||
entry._minimizing = false;
|
||||
}
|
||||
}, MINIMIZE_FALLBACK_MS);
|
||||
|
||||
this._emitter.dispatchEvent(new CustomEvent('widget:minimize', { detail: { id } }));
|
||||
await this.save();
|
||||
this._emitter.dispatchEvent(new CustomEvent('widget:minimize', { detail: { id } }));
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -207,8 +222,8 @@ const WidgetManager = {
|
||||
entry.el.classList.remove('widget-minimized');
|
||||
});
|
||||
this.bringToFront(id);
|
||||
this._emitter.dispatchEvent(new CustomEvent('widget:open', { detail: { id } }));
|
||||
await this.save();
|
||||
this._emitter.dispatchEvent(new CustomEvent('widget:open', { detail: { id } }));
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user