import{type PropertyValues,type TemplateResult}from'lit';import{LyraElement}from'../../../internal/lyra-element.js';export interface LyraAnimatedImageEventMap{'lr-load':CustomEvent;'lr-error':CustomEvent;'lr-play':CustomEvent;'lr-pause':CustomEvent;blur:FocusEvent;focus:FocusEvent;} /** * `` -- displays an animated GIF/APNG/WebP with a * play/pause control, defaulting to a frozen first frame both at rest and * automatically under `prefers-reduced-motion: reduce` (unless the page * author explicitly opts back in via `respect-reduced-motion="false"`), so * motion is never forced on a user who asked for less of it. * * **Freeze-frame mechanism.** The live ``'s `load` event handler * synchronously draws the just-loaded image to `[part="canvas"]` (a * DPR-aware `drawImage()`, the same pattern `` uses for its own * canvas sizing) before any animation frames have had a chance to advance. * That captured frame is what pausing always reverts to -- it is not * re-captured on every pause, only once per successful `src` load. Both * `[part="image"]` and `[part="canvas"]` stay mounted at all times (never * `display: none`/removed) so the browser's native decode loop keeps running * even while visually covered by the frozen canvas; only opacity and * `aria-hidden` swap between them, driven by the effective `playing` state. * * **`play` vs. `playing`.** `play` is the caller's intent (settable and * reflected). `playing` is the read-only, reflected effect * after reduced-motion arbitration: `play && !(respectReducedMotion && * )`. A page can set `.play = true` while * reduced motion still keeps the visual frozen -- `lr-play`/`lr-pause` * only fire on a real transition of the resolved `playing` value, never on a * `play` assignment that reduced motion blocks from taking visible effect. * * **Safety.** `src` is re-validated through `safeMediaSrc()` (the same * allowlist `` uses) before it is ever assigned to the real * ``. An empty `src` renders no `src` attribute and is not an * error; a non-empty `src` that fails the check is treated exactly like a * native image decode failure -- `lr-error` fires and no request is ever * attempted. * * **Alternative text follows native image presence semantics.** An absent or explicitly empty * `alt` keeps the image and frozen canvas decorative, matching the mirrored components. A * nonempty value names whichever of those two mutually-exclusive visual owners is exposed. The * play/pause button remains independently named with localized action text. * * Lyra deliberately adds a reduced-motion safety policy and a bounded `--lr-animated-image-max-height` * default beyond the mirrored components. Set `respect-reduced-motion="false"` when preserving * upstream playback under a reduced-motion preference is required, and override the max-height * hook with `none` when the upstream unconstrained block-size is required. * * Deliberately no label/hint/error chrome -- this is not a form-associated * control (nothing resembling a value the user submits). * * @customElement lr-animated-image * @slot play-icon - Decorative custom play glyph shown while frozen/paused. Rendered in an inert, * aria-hidden, pointer-transparent sibling layer over the play/pause button. * @slot pause-icon - Decorative custom pause glyph shown while playing. Rendered through the same * inert sibling layer. * @event lr-load - The live `` finished loading. Fires again on every successful subsequent `src` change. * @event lr-error - The live `` failed to load, or `src` was non-empty but failed the safe-URL check. Never fires for an empty `src`. * @event lr-play - The effective `playing` state transitioned `false` -> `true`. * @event lr-pause - The effective `playing` state transitioned `true` -> `false` (including a reduced-motion change forcing a freeze while `play` stays `true`). * @event {FocusEvent} blur - Relayed once from the internal play/pause button as a bubbling, * composed native event. * @event {FocusEvent} focus - Relayed once from the internal play/pause button as a bubbling, * composed native event. * @csspart base - Root wrapper; positioning context for `control-box`. * @csspart image - The live ``. * @csspart canvas - The frozen-frame ``, shown in place of `image` while not playing. * @csspart control-box - The container that surrounds and backgrounds the play/pause button. Only rendered once loaded and error-free. * @csspart play-button - The `