diff --git a/.changeset/tidy-parents-explain.md b/.changeset/tidy-parents-explain.md new file mode 100644 index 0000000..e95b234 --- /dev/null +++ b/.changeset/tidy-parents-explain.md @@ -0,0 +1,11 @@ +--- +'@vtbag/element-crossing': patch +--- + +Extend `anim` expression with support for SVG animations. + +To transfer the SVG animation state to the new document use the `/svg` key for the `anim` expression + +```html +... +``` diff --git a/src/vanilla.ts b/src/vanilla.ts index ffc496e..bb4a3f4 100644 --- a/src/vanilla.ts +++ b/src/vanilla.ts @@ -1,6 +1,7 @@ import { ElementSpec, Spec } from './types'; const DEBUG = false; +const SVG_ANIM_KEY = '/svg'; const crossing = top!.__vtbag?.elementCrossing; init(); @@ -147,18 +148,34 @@ function elementSpec(element: HTMLElement) { }); break; case 'anim': - const animations = element - .getAnimations() - .filter((a) => a instanceof CSSAnimation && a.animationName === key); - if (animations.length > 1) { - console.error( - '[crossing]', - `retrieval: animation name ${key} is not unique for`, - element - ); - } - if (animations.length > 0) { - specs.push({ kind, key, value: '' + (animations[0].currentTime ?? 0) }); + if (key === SVG_ANIM_KEY) { + if (!(element instanceof SVGSVGElement)) { + console.error( + '[crossing]', + `retrieval: element is not an SVG element, but "${key}" was used for its key`, + element + ); + break; + } + + const currentTime = element.getCurrentTime(); + if (currentTime > 0) { + specs.push({ kind, key, value: currentTime.toString() }); + } + } else { + const animations = element + .getAnimations() + .filter((a) => a instanceof CSSAnimation && a.animationName === key); + if (animations.length > 1) { + console.error( + '[crossing]', + `retrieval: animation name ${key} is not unique for`, + element + ); + } + if (animations.length > 0) { + specs.push({ kind, key, value: '' + (animations[0].currentTime ?? 0) }); + } } break; case 'elem': @@ -218,21 +235,35 @@ function restore(values: ElementSpec[]) { (element as any)[s.key] = parseFloat(s.value ?? '0'); break; case 'anim': - const animations = element! - .getAnimations() - .filter((a) => a instanceof CSSAnimation && a.animationName === s.key); - if (animations.length > 1) { - console.warn( - '[crossing]', - `restore: animation name ${s.key} is not unique for`, - element + if (s.key === SVG_ANIM_KEY) { + if (!(element instanceof SVGSVGElement)) { + console.error( + '[crossing]', + `restore: element for key ${s.key} is not an SVG element`, + element + ); + break; + } + element.setCurrentTime( + parseFloat(s.value ?? '0') + (new Date().getTime() - elementSpec.timestamp) / 1000 + ); + } else { + const animations = element! + .getAnimations() + .filter((a) => a instanceof CSSAnimation && a.animationName === s.key); + if (animations.length > 1) { + console.warn( + '[crossing]', + `restore: animation name ${s.key} is not unique for`, + element + ); + } + animations.forEach( + (a) => + (a.currentTime = + ~~(s.value ?? '0') + (new Date().getTime() - elementSpec.timestamp)) ); } - animations.forEach( - (a) => - (a.currentTime = - ~~(s.value ?? '0') + (new Date().getTime() - elementSpec.timestamp)) - ); break; case 'elem': const crossing = top?.__vtbag?.elementCrossing;