auto-animate; carry forward fragment visibility, unmatched elements adhere to duration/delay attributes

This commit is contained in:
Hakim El Hattab 2020-03-19 15:18:14 +01:00
parent 376b8230bb
commit 4d1cb43faf
6 changed files with 67 additions and 12 deletions

View file

@ -45,6 +45,10 @@ body {
opacity: 1; opacity: 1;
visibility: inherit; visibility: inherit;
} }
&.disabled {
transition: none;
}
} }
.reveal .slides section .fragment.grow { .reveal .slides section .fragment.grow {

4
dist/reveal.css vendored

File diff suppressed because one or more lines are too long

4
dist/reveal.min.js vendored

File diff suppressed because one or more lines are too long

View file

@ -38,9 +38,13 @@ export default class AutoAnimate {
fromSlide.dataset.autoAnimate = 'pending'; fromSlide.dataset.autoAnimate = 'pending';
toSlide.dataset.autoAnimate = 'pending'; toSlide.dataset.autoAnimate = 'pending';
// Flag the navigation direction, needed for fragment buildup
let allSlides = this.Reveal.getSlides();
animationOptions.slideDirection = allSlides.indexOf( toSlide ) > allSlides.indexOf( fromSlide ) ? 'forward' : 'backward';
// Inject our auto-animate styles for this transition // Inject our auto-animate styles for this transition
let css = this.getAutoAnimatableElements( fromSlide, toSlide ).map( elements => { let css = this.getAutoAnimatableElements( fromSlide, toSlide ).map( elements => {
return this.getAutoAnimateCSS( elements.from, elements.to, elements.options || {}, animationOptions, this.autoAnimateCounter++ ); return this.autoAnimateElements( elements.from, elements.to, elements.options || {}, animationOptions, this.autoAnimateCounter++ );
} ); } );
// Animate unmatched elements, if enabled // Animate unmatched elements, if enabled
@ -124,8 +128,9 @@ export default class AutoAnimate {
} }
/** /**
* Auto-animates the properties of an element from their original * Creates a FLIP animation where the `to` element starts out
* values to their new state. * in the `from` element position and animates to its original
* state.
* *
* @param {HTMLElement} from * @param {HTMLElement} from
* @param {HTMLElement} to * @param {HTMLElement} to
@ -134,7 +139,7 @@ export default class AutoAnimate {
* @param {String} id Unique ID that we can use to identify this * @param {String} id Unique ID that we can use to identify this
* auto-animate element in the DOM * auto-animate element in the DOM
*/ */
getAutoAnimateCSS( from, to, elementOptions, animationOptions, id ) { autoAnimateElements( from, to, elementOptions, animationOptions, id ) {
// 'from' elements are given a data-auto-animate-target with no value, // 'from' elements are given a data-auto-animate-target with no value,
// 'to' elements are are given a data-auto-animate-target with an ID // 'to' elements are are given a data-auto-animate-target with an ID
@ -154,6 +159,21 @@ export default class AutoAnimate {
let fromProps = this.getAutoAnimatableProperties( 'from', from, elementOptions ), let fromProps = this.getAutoAnimatableProperties( 'from', from, elementOptions ),
toProps = this.getAutoAnimatableProperties( 'to', to, elementOptions ); toProps = this.getAutoAnimatableProperties( 'to', to, elementOptions );
// Maintain fragment visibility for matching elements when
// we're navigating forwards, this way the viewer won't need
// to step through the same fragments twice
if( to.classList.contains( 'fragment' ) ) {
// Don't auto-animate the opacity of fragments to avoid
// conflicts with fragment animations
delete toProps.styles['opacity'];
if( from.classList.contains( 'fragment' ) && animationOptions.slideDirection === 'forward' ) {
to.classList.add( 'visible', 'disabled' );
}
}
// If translation and/or scaling are enabled, css transform // If translation and/or scaling are enabled, css transform
// the 'to' element so that it matches the position and size // the 'to' element so that it matches the position and size
// of the 'from' element // of the 'from' element

View file

@ -63,8 +63,8 @@ export default class Fragments {
let currentSlide = this.Reveal.getCurrentSlide(); let currentSlide = this.Reveal.getCurrentSlide();
if( currentSlide && this.Reveal.getConfig().fragments ) { if( currentSlide && this.Reveal.getConfig().fragments ) {
let fragments = currentSlide.querySelectorAll( '.fragment' ); let fragments = currentSlide.querySelectorAll( '.fragment:not(.disabled)' );
let hiddenFragments = currentSlide.querySelectorAll( '.fragment:not(.visible)' ); let hiddenFragments = currentSlide.querySelectorAll( '.fragment:not(.disabled):not(.visible)' );
return { return {
prev: fragments.length - hiddenFragments.length > 0, prev: fragments.length - hiddenFragments.length > 0,
@ -291,12 +291,12 @@ export default class Fragments {
let currentSlide = this.Reveal.getCurrentSlide(); let currentSlide = this.Reveal.getCurrentSlide();
if( currentSlide && this.Reveal.getConfig().fragments ) { if( currentSlide && this.Reveal.getConfig().fragments ) {
let fragments = this.sort( currentSlide.querySelectorAll( '.fragment' ) ); let fragments = this.sort( currentSlide.querySelectorAll( '.fragment:not(.disabled)' ) );
if( fragments.length ) { if( fragments.length ) {
// If no index is specified, find the current // If no index is specified, find the current
if( typeof index !== 'number' ) { if( typeof index !== 'number' ) {
let lastVisibleFragment = this.sort( currentSlide.querySelectorAll( '.fragment.visible' ) ).pop(); let lastVisibleFragment = this.sort( currentSlide.querySelectorAll( '.fragment:not(.disabled).visible' ) ).pop();
if( lastVisibleFragment ) { if( lastVisibleFragment ) {
index = parseInt( lastVisibleFragment.getAttribute( 'data-fragment-index' ) || 0, 10 ); index = parseInt( lastVisibleFragment.getAttribute( 'data-fragment-index' ) || 0, 10 );

View file

@ -42,6 +42,22 @@
<h1>Non-auto-animate slide</h1> <h1>Non-auto-animate slide</h1>
</section> </section>
<section data-auto-animate>
<h1 class="fragment">h1</h1>
<h2 class="fragment">h2</h2>
<h3>h3</h3>
</section>
<section data-auto-animate>
<h1 class="fragment">h1</h1>
<h2 class="fragment">h2</h2>
<h3 class="fragment">h3</h3>
</section>
<section>
<h1>Non-auto-animate slide</h1>
</section>
</div> </div>
</div> </div>
@ -119,6 +135,21 @@
Reveal.configure({ autoAnimate: true }); Reveal.configure({ autoAnimate: true });
}); });
QUnit.test( 'Carries forward matching fragment visibility', assert => {
Reveal.slide(4);
assert.ok( !slides[5].h1.classList.contains( 'visible' ) )
Reveal.next();
Reveal.next();
Reveal.next();
assert.ok( slides[5].h1.classList.contains( 'visible' ) )
assert.ok( slides[5].h2.classList.contains( 'visible' ) )
assert.ok( !slides[5].h3.classList.contains( 'visible' ) )
Reveal.next();
assert.ok( slides[5].h3.classList.contains( 'visible' ) )
Reveal.next();
assert.ok( slides[6].slide === Reveal.getCurrentSlide() )
});
} ); } );
</script> </script>