Skip to content

Commit

Permalink
[css-view-transitions-2] Apply new @view-transition rule syntax (#9523)
Browse files Browse the repository at this point in the history
* [css-view-transitions-2] Apply new CSS rule syntax

- Use the `@view-transition { navigation: auto | none; type: ... }` syntax as per the resolution
- `type: none` means that type is unspecified, needs a resolution
- reloads are ignored as per previous resolution
- Renamed the JS param "type" instead of "types"
- Currently types are resolved both at old and new document
  separately, this needs a resolution.

Closes #9383

See resolution: #9383 (comment)

* Make resolving the inbound transition a separate algo

* Extract algo that is to be used by HTML spec

* Clean up spec, improve names
  • Loading branch information
noamr authored Oct 26, 2023
1 parent 38c5b51 commit d6c50e9
Showing 1 changed file with 86 additions and 56 deletions.
142 changes: 86 additions & 56 deletions css-view-transitions-2/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ urlPrefix: https://wicg.github.io/navigation-api/; type: interface;
1. Once it's time to [=unload=] the old document, if the navigation is [=same origin=]
and the old {{Document}} has opted in to cross-document view-transitions, the old state is captured.

1. An event named {{RevealEvent|reveal}} is fired on the new {{Document}}, with a `viewTransition` property,
1. An event named {{PageRevealEvent|reveal}} is fired on the new {{Document}}, with a `viewTransition` property,
which is a {{ViewTransition}} object. This {{ViewTransition}}'s <code>{{ViewTransition/updateCallbackDone}}</code> is already resolved,
and its [=captured elements=] are populated from the old {{Document}}.

Expand All @@ -137,8 +137,8 @@ urlPrefix: https://wicg.github.io/navigation-api/; type: interface;

```css
// in both documents:
@view-transition same-origin {
trigger: navigation;
@view-transition {
navigation: auto;
}
```

Expand All @@ -153,12 +153,12 @@ urlPrefix: https://wicg.github.io/navigation-api/; type: interface;

- Opt-in to navigation-triggered view-transitions in both pages.
- Pass the click location to the new document, e.g. via {{WindowSessionStorage/sessionStorage}}.
- Intercept the {{ViewTransition}} object in the new document, using the {{RevealEvent}}.
- Intercept the {{ViewTransition}} object in the new document, using the {{PageRevealEvent}}.

In both pages:
```css
@view-transition same-origin {
trigger: navigation;
@view-transition {
navigation: auto;
}

```
Expand Down Expand Up @@ -263,72 +263,81 @@ document.startViewTransition({update: updateTheDOMSomehow});

The ''@view-transition'' rule is used by a document to indicate that cross-document navigations
should setup and activate a {{ViewTransition}}. To take effect, it must be present in the old document
when unloading, and in the new document when it is [=ready to render=].
when unloading, and in the new document when it is [=reveal=].


## @view-transition rule grammar ## {#view-transition-grammar}

The ''@view-transition'' rule has the following syntax:

<pre class=prod>
@view-transition same-origin {
@view-transition {
<<declaration-rule-list>>
}
</pre>

Note: currently <code>same-origin</code> has to be present, as a future placeholder for customizing
the navigation behavior based on the URL.

Note: as per default behavior, the ''@view-transition'' rule can be nested inside a
[=conditional group rule=] such as ''@media'' or ''@supports''.

## The [=@view-transition/trigger=] property ## {#view-transition-trigger-descriptor}
## The [=@view-transition/navigation=] descriptor ## {#view-transition-navigation-descriptor}

<pre class='descdef'>
Name: trigger
Name: navigation
For: @view-transition
Value: navigation | none
Value: auto | none
Initial: none
</pre>

The '<dfn for="@view-transition">trigger</dfn>' property opts in to automatically starting a view transition when performing a navigation.
It needs to be enabled both in the old document (when unloading) and in the new document (when ready to render).
The '<dfn for="@view-transition">navigation</dfn>' descriptor opts in to automatically starting a view transition when performing a navigation of a certain type.
It needs to be enabled both in the old document (when unloading) and in the new document (when reveal).

<dl dfn-type=value dfn-for="trigger">
<dl dfn-type=value dfn-for="@view-transition/navigation">
: <dfn>none</dfn>
:: There will be no transition.

: <dfn>navigation</dfn>
: <dfn>auto</dfn>
:: The transition will be enabled if the navigation is same-origin, without cross-origin
redirects.
redirects, and is not a {{NavigationType/reload}}.
</dl>

## The [=@view-transition/type=] descriptor ## {#view-transition-type-descriptor}

<pre class='descdef'>
Name: type
For: @view-transition
Value: <<custom-ident>>+
Initial: n/a
</pre>

The '<dfn for="@view-transition">type</dfn>' descriptor sets the [=ViewTransition/active types=] for the transition
when capturing and performing the transition, equivalent to calling {{Document/startViewTransition(callbackOptions)}} with that {{StartViewTransitionOptions/type}}.
Omitting the ''@view-transition/type'' descriptor is equivalent to calling {{Document/startViewTransition(callbackOptions)}} without a {{StartViewTransition/type}}.

# API # {#api}

## The <dfn interface>RevealEvent</dfn> ## {#ready-to-render-event}
## The <dfn interface>PageRevealEvent</dfn> ## {#ready-to-render-event}

Note: this should go in the HTML spec. See [Issue 9315](https://github.com/whatwg/html/issues/9315).

<xmp class=idl>
[Exposed=Window]
interface RevealEvent : Event {
interface PageRevealEvent : Event {
readonly attribute ViewTransition? viewTransition;
};
</xmp>

Note: this event is fired when the document is [=ready to render=].
A {{PageRevealEvent}} has a null-or-{{ViewTransition}} <dfn for=PageRevealEvent>view transition</dfn>, initially null.

Note: this event is fired when the document is [=reveal=].

The <dfn attribute for=RevealEvent>viewTransition</dfn> [=getter steps=] are to return the
[=inbound cross-document view-transition=] for [=this's=] [=relevant global object's=] [=associated document=].
The <dfn attribute for=RevealEvent>viewTransition</dfn> [=getter steps=] are to return [=this=]'s [=PageRevealEvent/view transition=].

## Additions to {{Document}} ## {#additions-to-document-api}

<xmp class=idl>
dictionary StartViewTransitionOptions {
UpdateCallback? update = null;
sequence<DOMString>? types = null;
sequence<DOMString>? type = null;
};

partial interface Document {
Expand All @@ -348,7 +357,7 @@ The <dfn attribute for=RevealEvent>viewTransition</dfn> [=getter steps=] are to

1. Let |viewTransition| be the result of running [=method steps=] for {{Document/startViewTransition(updateCallback)}} given |callbackOptions|'s {{StartViewTransitionOptions/update}}.

1. Set |viewTransition|'s [=ViewTransition/active types=] to |callbackOptions|'s {{StartViewTransitionOptions/types}}.
1. Set |viewTransition|'s [=ViewTransition/active types=] to |callbackOptions|'s {{StartViewTransitionOptions/type}}.

1. Return |viewTransition|.
</div>
Expand All @@ -368,11 +377,11 @@ partial interface CSSRule {
The {{CSSViewTransitionRule}} represents a ''@view-transition'' rule.

<xmp class=idl>
enum ViewTransitionTrigger { "navigation", "none" };
enum ViewTransitionNavigation { "auto", "none" };
[Exposed=Window]
interface CSSViewTransitionRule : CSSRule {
readonly attribute CSSOMString navigationConditionText;
attribute ViewTransitionTrigger trigger;
attribute ViewTransitionNavigation navigation;
attribute DOMTokenList? type;
};
</xmp>

Expand All @@ -385,7 +394,7 @@ The {{CSSViewTransitionRule}} represents a ''@view-transition'' rule.
A {{Document}} additionally has:

<dl dfn-for=document>
: <dfn>ready to render fired</dfn>
: <dfn>pagereveal fired</dfn>
:: a boolean, initially false.

### Additions to {{ViewTransition}} ### {#view-transitions-extension}
Expand All @@ -395,6 +404,8 @@ The {{CSSViewTransitionRule}} represents a ''@view-transition'' rule.
: <dfn>is inbound cross-document transition</dfn>
:: a boolean, initially false.

Issue: should a cross-document transition take precedent? See [#9512](https://github.com/w3c/csswg-drafts/issues/9512)

: <dfn>active types</dfn>
:: Null or a [=list=] of strings, initially null.
</dl>
Expand All @@ -405,44 +416,57 @@ The {{CSSViewTransitionRule}} represents a ''@view-transition'' rule.
Prepend a step at the beginning of the task [=queue a global task|queued=] on |navigable|'s [=active window=]
when <a href="https://html.spec.whatwg.org/multipage/browsing-the-web.html#apply-the-history-step">applying the history step</a> (14.11.1, <a href="https://html.spec.whatwg.org/multipage/browsing-the-web.html#updating-the-traversable:queue-a-global-task-3">here</a>):

If |changingNavigationContinuation| update-only is false, then [=setup outbound cross-document view transition=] given |oldDocument|, |newDocument| and the remaining steps and return from these steps.
If |changingNavigationContinuation| update-only is false, then [=setup cross-document view-transition=] given |oldDocument|, |newDocument|, |navigationType|, and the remaining steps and return from these steps.

Note: This would wait until a transition is captured or skipped before proceeding to unloading the old document and activating the new one.
</div>

<div algorithm="monkey patch to rendering">
Run the following step in [=update the rendering|updating the renedering=], before [=running the animation frame callbacks=]:

1. For each [=fully active=] {{Document}} |doc| in |docs|, run the [=ready to render=] steps for |doc|.
1. For each [=fully active=] {{Document}} |doc| in |docs|, run the [=reveal=] steps for |doc|.
</div>

<div algorithm="monkey patch to reactivation">
Run the following step at the end of [=Document/reactivate=]:

1. Set |document|'s [=ready to render fired=] to false.
1. Set |document|'s [=pagereveal fired=] to false.
</div>

<div algorithm="page ready to render">
When {{Document}} |document| is <dfn>ready to render</dfn>:
1. If |document|'s [=document/ready to render fired=] is true, then return.
<div algorithm="page reveal">
To <dfn>reveal</dfn> {{Document}} |document|:
1. If |document|'s [=document/page pagereveal fired=] is false, then:
1. Let |transition| be the result of [=activating cross-document view-transition=] for |document|.

1. Let |transition| be the result of getting the [=inbound cross-document view-transition=] for |document|.
1. [=Fire an event=] named <code>pagereveal</code> at |document|'s [=relevant global object=],
using {{PageRevealEvent}}, with [=PageRevealEvent/view transition=] initialized to .

1. If |transition| is not null and |document| does not [=opt in to cross-document view transitions=], then [=skip the view transition|skip=] |transition| and set |transition| to null.
1. Set |document|'s [=document/page pagereveal fired=] to true.
</div>

## Setting up and activating the cross-document view transition ## {#setting-up-and-activating-the-cross-document-view-transition}

### Resolving the ''@view-transition''' rule

<div algorithm>
To get the <dfn>resolve @view-transition rule</dfn> for a {{Document}} |document|:

1. Fire a new event named <code>reveal</code> on |document|'s [=relevant global object=],
using {{RevealEvent}}.
1. Let |matchingRule| be the last ''@view-transition'' rule in |document| which has a ''@view-transition/navigation'' descriptor whose [=computed value=] is ''@view-transition/navigation/auto''.

1. If |transition| is not null, then [=activate view transition|activate=] |transition|.
1. If |matchingRule| is not found, then return "<code>not found</code>".

1. Set |document|'s [=document/ready to render fired=] to true.
1. If |matchingRule| contains a ''@view-transition/type'' descriptor, then return a [=list=] of strings corresponding to that descriptor's [=computed value=].

1. Return null.
</div>

## Setting up and activating the cross-document view transition ## {#setting-up-and-activating-the-cross-document-view-transition}
### Setting up the view-transition in the old {{Document}}

<div algorithm>
To <dfn>setup outbound cross-document view transition</dfn> given a {{Document}} |oldDocument|,
a {{Document}} |newDocument|, and |onReady|, which is an algorithm accepting nothing:
To <dfn export>setup cross-document view-transition</dfn> given a {{Document}} |oldDocument|,
a {{Document}} |newDocument|, a {{NavigationType}} |navigationType|, and |onReady|, which is an algorithm accepting nothing:

1. If |navigationType| is {{NavigationType/reload}}, then return.

1. If |oldDocument|'s [=environment settings object/origin=] is not [=same origin=] as
|newDocument|'s [=environment settings object/origin=] then call |onReady| and return.
Expand All @@ -453,10 +477,12 @@ The {{CSSViewTransitionRule}} represents a ''@view-transition'' rule.
Note: A document with a non-null [=latest entry=]
is being [=Document/reactivated=], in which case we don't need to check for cross-origin redirects.

1. If |oldDocument| does not [=opt in to cross-document view transitions=], then call |onReady| and return.
1. [=Resolve @view-transition rule=] for |oldDocument| and let |resolvedRule| be the result.

1. If |resolvedRule| is "<code>not found</code>", then call |onReady| and return.

Note: We don't know yet if |newDocument| has opted in, as it might not be parsed yet.
We check the opt-in for |newDocument| when it is [=ready to render=].
We check the opt-in for |newDocument| when it is [=reveal=].

1. If |oldDocument|'s [=active view transition=] is not null,
then [=skip the view transition|skip=] |oldDocument|'s [=active view transition=]
Expand All @@ -466,7 +492,7 @@ The {{CSSViewTransitionRule}} represents a ''@view-transition'' rule.
to unload.

1. Let |outboundTransition| be a new {{ViewTransition}} object in |oldDocument|'s [=relevant Realm=],
whose [=ViewTransition/process old state captured=] is set to the following steps:
whose [=ViewTransition/active types=] is |resolvedRule|, and whose [=ViewTransition/process old state captured=] is set to the following steps:

Issue: should we check for the opt-in again, in case there was a CSSOM change in a requestAnimationFrame callback?

Expand Down Expand Up @@ -499,24 +525,28 @@ The {{CSSViewTransitionRule}} represents a ''@view-transition'' rule.
Note: The process continues in [=setup view transition=], via [=perform pending transition operations=].
</div>

### Activating the view-transition in the new {{Document}}

<div algorithm>
To get the <dfn>inbound cross-document view-transition</dfn> for a {{Document}} |document|:
To <dfn export>activate cross-document view-transition</dfn> for {{Document}} |document|:

1. Let |transition| be |document|'s [=active view transition=].

1. If |transition| is null or |transition|'s [=ViewTransition/is inbound cross-document transition=] is false,
then return null.

Note: |transition|'s [=ViewTransition/is inbound cross-document transition=] would be false if a same-document
transition was started before the page was [=ready to render=].
transition was started before the page was [=reveal=].

1. Return |transition|.
</div>
1. [=Resolve @view-transition rule=] for |document| and let |resolvedRule| be the result.

<div algorithm>
A {{Document}} |document| is said to <dfn>opt in to cross-document view transitions</dfn>
if the [=computed value=] of <a data-xref-type="css-descriptor" data-xref-for="@view-transition">trigger</a>
for |document| is <code>navigation</code>.
1. If |resolvedRule| is "<code>not found</code>", then [=skip the view transition|skip=] |transition| and return null.

1. Set |transition|'s [=ViewTransition/active types=] to |resolvedRule|.

1. [=activate view transition|Activate=] |transition|.

1. Return |transition|.
</div>


Expand Down

0 comments on commit d6c50e9

Please sign in to comment.