The loading indicator *should* fade in after two seconds, to avoid a
flash of a loading indicator when the page loads quickly - but in some
circumstances it wouldn't delay:
1. Visit an item page. (It delays correctly the first time!)
2. Click "Infinite Closet", then click a link to another item page.
3. The loading indicator appears immediately, because this time the
web component JS is already loaded, so the `outfit-layer` elements
enter `:state(loading)` *immediately*. The element starts at
`opacity: 1`, and the delay doesn't matter, because it was never at
anything else.
In this change, we have the `outfit-viewer` web component take on a
`:state(after-first-frame)`, after a `setTimeout(0)` resolves. That
enables the loading state CSS to *never* apply on the first frame, but
then sometimes kick in on the *second* frame, so that the element is
correctly perceived as "transitioning" from hidden to visible, and the
two-second delay will apply.
For static image layers, this was *always* logging that we failed to
send the frame a "pause" message. Which, like, of course!
It makes sense to log the notable circumstance where we send a message
we *expect* to arrive, but the frame isn't loaded yet. But if there's
just no frame, ignore it and don't bother to say so.
I thiiiink I've seen the status of a movie `<outfit-layer>` sometimes
be `loading` even when it's clearly already loaded and running. I
haven't been able to track down where and how that happens exactly, so
this is me acting on a hunch: that maybe the
I-would-have-thought-very-unlikely event that the iframe finishes
loading before the `<outfit-layer>` connects with its children maybe
happens more often than one might think!
In this change, we set up the iframe to receive `requestStatus`
messages, which it responds to with the status immediately. And we send
one of these when the `<outfit-layer>` first discovers the iframe.
Fingers crossed!
This doesn't do a good job maintaining state across morphs, but hey
it's Working At All in terms of wiring, and that's good!!
Also need to style up the toggle as a cute button instead of a visible
checkbox and the words "Play/pause"!
This is a nice extra error handler to have, but note that it *won't*
catch the case where the iframe successfully loads but the page returns
a bad status code. In this case, we'll just show the loading state
forever.
The most notable thing here is that we keep the movie iframes running!
So if you're trying different pets for an animated item, the animation
keeps going while the new pet layers load alongside it.
This is also nice for like, the species/color picker form, so we're not
taking away input elements from people who depend on e.g. keyboard
focus.
Oh right okay, attributes like `status="loading"` are more of an API
for the caller, whereas the internal state API is where you wanna put
things that are meant to be used in CSS selectors and stuff.
Instead of doing all this listening to Turbo events etc to know when
outfit layers might have changed, making it a custom element and wiring
in the behavior to its actual lifecycle makes it always Just Work!