Skip to content

Commit 88766c2

Browse files
author
Felix Arntz
committed
Complete decoupling view transition animations from view transition types.
1 parent e4798d3 commit 88766c2

8 files changed

Lines changed: 429 additions & 128 deletions

src/js/_enqueues/wp/view-transitions.js

Lines changed: 61 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,27 @@ window.wp.viewTransitions.init = ( config ) => {
2626
/**
2727
* Gets all view transition entries relevant for a view transition.
2828
*
29-
* @param {string} transitionType View transition type (e.g. 'default', 'forwards', 'backwards').
29+
* @param {string} transitionType View transition type (e.g. 'default', 'chronological-forwards', 'chronological-backwards').
3030
* @param {Element} bodyElement The body element.
3131
* @param {Element|null} articleElement The post element relevant for the view transition, if any.
3232
* @return {Array[]} View transition entries with each one containing the element and its view transition name.
3333
*/
3434
const getViewTransitionEntries = ( transitionType, bodyElement, articleElement ) => {
35-
const isMainSlide = transitionType === 'forwards' || transitionType === 'backwards';
36-
let foundMainElement = false;
37-
const globalEntries = Object.entries( config.globalTransitionNames || {} ).map( ( [ selector, name ] ) => {
38-
const element = bodyElement.querySelector( selector );
39-
if ( name === 'main' && element ) {
40-
foundMainElement = true;
41-
}
42-
return [ element, name ];
43-
} );
44-
if ( ! articleElement || isMainSlide && foundMainElement ) {
45-
return globalEntries;
46-
}
47-
return [
48-
...globalEntries,
49-
...Object.entries( config.postTransitionNames || {} ).map( ( [ selector, name ] ) => {
35+
const globalEntries = config.animations[ transitionType ].useGlobalTransitionNames ?
36+
Object.entries( config.globalTransitionNames || {} ).map( ( [ selector, name ] ) => {
37+
const element = bodyElement.querySelector( selector );
38+
return [ element, name ];
39+
} ) : [];
40+
41+
const postEntries = config.animations[ transitionType ].usePostTransitionNames && articleElement ?
42+
Object.entries( config.postTransitionNames || {} ).map( ( [ selector, name ] ) => {
5043
const element = articleElement.querySelector( selector );
5144
return [ element, name ];
52-
} ),
45+
} ) : [];
46+
47+
return [
48+
...globalEntries,
49+
...postEntries,
5350
];
5451
};
5552

@@ -126,14 +123,20 @@ window.wp.viewTransitions.init = ( config ) => {
126123
*
127124
* @param {NavigationHistoryEntry} oldEntry Navigation history entry for the URL navigated from.
128125
* @param {NavigationHistoryEntry} newEntry Navigation history entry for the URL navigated to.
129-
* @return {string} View transition type (e.g. 'default', 'forwards', 'backwards').
126+
* @return {string} View transition type (e.g. 'default', 'chronological-forwards', 'chronological-backwards').
130127
*/
131128
const determineTransitionType = ( oldEntry, newEntry ) => {
132-
if ( ! config.chronologicalSlideInOut ) {
129+
if ( ! oldEntry || ! newEntry ) {
133130
return 'default';
134131
}
135132

136-
if ( ! oldEntry || ! newEntry ) {
133+
// Use 'default' transition type if all other transition types are disabled.
134+
if (
135+
! config.animations['chronological-forwards'] &&
136+
! config.animations['chronological-backwards'] &&
137+
! config.animations['pagination-forwards'] &&
138+
! config.animations['pagination-backwards']
139+
) {
137140
return 'default';
138141
}
139142

@@ -147,49 +150,61 @@ window.wp.viewTransitions.init = ( config ) => {
147150
return 'default';
148151
}
149152

150-
// Check if the URLs are for a paginated archive.
151-
let oldPageMatches = oldPathname.match( /\/page\/(\d+)\/?$/ );
152-
let newPageMatches = newPathname.match( /\/page\/(\d+)\/?$/ );
153+
let oldPageMatches = false;
154+
let newPageMatches = false;
153155
let prefix = '';
154156

157+
// If enabled, check if the URLs are for a chronologically paginated archive.
158+
if ( config.animations['chronological-forwards'] || config.animations['chronological-backwards'] ) {
159+
oldPageMatches = oldPathname.match( /\/page\/(\d+)\/?$/ );
160+
newPageMatches = newPathname.match( /\/page\/(\d+)\/?$/ );
161+
prefix = 'chronological-';
162+
}
163+
155164
// If not, check if the URLs are for a multi-page post.
156-
if ( ! oldPageMatches && ! newPageMatches ) {
165+
if ( ! oldPageMatches && ! newPageMatches && ( config.animations['pagination-forwards'] || config.animations['pagination-backwards'] ) ) {
157166
oldPageMatches = oldPathname.match( /\/(\d+)\/?$/ );
158167
newPageMatches = newPathname.match( /\/(\d+)\/?$/ );
159-
prefix = 'content-';
168+
prefix = 'pagination-';
160169
}
161170

162171
// If there is a match on at least one of the URLs, compare whether their roots before the page segment match.
163172
if ( oldPageMatches || newPageMatches ) {
164173
const oldPageBase = oldPageMatches ? oldPathname.substring( 0, oldPathname.length - oldPageMatches[ 0 ].length ) : oldPathname.replace( /\/$/, '' );
165174
const newPageBase = newPageMatches ? newPathname.substring( 0, newPathname.length - newPageMatches[ 0 ].length ) : newPathname.replace( /\/$/, '' );
166175
if ( oldPageBase === newPageBase ) { // They belong to the same archive or post.
176+
// Return the appropriate transition type, or 'default' if no particular animation is specified.
167177
if ( oldPageMatches && newPageMatches ) {
168-
return Number( oldPageMatches[ 1 ] ) < Number( newPageMatches[ 1 ] ) ? `${ prefix }forwards` : `${ prefix }backwards`;
178+
if ( Number( oldPageMatches[ 1 ] ) < Number( newPageMatches[ 1 ] ) ) {
179+
return config.animations[ `${ prefix }forwards` ] ? `${ prefix }forwards` : 'default';
180+
}
181+
return config.animations[ `${ prefix }backwards` ] ? `${ prefix }backwards` : 'default';
169182
}
170183
if ( newPageMatches && Number( newPageMatches[ 1 ] ) > 1 ) {
171-
return `${ prefix }forwards`;
184+
return config.animations[ `${ prefix }forwards` ] ? `${ prefix }forwards` : 'default';
172185
}
173186
if ( oldPageMatches && Number( oldPageMatches[ 1 ] ) > 1 ) {
174-
return `${ prefix }backwards`;
187+
return config.animations[ `${ prefix }backwards` ] ? `${ prefix }backwards` : 'default';
175188
}
176189
}
177190
}
178191

179-
// Check if the URLs are for content labelled by date (e.g. navigation to previous/next post).
180-
const oldDateMatches = oldPathname.match( /\/(\d{4})\/(\d{2})\/(\d{2})\/[^\/]+\/?$/ );
181-
const newDateMatches = newPathname.match( /\/(\d{4})\/(\d{2})\/(\d{2})\/[^\/]+\/?$/ );
182-
if ( oldDateMatches && newDateMatches ) {
183-
const oldPageBase = oldPathname.substring( 0, oldPathname.length - oldDateMatches[ 0 ].length );
184-
const newPageBase = newPathname.substring( 0, newPathname.length - newDateMatches[ 0 ].length );
185-
if ( oldPageBase === newPageBase ) { // They belong to the same hierarchy.
186-
const oldDate = new Date( parseInt( oldDateMatches[ 1 ] ), parseInt( oldDateMatches[ 2 ] ) - 1, parseInt( oldDateMatches[ 3 ] ) );
187-
const newDate = new Date( parseInt( newDateMatches[ 1 ] ), parseInt( newDateMatches[ 2 ] ) - 1, parseInt( newDateMatches[ 3 ] ) );
188-
if ( oldDate < newDate ) {
189-
return 'forwards';
190-
}
191-
if ( oldDate > newDate ) {
192-
return 'backwards';
192+
// If enabled, check if the URLs are for content labelled by date (e.g. navigation to previous/next post).
193+
if ( config.animations['chronological-forwards'] || config.animations['chronological-backwards'] ) {
194+
const oldDateMatches = oldPathname.match( /\/(\d{4})\/(\d{2})\/(\d{2})\/[^\/]+\/?$/ );
195+
const newDateMatches = newPathname.match( /\/(\d{4})\/(\d{2})\/(\d{2})\/[^\/]+\/?$/ );
196+
if ( oldDateMatches && newDateMatches ) {
197+
const oldPageBase = oldPathname.substring( 0, oldPathname.length - oldDateMatches[ 0 ].length );
198+
const newPageBase = newPathname.substring( 0, newPathname.length - newDateMatches[ 0 ].length );
199+
if ( oldPageBase === newPageBase ) { // They belong to the same hierarchy.
200+
const oldDate = new Date( parseInt( oldDateMatches[ 1 ] ), parseInt( oldDateMatches[ 2 ] ) - 1, parseInt( oldDateMatches[ 3 ] ) );
201+
const newDate = new Date( parseInt( newDateMatches[ 1 ] ), parseInt( newDateMatches[ 2 ] ) - 1, parseInt( newDateMatches[ 3 ] ) );
202+
if ( oldDate < newDate ) {
203+
return config.animations['chronological-forwards'] ? 'chronological-forwards' : 'default';
204+
}
205+
if ( oldDate > newDate ) {
206+
return config.animations['chronological-backwards'] ? 'chronological-backwards' : 'default';
207+
}
193208
}
194209
}
195210
}
@@ -204,11 +219,8 @@ window.wp.viewTransitions.init = ( config ) => {
204219
* @return {string|null} View transition name, or null if none is relevant for the transition type.
205220
*/
206221
const getViewTransitionNameForSlideAnimation = ( transitionType ) => {
207-
if ( transitionType === 'forwards' || transitionType === 'backwards' ) {
208-
return 'main';
209-
}
210-
if ( transitionType === 'content-forwards' || transitionType === 'content-backwards' ) {
211-
return 'post-content';
222+
if ( config.animations[ transitionType ] && config.animations[ transitionType ].targetName !== '*' ) {
223+
return config.animations[ transitionType ].targetName;
212224
}
213225
return null;
214226
};
@@ -239,6 +251,7 @@ window.wp.viewTransitions.init = ( config ) => {
239251
}
240252
if ( viewTransitionEntries ) {
241253
setTemporaryViewTransitionNames( viewTransitionEntries, event.viewTransition.finished );
254+
242255
const slideViewTransitionName = getViewTransitionNameForSlideAnimation( transitionType );
243256
if ( slideViewTransitionName ) {
244257
// Consider a scroll offset if defined (e.g. due to fixed navigation bars being in the way).
@@ -276,6 +289,7 @@ window.wp.viewTransitions.init = ( config ) => {
276289
}
277290
if ( viewTransitionEntries ) {
278291
setTemporaryViewTransitionNames( viewTransitionEntries, event.viewTransition.ready );
292+
279293
const slideViewTransitionName = getViewTransitionNameForSlideAnimation( transitionType );
280294
if ( slideViewTransitionName ) {
281295
const oldScrollY = sessionStorage.getItem( 'wpViewTransitionsOldScrollY' );

src/wp-includes/class-wp-view-transition-animation-registry.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,30 +119,34 @@ public function get_animation_stylesheet( string $alias, array $args = array() )
119119
*
120120
* @since 6.9.0
121121
*
122-
* @param string $alias Slug or alias for the animation.
122+
* @param string $alias Slug or alias to reference the animation with. May be used to alter the
123+
* animation's behavior.
124+
* @param array<string, mixed> $args Optional. Animation arguments. Default is the animation's default arguments.
123125
* @return bool True if the global view transition names should be applied, false otherwise.
124126
*/
125-
public function use_animation_global_transition_names( string $alias ): bool {
127+
public function use_animation_global_transition_names( string $alias, array $args = array() ): bool {
126128
if ( ! isset( $this->alias_map[ $alias ] ) ) {
127129
return true;
128130
}
129131

130-
return $this->registered_animations[ $this->alias_map[ $alias ] ]->use_global_transition_names();
132+
return $this->registered_animations[ $this->alias_map[ $alias ] ]->use_global_transition_names( $alias, $args );
131133
}
132134

133135
/**
134136
* Returns whether to apply the post specific view transition names for the given animation alias.
135137
*
136138
* @since 6.9.0
137139
*
138-
* @param string $alias Slug or alias for the animation.
140+
* @param string $alias Slug or alias to reference the animation with. May be used to alter the
141+
* animation's behavior.
142+
* @param array<string, mixed> $args Optional. Animation arguments. Default is the animation's default arguments.
139143
* @return bool True if the post specific view transition names should be applied, false otherwise.
140144
*/
141-
public function use_animation_post_transition_names( string $alias ): bool {
145+
public function use_animation_post_transition_names( string $alias, array $args = array() ): bool {
142146
if ( ! isset( $this->alias_map[ $alias ] ) ) {
143147
return true;
144148
}
145149

146-
return $this->registered_animations[ $this->alias_map[ $alias ] ]->use_post_transition_names();
150+
return $this->registered_animations[ $this->alias_map[ $alias ] ]->use_post_transition_names( $alias, $args );
147151
}
148152
}

src/wp-includes/class-wp-view-transition-animation.php

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,15 @@ final class WP_View_Transition_Animation {
4545
* Whether to apply the global view transition names while using this animation.
4646
*
4747
* @since 6.9.0
48-
* @var bool
48+
* @var bool|callable
4949
*/
5050
private $use_global_transition_names = true;
5151

5252
/**
5353
* Whether to apply the post specific view transition names while using this animation.
5454
*
5555
* @since 6.9.0
56-
* @var bool
56+
* @var bool|callable
5757
*/
5858
private $use_post_transition_names = true;
5959

@@ -95,10 +95,14 @@ final class WP_View_Transition_Animation {
9595
* @type string[] $aliases Unique aliases for the animation, if any. Default empty
9696
* array.
9797
* @type bool $use_stylesheet Whether the animation uses a stylesheet. Default false.
98-
* @type bool $use_global_transition_names Whether to apply the global view transition names while
99-
* using this animation. Default true.
100-
* @type bool $use_post_transition_names Whether to apply the post specific view transition names
101-
* while using this animation. Default true.
98+
* @type bool|callable $use_global_transition_names Whether to apply the global view transition names while
99+
* using this animation. Alternatively to a concrete value, a
100+
* callback can be specified to determine it dynamically.
101+
* Default true.
102+
* @type bool|callable $use_post_transition_names Whether to apply the post specific view transition names
103+
* while using this animation. Alternatively to a concrete
104+
* value, acallback can be specified to determine it
105+
* dynamically. Default true.
102106
* @type callable|null $get_stylesheet_callback Callback to get the stylesheet for the animation, as
103107
* inline CSS. This can be used if the animation CSS requires
104108
* further preparation other than simply loading its
@@ -182,21 +186,41 @@ public function get_stylesheet( string $alias = '', array $args = array() ): str
182186
*
183187
* @since 6.9.0
184188
*
189+
* @param string $alias Optional. Slug or alias to reference the animation with. May be used to alter
190+
* the animation's behavior. Default is the animation's slug.
191+
* @param array<string, mixed> $args Optional. Animation arguments. Default is the animation's default arguments.
185192
* @return bool True if the global view transition names should be applied, false otherwise.
186193
*/
187-
public function use_global_transition_names(): bool {
188-
return $this->use_global_transition_names;
194+
public function use_global_transition_names( string $alias = '', array $args = array() ): bool {
195+
if ( is_bool( $this->use_global_transition_names ) ) {
196+
return $this->use_global_transition_names;
197+
}
198+
if ( ! $alias ) {
199+
$alias = $this->slug;
200+
}
201+
$args = wp_parse_args( $args, $this->default_args );
202+
return call_user_func( $this->use_global_transition_names, $alias, $args );
189203
}
190204

191205
/**
192206
* Returns whether to apply the post specific view transition names while using this animation.
193207
*
194208
* @since 6.9.0
195209
*
210+
* @param string $alias Optional. Slug or alias to reference the animation with. May be used to alter
211+
* the animation's behavior. Default is the animation's slug.
212+
* @param array<string, mixed> $args Optional. Animation arguments. Default is the animation's default arguments.
196213
* @return bool True if the post specific view transition names should be applied, false otherwise.
197214
*/
198-
public function use_post_transition_names(): bool {
199-
return $this->use_post_transition_names;
215+
public function use_post_transition_names( string $alias = '', array $args = array() ): bool {
216+
if ( is_bool( $this->use_post_transition_names ) ) {
217+
return $this->use_post_transition_names;
218+
}
219+
if ( ! $alias ) {
220+
$alias = $this->slug;
221+
}
222+
$args = wp_parse_args( $args, $this->default_args );
223+
return call_user_func( $this->use_post_transition_names, $alias, $args );
200224
}
201225

202226
/**
@@ -226,10 +250,14 @@ private function apply_config( array $config ): void {
226250
$this->use_stylesheet = (bool) $config['use_stylesheet'];
227251
}
228252
if ( isset( $config['use_global_transition_names'] ) ) {
229-
$this->use_global_transition_names = (bool) $config['use_global_transition_names'];
253+
$this->use_global_transition_names = is_callable( $config['use_global_transition_names'] ) ?
254+
$config['use_global_transition_names'] :
255+
(bool) $config['use_global_transition_names'];
230256
}
231257
if ( isset( $config['use_post_transition_names'] ) ) {
232-
$this->use_post_transition_names = (bool) $config['use_post_transition_names'];
258+
$this->use_post_transition_names = is_callable( $config['use_post_transition_names'] ) ?
259+
$config['use_post_transition_names'] :
260+
(bool) $config['use_post_transition_names'];
233261
}
234262
if ( isset( $config['get_stylesheet_callback'] ) && is_callable( $config['get_stylesheet_callback'] ) ) {
235263
$this->get_stylesheet_callback = $config['get_stylesheet_callback'];
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
@property --wp-view-transition-animation-slide-horizontal-offset {
2+
syntax: "<number>";
3+
initial-value: 1;
4+
inherits: false;
5+
}
6+
7+
@property --wp-view-transition-animation-slide-vertical-offset {
8+
syntax: "<number>";
9+
initial-value: 0;
10+
inherits: false;
11+
}
12+
13+
@keyframes wp-view-transition-animation-slide-old {
14+
to {
15+
translate: calc(100vw * var(--wp-view-transition-animation-slide-horizontal-offset) * -1) calc(100vw * var(--wp-view-transition-animation-slide-vertical-offset) * -1);
16+
}
17+
}
18+
19+
@keyframes wp-view-transition-animation-slide-new {
20+
from {
21+
translate: calc(100vw * var(--wp-view-transition-animation-slide-horizontal-offset)) calc(100vw * var(--wp-view-transition-animation-slide-vertical-offset));
22+
}
23+
}
24+
25+
::view-transition-group(*) {
26+
animation-duration: 1s;
27+
}
28+
29+
::view-transition-old(*) {
30+
animation-name: wp-view-transition-animation-slide-old;
31+
}
32+
33+
::view-transition-new(*) {
34+
animation-name: wp-view-transition-animation-slide-new;
35+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
@property --wp-view-transition-animation-swipe-horizontal-offset {
2+
syntax: "<number>";
3+
initial-value: 1;
4+
inherits: false;
5+
}
6+
7+
@property --wp-view-transition-animation-swipe-vertical-offset {
8+
syntax: "<number>";
9+
initial-value: 0;
10+
inherits: false;
11+
}
12+
13+
@keyframes wp-view-transition-animation-swipe-old {
14+
to {
15+
opacity: 0;
16+
translate: calc(100vw * var(--wp-view-transition-animation-swipe-horizontal-offset) * -1) calc(100vw * var(--wp-view-transition-animation-swipe-vertical-offset) * -1);
17+
}
18+
}
19+
20+
@keyframes wp-view-transition-animation-swipe-new {
21+
from {
22+
opacity: 0;
23+
translate: calc(100vw * var(--wp-view-transition-animation-swipe-horizontal-offset)) calc(100vw * var(--wp-view-transition-animation-swipe-vertical-offset));
24+
}
25+
}
26+
27+
::view-transition-group(*) {
28+
animation-duration: 1s;
29+
}
30+
31+
::view-transition-old(*) {
32+
animation-name: wp-view-transition-animation-swipe-old;
33+
}
34+
35+
::view-transition-new(*) {
36+
animation-name: wp-view-transition-animation-swipe-new;
37+
}

0 commit comments

Comments
 (0)