feat(component): startScopedViewTranstion func to support scoped view transition (#8093)

AF-1293
This commit is contained in:
CatsJuice
2024-09-05 06:45:29 +00:00
parent 73dd1d3326
commit 03c2051926
7 changed files with 72 additions and 26 deletions
@@ -1 +1,2 @@
export * from './observe-resize';
export { startScopedViewTransition } from './view-transition';
@@ -9,8 +9,9 @@ let _resizeObserver: ResizeObserver | null = null;
const elementsMap = new WeakMap<Element, Array<ObserveResize>>();
// for debugging
(window as any)._resizeObserverElementsMap = elementsMap;
if (typeof window !== 'undefined') {
(window as any)._resizeObserverElementsMap = elementsMap;
}
/**
* @internal get or initialize the ResizeObserver instance
*/
@@ -0,0 +1,37 @@
const setScope = (scope: string) =>
document.body.setAttribute(`data-${scope}`, '');
const rmScope = (scope: string) =>
document.body.removeAttribute(`data-${scope}`);
/**
* A wrapper around `document.startViewTransition` that adds a scope attribute to the body element.
*/
export function startScopedViewTransition(
scope: string | string[],
cb: () => Promise<void> | void,
options?: { timeout?: number }
) {
if (typeof document === 'undefined') return;
if (typeof document.startViewTransition === 'function') {
const scopes = Array.isArray(scope) ? scope : [scope];
const timeout = options?.timeout ?? 2000;
scopes.forEach(setScope);
const vt = document.startViewTransition(cb);
const timeoutPromise = new Promise<void>((_, reject) => {
setTimeout(() => reject(new Error('View transition timeout')), timeout);
});
Promise.race([vt.finished, timeoutPromise])
.catch(err => console.error(`View transition[${scope}] failed: ${err}`))
.finally(() => scopes.forEach(rmScope));
} else {
cb()?.catch(console.error);
}
}
export function vtScopeSelector(scope: string) {
return `[data-${scope}]`;
}