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,12 +1,16 @@
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 = ( export const removeLaunchScreen = () => {
launchScreenElement: HTMLElement, const launchScreenElement = document.getElementById("ha-launch-screen");
skipAnimation: boolean if (!launchScreenElement?.parentElement) {
) => { return;
if (skipAnimation) { }
withViewTransition((viewTransitionAvailable: boolean) => {
if (!viewTransitionAvailable) {
launchScreenElement.parentElement?.removeChild(launchScreenElement); launchScreenElement.parentElement?.removeChild(launchScreenElement);
return; return;
} }
@@ -20,22 +24,7 @@ const removeElement = (
setTimeout(() => { setTimeout(() => {
launchScreenElement.parentElement?.removeChild(launchScreenElement); launchScreenElement.parentElement?.removeChild(launchScreenElement);
}, parseAnimationDuration(durationFromCss)); }, parseAnimationDuration(durationFromCss));
};
export const removeLaunchScreen = () => {
const launchScreenElement = document.getElementById("ha-launch-screen");
if (!launchScreenElement?.parentElement) {
return;
}
if (document.startViewTransition) {
document.startViewTransition(() => {
removeElement(launchScreenElement, false);
}); });
} else {
// Fallback: Direct removal without transition
removeElement(launchScreenElement, true);
}
}; };
export const renderLaunchScreenInfoBox = (content: TemplateResult) => { export const renderLaunchScreenInfoBox = (content: TemplateResult) => {