Re: [w3ctag/design-reviews] Shared Element Transitions API (Issue #748)

> I understand, but the callback model makes this very annoying to use w/ progressive enhancement
> Branching is still possible with this API, but very cumbersome and boilerplatey:

In the simple case, we're talking:

```js
function spaNavigate(data) {
  // Fallback for browsers that don't support this API:
  if (!self.SameDocumentTransition || !animationsEnabled) {
    updateTheDOMSomehow(data);
    return;
  }

  const transition = new SameDocumentTransition();
  transition.prepare(() => updateTheDOMSomehow(data));
}
```

Vs:

```js
async function spaNavigate(data) {
  const transition =
    animationsEnabled && self.SameDocumentTransition
      ? new SameDocumentTransition()
      : null;
  await transition?.captureBeforeState();
  await updateTheDOMSomehow();
  transition?.domChanged();
}
```

(both examples formatted with https://prettier.io/)

I'm not sure the latter is less cumbersome. Every time you interact with `transition?`, you need to think about the 'null' case too.

Once you start adding more transition-specific script:

```js
thumbnail.onclick = () => {
  if (!self.SameDocumentTransition || !animationsEnabled) {
    updateTheDOMSomehow(data);
    return;
  }
  const transition = new SameDocumentTransition();
  thumbnail.style.pageTransitionTag = "full-embed";
  transition.prepare(() => {
    thumbnail.style.pageTransitionTag = "";
    updateTheDOMSomehow();
  });
};
```

Vs:

```js
thumbnail.onclick = async () => {
  const transition =
    animationsEnabled && self.SameDocumentTransition
      ? new SameDocumentTransition()
      : null;
  thumbnail.style.pageTransitionTag = 'full-embed';
  await transition?.captureBeforeState();
  thumbnail.style.pageTransitionTag = '';
  updateTheDOMSomehow();
  transition?.domChanged();
};
```

Again, this doesn't seem particularly better, and now you're running steps that are for transitions, even in cases where you're not actually wanting a transition. In this case it's a no-op, but as the author and the reader, you need to think that through. Or, alternatively, avoid those steps if it isn't a transition:

```js
thumbnail.onclick = async () => {
  const transition =
    animationsEnabled && self.SameDocumentTransition
      ? new SameDocumentTransition()
      : null;
  if (transition) {
    thumbnail.style.pageTransitionTag = 'full-embed';
  }
  await transition?.captureBeforeState();
  if (transition) {
    thumbnail.style.pageTransitionTag = '';
  }
  updateTheDOMSomehow();
  transition?.domChanged();
};
```

And now this is looking much more complicated than the first example. Things get worse still when you're wanting to also control parts of the transition with script. And still, there's the timeout issue if the DOM change throws.

> and the Web Platform in general is trying to move away from callback-based APIs.

This is news to me, and I'm not sure it's true. Cases where an API wants to know the async result of a developer action are commonly callbacks.

Some modern examples:

- The [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) constructor callback.
- [The transformer of transform streams](https://streams.spec.whatwg.org/#dictdef-transformer), in particular the `flush` callback.
- The `handler` callback in the [navigation API](https://wicg.github.io/navigation-api/#ref-for-dom-navigateevent-intercept%E2%91%A0%E2%91%A3).
- [Web locks API](https://w3c.github.io/web-locks/#api-lock-manager) lock granted callback.

These kinds of cases don't really make sense as promises, because it isn't purely waiting for a response from the API, it's also providing a response _to_ the API. These kinds of cases don't really make sense as events either, since they only really have one listener, and the response may be async. 

> Having the rendering be frozen until a timeout could not be such a dealbreaker if the timeout is explicitly specified when creating the transition? After all, DOM manipulation is not a lengthy process (compared to e.g. network requests), so you'd likely need a very small timeout, smaller than the threshold of a lag that is perceptible by humans (60ms)

That kind of lag is acceptable when it comes to reaction to a click, but pausing animations for 60ms is very noticable. So if the DOM change actually failed in 5ms, I'd rather not have a 60ms lag.

> You could also take a signal to abort the operation, [which is good practice anyway](https://w3ctag.github.io/design-principles/#aborting).

We currently have an `.abandon()` method on transitions, but I want to rename this `.skipTransition()`, or something that communicates that only the transition will be skipped, it won't skip the DOM change (unless you skip that in some other way).

One of the mistakes we made in some of the earlier designs of this API is trying to be a scheduler for the DOM change, but I think we really need to focus on transitions only. The Navigation API provides an abort signal for abandoning DOM changes, and frameworks that perform DOM changes asynchronously already have their own scheduling systems.

> Note that the current API can still cause rendering to freeze, if you await a promise that never resolves.

Yeah, although it's generally only faulty promises that do that. Those cases are caught by the timeout. But I'd rather not rely on the timeout for cases where the error can be easily caught.

> I’m sure it's _possible_ with every framework, but it's yet another obstacle for authors to figure out which advanced framework feature would do this. E.g. off the top of my head I cannot think of how to reliably do this with Vue, at least not without heuristics and hacks.

I've never written anything in Vue before, but I can try and cook up a demo. Do you have an example of how you'd use something like `ResizeObserver` with Vue? That would give me a good start I think.

-- 
Reply to this email directly or view it on GitHub:
https://github.com/w3ctag/design-reviews/issues/748#issuecomment-1225922770

You are receiving this because you are subscribed to this thread.

Message ID: <w3ctag/design-reviews/issues/748/1225922770@github.com>

Received on Wednesday, 24 August 2022 16:01:15 UTC