1
0
mirror of https://github.com/home-assistant/frontend.git synced 2025-12-20 02:38:53 +00:00

Attempt to ensure view transitions are always ran (#28547)

This commit is contained in:
Aidan Timson
2025-12-15 10:24:50 +00:00
committed by GitHub
parent 81cb483163
commit 54e4f4e60a

View File

@@ -1,30 +1,45 @@
/** /**
* Executes a callback within a View Transition if supported, otherwise runs it directly. * Executes a synchronous callback within a View Transition if supported, otherwise runs it directly.
* *
* @param callback - Function to execute. Can be synchronous or return a Promise. The callback will be passed a boolean indicating whether the view transition is available. * @param callback - Synchronous function to execute. The callback will be passed a boolean indicating whether the view transition is available.
* @returns Promise that resolves when the transition completes (or immediately if not supported) * @returns Promise that resolves when the transition completes (or immediately if not supported)
* *
* @example * @example
* ```typescript * ```typescript
* // Synchronous callback
* withViewTransition(() => { * withViewTransition(() => {
* this.large = !this.large; * this.large = !this.large;
* }); * });
*
* // Async callback
* await withViewTransition(async () => {
* await this.updateData();
* });
* ``` * ```
*/ */
export const withViewTransition = ( export const withViewTransition = (
callback: (viewTransitionAvailable: boolean) => void | Promise<void> callback: (viewTransitionAvailable: boolean) => void
): Promise<void> => { ): Promise<void> => {
if (document.startViewTransition) { if (!document.startViewTransition) {
return document.startViewTransition(() => callback(true)).finished; callback(false);
return Promise.resolve();
} }
// Fallback: Execute callback directly without transition let callbackInvoked = false;
const result = callback(false);
return result instanceof Promise ? result : Promise.resolve(); try {
// View Transitions require DOM updates to happen synchronously within
// the callback. Execute the callback immediately (synchronously).
const transition = document.startViewTransition(() => {
callbackInvoked = true;
callback(true);
});
return transition.finished;
} catch (err) {
// eslint-disable-next-line no-console
console.warn(
"View transition failed, falling back to direct execution.",
err
);
// Make sure the callback is invoked exactly once.
if (!callbackInvoked) {
callback(false);
return Promise.resolve();
}
return Promise.reject(err);
}
}; };