Create withViewTransition wrapper function (#27918)

* Create withViewTransition wrapper function

* Add missing space

* Remove function, check for view transition, add param

* Document
This commit is contained in:
Aidan Timson
2025-11-13 15:32:15 +00:00
committed by GitHub
parent 09bdfd3ad7
commit 81c27090d2
3 changed files with 48 additions and 28 deletions

View File

@@ -0,0 +1,30 @@
/**
* Executes a 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.
* @returns Promise that resolves when the transition completes (or immediately if not supported)
*
* @example
* ```typescript
* // Synchronous callback
* withViewTransition(() => {
* this.large = !this.large;
* });
*
* // Async callback
* await withViewTransition(async () => {
* await this.updateData();
* });
* ```
*/
export const withViewTransition = (
callback: (viewTransitionAvailable: boolean) => void | Promise<void>
): Promise<void> => {
if (document.startViewTransition) {
return document.startViewTransition(() => callback(true)).finished;
}
// Fallback: Execute callback directly without transition
const result = callback(false);
return result instanceof Promise ? result : Promise.resolve();
};

View File

@@ -55,6 +55,7 @@ export const coreStyles = css`
--ha-shadow-spread-sm: 0; --ha-shadow-spread-sm: 0;
--ha-shadow-spread-md: 0; --ha-shadow-spread-md: 0;
--ha-shadow-spread-lg: 0; --ha-shadow-spread-lg: 0;
--ha-animation-base-duration: 350ms; --ha-animation-base-duration: 350ms;
} }

View File

@@ -1,26 +1,7 @@
import type { TemplateResult } from "lit"; import type { TemplateResult } from "lit";
import { render } from "lit"; import { render } from "lit";
import { parseAnimationDuration } from "../common/util/parse-animation-duration"; import { parseAnimationDuration } from "../common/util/parse-animation-duration";
import { withViewTransition } from "../common/util/view-transition";
const removeElement = (
launchScreenElement: HTMLElement,
skipAnimation: boolean
) => {
if (skipAnimation) {
launchScreenElement.parentElement?.removeChild(launchScreenElement);
return;
}
launchScreenElement.classList.add("removing");
const durationFromCss = getComputedStyle(document.documentElement)
.getPropertyValue("--ha-animation-base-duration")
.trim();
setTimeout(() => {
launchScreenElement.parentElement?.removeChild(launchScreenElement);
}, parseAnimationDuration(durationFromCss));
};
export const removeLaunchScreen = () => { export const removeLaunchScreen = () => {
const launchScreenElement = document.getElementById("ha-launch-screen"); const launchScreenElement = document.getElementById("ha-launch-screen");
@@ -28,14 +9,22 @@ export const removeLaunchScreen = () => {
return; return;
} }
if (document.startViewTransition) { withViewTransition((viewTransitionAvailable: boolean) => {
document.startViewTransition(() => { if (!viewTransitionAvailable) {
removeElement(launchScreenElement, false); launchScreenElement.parentElement?.removeChild(launchScreenElement);
}); return;
} else { }
// Fallback: Direct removal without transition
removeElement(launchScreenElement, true); launchScreenElement.classList.add("removing");
}
const durationFromCss = getComputedStyle(document.documentElement)
.getPropertyValue("--ha-animation-base-duration")
.trim();
setTimeout(() => {
launchScreenElement.parentElement?.removeChild(launchScreenElement);
}, parseAnimationDuration(durationFromCss));
});
}; };
export const renderLaunchScreenInfoBox = (content: TemplateResult) => { export const renderLaunchScreenInfoBox = (content: TemplateResult) => {