1
0
mirror of https://github.com/hakimel/reveal.js.git synced 2025-09-14 16:42:05 +02:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Hakim El Hattab
c69adfb022 add lightbox to reveal.js state, enables syncing with speaker view #3771 2025-03-24 15:34:51 +01:00
27 changed files with 74 additions and 260 deletions

View File

@@ -4,7 +4,7 @@
</a>
<br><br>
<a href="https://github.com/hakimel/reveal.js/actions"><img src="https://github.com/hakimel/reveal.js/workflows/tests/badge.svg"></a>
<a href="https://slides.com/"><img src="https://static.slid.es/images/slides-github-banner-320x40.png?1" alt="Slides" width="160" height="20"></a>
<a href="https://slides.com/"><img src="https://s3.amazonaws.com/static.slid.es/images/slides-github-banner-320x40.png?1" alt="Slides" width="160" height="20"></a>
</p>
reveal.js is an open source HTML presentation framework. It enables anyone with a web browser to create beautiful presentations for free. Check out the live demo at [revealjs.com](https://revealjs.com/).

View File

@@ -39,12 +39,6 @@ html.reveal-full-page {
--r-overlay-gap: 5px;
}
@media screen and (max-width: 1024px), (max-height: 768px) {
.reveal-viewport {
--r-overlay-header-height: 26px;
}
}
// Force the presentation to cover the full viewport when we
// enter fullscreen mode. Fixes sizing issues in Safari.
.reveal-viewport:fullscreen {
@@ -1339,12 +1333,9 @@ $controlsArrowAngleActive: 36deg;
}
.slides section:hover,
.slides section.present {
outline: 10px solid rgba(150,150,150,0.6);
outline: 10px solid rgba(150,150,150,0.4);
outline-offset: 10px;
}
.slides section.present {
outline: 10px solid var(--r-link-color);
}
.slides section .fragment {
opacity: 1;
transition: none;
@@ -1465,7 +1456,7 @@ $controlsArrowAngleActive: 36deg;
bottom: var(--r-overlay-margin);
left: var(--r-overlay-margin);
border-radius: min( var(--r-overlay-margin), 6px );
z-index: 99;
z-index: 1000;
background: rgba( 0, 0, 0, 0.95 );
backdrop-filter: blur( 10px );
transition: all 0.3s ease;
@@ -1501,7 +1492,7 @@ $controlsArrowAngleActive: 36deg;
justify-content: center;
min-width: var(--r-overlay-header-height);
min-height: var(--r-overlay-header-height);
padding: 0 calc(var(--r-overlay-header-height) / 4);
padding: 0 10px;
opacity: 1;
border-radius: 6px;
font-size: 18px;

View File

@@ -9,10 +9,9 @@
@import "../template/settings";
// ---------------------------------------------
// Include theme-specific fonts
@import url(./fonts/league-gothic/league-gothic.css);
@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic);
// Include theme-specific fonts
$systemFontsSansSerif: -apple-system,
BlinkMacSystemFont,
avenir next,

View File

@@ -197,25 +197,6 @@
</script>
</section>
<section>
<h2>Lightbox</h2>
Turn any element into a <a href="https://revealjs.com/lightbox/">lightbox</a> using <strong>datapreviewimage</strong> & <strong>datapreviewvideo</strong>.
<div class="r-hstack" style="gap: 2rem;">
<div>
<pre style="font-size: 12px; width: 100%"><code class="html" data-trim>
&lt;img src="image.png" data-preview-image="image.png"&gt;
</code></pre>
<img src="https://static.slid.es/logo/v2/slides-symbol-1024x1024.png" height="100" data-preview-image>
</div>
<div>
<pre style="font-size: 12px; width: 100%"><code class="html" data-trim>
&lt;img src="video.png" data-preview-video="video.mp4"&gt;
</code></pre>
<img src="https://static.slid.es/site/homepage/v1/homepage-video-editor.png" height="100" data-preview-video="https://static.slid.es/site/homepage/v1/homepage-video-editor.mp4">
</div>
</div>
</section>
<section>
<p>Add the <code>r-fit-text</code> class to auto-size text</p>
<h2 class="r-fit-text">FIT TEXT</h2>

4
dist/reveal.css vendored

File diff suppressed because one or more lines are too long

4
dist/reveal.esm.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
dist/reveal.js vendored

File diff suppressed because one or more lines are too long

2
dist/reveal.js.map vendored

File diff suppressed because one or more lines are too long

View File

@@ -2,8 +2,6 @@
* Dracula Dark theme for reveal.js.
* Based on https://draculatheme.com
*/
@import url(./fonts/league-gothic/league-gothic.css);
@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic);
/**
* Dracula colors by Zeno Rocha
* https://draculatheme.com/contribute

View File

@@ -89,7 +89,7 @@
<h2>Same background twice (2/2)</h2>
</section>
<section data-background-video="https://static.slid.es/site/homepage/v1/homepage-video-editor.mp4,https://static.slid.es/site/homepage/v1/homepage-video-editor.webm">
<section data-background-video="https://s3.amazonaws.com/static.slid.es/site/homepage/v1/homepage-video-editor.mp4,https://s3.amazonaws.com/static.slid.es/site/homepage/v1/homepage-video-editor.webm">
<h2>Video background</h2>
</section>

View File

@@ -121,7 +121,7 @@
<!-- Images -->
<section data-markdown>
<script type="text/template">
![Sample image](https://static.slid.es/logo/v2/slides-symbol-512x512.png)
![Sample image](https://s3.amazonaws.com/static.slid.es/logo/v2/slides-symbol-512x512.png)
</script>
</section>

View File

@@ -33,7 +33,7 @@ Content 3.2
## External 3.3 (Image)
![External Image](https://static.slid.es/logo/v2/slides-symbol-512x512.png)
![External Image](https://s3.amazonaws.com/static.slid.es/logo/v2/slides-symbol-512x512.png)
## External 3.4 (Math)

View File

@@ -33,10 +33,10 @@
<section>
<h2>Video</h2>
<video src="https://static.slid.es/site/homepage/v1/homepage-video-editor.mp4" data-autoplay></video>
<video src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" data-autoplay></video>
</section>
<section data-background-video="https://static.slid.es/site/homepage/v1/homepage-video-editor.mp4">
<section data-background-video="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4">
<h2>Background Video</h2>
</section>

View File

@@ -91,7 +91,7 @@
<section data-background="https://static.slid.es/reveal/image-placeholder.png" id="image-bg">
<h2>Image Backgrounds</h2>
</section>
<section data-background-video-muted data-background-video="https://static.slid.es/site/homepage/v1/homepage-video-editor.mp4,https://static.slid.es/site/homepage/v1/homepage-video-editor.webm">
<section data-background-video-muted data-background-video="https://s3.amazonaws.com/static.slid.es/site/homepage/v1/homepage-video-editor.mp4,https://s3.amazonaws.com/static.slid.es/site/homepage/v1/homepage-video-editor.webm">
<div style="background-color: rgba(0, 0, 0, 0.9); color: #fff; padding: 20px;">
<h2>Video background</h2>
</div>

View File

@@ -83,10 +83,9 @@ export default class Controls {
let pointerEvents = [ 'touchstart', 'click' ];
// Only support touch for Android, fixes double navigations in
// stock browser. Use touchend for it to be considered a valid
// user interaction (so we're allowed to autoplay media).
// stock browser
if( isAndroid ) {
pointerEvents = [ 'touchend' ];
pointerEvents = [ 'touchstart' ];
}
pointerEvents.forEach( eventName => {
@@ -103,7 +102,7 @@ export default class Controls {
unbind() {
[ 'touchstart', 'touchend', 'click' ].forEach( eventName => {
[ 'touchstart', 'click' ].forEach( eventName => {
this.controlsLeft.forEach( el => el.removeEventListener( eventName, this.onNavigateLeftClicked, false ) );
this.controlsRight.forEach( el => el.removeEventListener( eventName, this.onNavigateRightClicked, false ) );
this.controlsUp.forEach( el => el.removeEventListener( eventName, this.onNavigateUpClicked, false ) );

View File

@@ -190,7 +190,7 @@ export default class Keyboard {
}
}
if( this.Reveal.isOverlayOpen() && !["Escape", "f", "c", "b", "."].includes(event.key) ) {
if( this.Reveal.isOverlayOpen() && !['Escape', 'f', 'c'].includes(event.key) ) {
return false;
}
@@ -398,12 +398,6 @@ export default class Keyboard {
event.preventDefault && event.preventDefault();
}
// Enter to exit overview mode
else if (keyCode === 13 && this.Reveal.overview.isActive()) {
this.Reveal.overview.deactivate();
event.preventDefault && event.preventDefault();
}
// If auto-sliding is enabled we need to cue up
// another timeout

View File

@@ -2,6 +2,7 @@
* Handles the display of reveal.js' overlay elements used
* to preview iframes, images & videos.
*/
export default class Overlay {
constructor( Reveal ) {
@@ -10,10 +11,9 @@ export default class Overlay {
this.onSlidesClicked = this.onSlidesClicked.bind( this );
this.iframeTriggerSelector = null;
this.mediaTriggerSelector = '[data-preview-image], [data-preview-video]';
this.linkPreviewSelector = null;
this.mediaPreviewSelector = '[data-preview-image], [data-preview-video]';
this.stateProps = ['previewIframe', 'previewImage', 'previewVideo', 'previewFit'];
this.state = {};
}
@@ -22,18 +22,18 @@ export default class Overlay {
// Enable link previews globally
if( this.Reveal.getConfig().previewLinks ) {
this.iframeTriggerSelector = 'a[href]:not([data-preview-link=false]), [data-preview-link]:not(a):not([data-preview-link=false])';
this.linkPreviewSelector = 'a[href]:not([data-preview-link=false]), [data-preview-link]:not(a):not([data-preview-link=false])';
}
// Enable link previews for individual elements
else {
this.iframeTriggerSelector = '[data-preview-link]:not([data-preview-link=false])';
this.linkPreviewSelector = '[data-preview-link]:not([data-preview-link=false])';
}
const hasLinkPreviews = this.Reveal.getSlidesElement().querySelectorAll( this.iframeTriggerSelector ).length > 0;
const hasMediaPreviews = this.Reveal.getSlidesElement().querySelectorAll( this.mediaTriggerSelector ).length > 0;
this.hasLinkPreviews = this.Reveal.getSlidesElement().querySelectorAll( this.linkPreviewSelector ).length > 0;
this.hasMediaPreviews = this.Reveal.getSlidesElement().querySelectorAll( this.mediaPreviewSelector ).length > 0;
// Only add the listener when there are previewable elements in the slides
if( hasLinkPreviews || hasMediaPreviews ) {
if( this.hasLinkPreviews || this.hasMediaPreviews ) {
this.Reveal.getSlidesElement().addEventListener( 'click', this.onSlidesClicked, false );
}
else {
@@ -57,15 +57,15 @@ export default class Overlay {
}
/**
* Opens a lightbox that previews the target URL.
* Opens a preview window for the target URL.
*
* @param {string} url - url for lightbox iframe src
* @param {string} url - url for preview iframe src
*/
previewIframe( url ) {
showIframePreview( url ) {
this.close();
this.state = { previewIframe: url };
this.state.previewIframe = url;
this.createOverlay( 'r-overlay-preview' );
this.dom.dataset.state = 'loading';
@@ -96,19 +96,20 @@ export default class Overlay {
this.close();
}, false );
this.Reveal.dispatchEvent({ type: 'previewiframe', data: { url } });
this.Reveal.dispatchEvent({ type: 'showiframepreview', data: { url } });
}
/**
* Opens a lightbox window that provides a larger view of the
* Opens a preview window that provides a larger view of the
* given image/video.
*
* @param {string} url - url to the image/video to preview
* @param {image|video} mediaType
* @param {string} [fitMode] - the fit mode to use for the preview
* @param {HTMLElement} [trigger] - the element that triggered
* the preview
*/
previewMedia( url, mediaType, fitMode ) {
showMediaPreview( url, mediaType, trigger ) {
if( mediaType !== 'image' && mediaType !== 'video' ) {
console.warn( 'Please specify a valid media type to preview (image|video)' );
@@ -117,7 +118,7 @@ export default class Overlay {
this.close();
fitMode = fitMode || 'scale-down';
const fitMode = trigger ? trigger.dataset.previewFit || 'scale-down' : 'scale-down';
this.createOverlay( 'r-overlay-preview' );
this.dom.dataset.state = 'loading';
@@ -156,8 +157,6 @@ export default class Overlay {
this.close();
}, false );
this.Reveal.dispatchEvent({ type: 'previewimage', data: { url } });
}
else if( mediaType === 'video' ) {
@@ -182,8 +181,6 @@ export default class Overlay {
`<span class="r-overlay-error">Unable to load video.</span>`;
}, false );
this.Reveal.dispatchEvent({ type: 'previewvideo', data: { url } });
}
else {
throw new Error( 'Please specify a valid media type to preview' );
@@ -194,17 +191,7 @@ export default class Overlay {
event.preventDefault();
}, false );
}
previewImage( url, fitMode ) {
this.previewMedia( url, 'image', fitMode );
}
previewVideo( url, fitMode ) {
this.previewMedia( url, 'video', fitMode );
this.Reveal.dispatchEvent({ type: 'showmediapreview', data: { mediaType, url, trigger } });
}
@@ -314,20 +301,14 @@ export default class Overlay {
setState( state ) {
// Ignore the incoming state if none of the preview related
// props have changed
if( this.stateProps.every( key => this.state[ key ] === state[ key ] ) ) {
return;
}
if( state.previewIframe ) {
this.previewIframe( state.previewIframe );
this.showIframePreview( state.previewIframe );
}
else if( state.previewImage ) {
this.previewImage( state.previewImage, state.previewFit );
this.showMediaPreview( state.previewImage, 'image' );
}
else if( state.previewVideo ) {
this.previewVideo( state.previewVideo, state.previewFit );
this.showMediaPreview( state.previewVideo, 'video' );
}
else {
this.close();
@@ -339,27 +320,23 @@ export default class Overlay {
const target = event.target;
const linkTarget = target.closest( this.iframeTriggerSelector );
const mediaTarget = target.closest( this.mediaTriggerSelector );
const linkTarget = target.closest( this.linkPreviewSelector );
const mediaTarget = target.closest( this.mediaPreviewSelector );
// Was an iframe lightbox trigger clicked?
// Was a link preview clicked?
if( linkTarget ) {
if( event.metaKey || event.shiftKey || event.altKey ) {
// Let the browser handle meta keys naturally so users can cmd+click
return;
}
let url = linkTarget.getAttribute( 'href' ) || linkTarget.getAttribute( 'data-preview-link' );
if( url ) {
this.previewIframe( url );
this.showIframePreview( url );
event.preventDefault();
}
}
// Was a media lightbox trigger clicked?
// Was a media preview clicked?
else if( mediaTarget ) {
if( mediaTarget.hasAttribute( 'data-preview-image' ) ) {
let url = mediaTarget.dataset.previewImage || mediaTarget.getAttribute( 'src' );
if( url ) {
this.previewImage( url, mediaTarget.dataset.previewFit );
this.showMediaPreview( url, 'image', mediaTarget );
event.preventDefault();
}
}
@@ -372,7 +349,7 @@ export default class Overlay {
}
}
if( url ) {
this.previewVideo( url, mediaTarget.dataset.previewFit );
this.showMediaPreview( url, 'video', mediaTarget );
event.preventDefault();
}
}

View File

@@ -9,14 +9,11 @@ import fitty from 'fitty';
*/
export default class SlideContent {
allowedToPlay = true;
constructor( Reveal ) {
this.Reveal = Reveal;
this.startEmbeddedIframe = this.startEmbeddedIframe.bind( this );
this.ensureMobileMediaPlaying = this.ensureMobileMediaPlaying.bind( this );
}
@@ -54,13 +51,7 @@ export default class SlideContent {
load( slide, options = {} ) {
// Show the slide element
const displayValue = this.Reveal.getConfig().display;
if( displayValue.includes('!important') ) {
const value = displayValue.replace(/\s*!important\s*$/, '').trim();
slide.style.setProperty('display', value, 'important');
} else {
slide.style.display = displayValue;
}
slide.style.display = this.Reveal.getConfig().display;
// Media elements with data-src attributes
queryAll( slide, 'img[data-src], video[data-src], audio[data-src], iframe[data-src]' ).forEach( element => {
@@ -329,16 +320,10 @@ export default class SlideContent {
else if( isMobile ) {
let promise = el.play();
el.addEventListener( 'canplay', this.ensureMobileMediaPlaying );
// If autoplay does not work, ensure that the controls are visible so
// that the viewer can start the media on their own
if( promise && typeof promise.catch === 'function' && el.controls === false ) {
promise
.then( () => {
this.allowedToPlay = true;
})
.catch( () => {
promise.catch( () => {
el.controls = true;
// Once the video does start playing, hide the controls again
@@ -389,40 +374,6 @@ export default class SlideContent {
}
/**
* Ensure that an HTMLMediaElement is playing on mobile devices.
*
* This is a workaround for a bug in mobile Safari where
* the media fails to display if many videos are started
* at the same moment. When this happens, Mobile Safari
* reports the video is playing, and the current time
* advances, but nothing is visible.
*
* @param {Event} event
*/
ensureMobileMediaPlaying( event ) {
const el = event.target;
// Ignore this check incompatible browsers
if( typeof el.getVideoPlaybackQuality !== 'function' ) {
return;
}
setTimeout( () => {
const playing = el.paused === false;
const totalFrames = el.getVideoPlaybackQuality().totalVideoFrames;
if( playing && totalFrames === 0 ) {
el.load();
el.play();
}
}, 1000 );
}
/**
* Starts playing an embedded video/audio element after
* it has finished loading.
@@ -438,19 +389,7 @@ export default class SlideContent {
// Don't restart if media is already playing
if( event.target.paused || event.target.ended ) {
event.target.currentTime = 0;
const promise = event.target.play();
if( promise && typeof promise.catch === 'function' ) {
promise
.then( () => {
this.allowedToPlay = true;
} )
.catch( ( error ) => {
if( error.name === 'NotAllowedError' ) {
this.allowedToPlay = false;
}
} );
}
event.target.play();
}
}
@@ -522,10 +461,6 @@ export default class SlideContent {
if( !el.hasAttribute( 'data-ignore' ) && typeof el.pause === 'function' ) {
el.setAttribute('data-paused-by-reveal', '');
el.pause();
if( isMobile ) {
el.removeEventListener( 'canplay', this.ensureMobileMediaPlaying );
}
}
} );
@@ -562,15 +497,4 @@ export default class SlideContent {
}
/**
* Checks whether media playback is blocked by the browser. This
* typically happens when media playback is initiated without a
* direct user interaction.
*/
isNotAllowedToPlay() {
return !this.allowedToPlay;
}
}

View File

@@ -216,14 +216,6 @@ export default class Touch {
*/
onTouchEnd( event ) {
// Media playback is only allowed as a direct result of a
// user interaction. Some mobile devices do not consider a
// 'touchmove' to be a direct user action. If this is the
// case, we fall back to starting playback here instead.
if( this.touchCaptured && this.Reveal.slideContent.isNotAllowedToPlay() ) {
this.Reveal.startEmbeddedContent( this.Reveal.getCurrentSlide() );
}
this.touchCaptured = false;
}

View File

@@ -29,7 +29,7 @@ import {
} from './utils/constants.js'
// The reveal.js version
export const VERSION = '5.2.1';
export const VERSION = '5.2.0';
/**
* reveal.js
@@ -394,7 +394,7 @@ export default function( revealElement, options ) {
// Text node
if( node.nodeType === 3 ) {
text += node.textContent.trim();
text += node.textContent;
}
// Element node
else if( node.nodeType === 1 ) {
@@ -403,25 +403,10 @@ export default function( revealElement, options ) {
let isDisplayHidden = window.getComputedStyle( node )['display'] === 'none';
if( isAriaHidden !== 'true' && !isDisplayHidden ) {
// Capture alt text from img and video elements
if( node.tagName === 'IMG' || node.tagName === 'VIDEO' ) {
let altText = node.getAttribute( 'alt' );
if( altText ) {
text += ensurePunctuation( altText );
}
}
Array.from( node.childNodes ).forEach( child => {
text += getStatusText( child );
} );
// Add period after block-level text elements to improve
// screen reader experience
const textElements = ['P', 'DIV', 'UL', 'OL', 'LI', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'BLOCKQUOTE'];
if( textElements.includes( node.tagName ) && text.trim() !== '' ) {
text = ensurePunctuation( text );
}
}
}
@@ -432,22 +417,6 @@ export default function( revealElement, options ) {
}
/**
* Ensures text ends with proper punctuation by adding a period
* if it doesn't already end with punctuation.
*/
function ensurePunctuation( text ) {
const trimmedText = text.trim();
if( trimmedText === '' ) {
return text;
}
return !/[.!?]$/.test(trimmedText) ? trimmedText + '.' : trimmedText;
}
/**
* This is an unfortunate necessity. Some actions such as
* an input field being focused in an iframe or using the
@@ -1813,16 +1782,14 @@ export default function( revealElement, options ) {
if( horizontalSlidesLength && typeof indexh !== 'undefined' ) {
const isOverview = overview.isActive();
// The number of steps away from the present slide that will
// be visible
let viewDistance = isOverview ? 10 : config.viewDistance;
let viewDistance = overview.isActive() ? 10 : config.viewDistance;
// Shorten the view distance on devices that typically have
// less resources
if( Device.isMobile ) {
viewDistance = isOverview ? 6 : config.mobileViewDistance;
viewDistance = overview.isActive() ? 6 : config.mobileViewDistance;
}
// All slides need to be visible when exporting to PDF
@@ -1855,7 +1822,7 @@ export default function( revealElement, options ) {
if( verticalSlidesLength ) {
let oy = isOverview ? 0 : getPreviousVerticalIndex( horizontalSlide );
let oy = getPreviousVerticalIndex( horizontalSlide );
for( let y = 0; y < verticalSlidesLength; y++ ) {
let verticalSlide = verticalSlides[y];
@@ -2799,12 +2766,10 @@ export default function( revealElement, options ) {
startEmbeddedContent: () => slideContent.startEmbeddedContent( currentSlide ),
stopEmbeddedContent: () => slideContent.stopEmbeddedContent( currentSlide, { unloadIframes: false } ),
// Lightbox previews
previewIframe: overlay.previewIframe.bind( overlay ),
previewImage: overlay.previewImage.bind( overlay ),
previewVideo: overlay.previewVideo.bind( overlay ),
showPreview: overlay.previewIframe.bind( overlay ), // deprecated in favor of showIframeLightbox
// Preview management
showIframePreview: overlay.showIframePreview.bind( overlay ),
showMediaPreview: overlay.showMediaPreview.bind( overlay ),
showPreview: overlay.showIframePreview.bind( overlay ), // deprecated in favor of showIframePreview
hidePreview: overlay.close.bind( overlay ),
// Adds or removes all internal event listeners

View File

@@ -1,6 +1,6 @@
{
"name": "reveal.js",
"version": "5.2.1",
"version": "5.2.0",
"description": "The HTML Presentation Framework",
"homepage": "https://revealjs.com",
"subdomain": "revealjs",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -209,10 +209,6 @@ const Plugin = () => {
deck.on( 'overviewshown', post );
deck.on( 'paused', post );
deck.on( 'resumed', post );
deck.on( 'previewiframe', post );
deck.on( 'previewimage', post );
deck.on( 'previewvideo', post );
deck.on( 'closeoverlay', post );
// Post the initial state
post();

View File

@@ -420,16 +420,17 @@
'fragmenthidden',
'paused',
'resumed',
'previewiframe',
'previewimage',
'previewvideo',
'closeoverlay'
'showiframepreview',
'showmediapreview'
];
if( /ready/.test( data.eventName ) ) {
// Send a message back to notify that the handshake is complete
window.opener.postMessage( JSON.stringify({ namespace: 'reveal-notes', type: 'connected'} ), '*' );
}
else if( /closeoverlay/.test( data.eventName ) ) {
dispatchStateToMainWindow( data.state );
}
else if( supportedEvents.includes( data.eventName ) && currentState !== JSON.stringify( data.state ) ) {
dispatchStateToMainWindow( data.state );
}
@@ -504,12 +505,9 @@
notes.classList.add( 'hidden' );
}
// Don't show lightboxes in the upcoming slide
const { previewVideo, previewImage, previewIframe, ...upcomingState } = data.state;
// Update the note slides
currentSlide.contentWindow.postMessage( JSON.stringify({ method: 'setState', args: [ data.state ] }), '*' );
upcomingSlide.contentWindow.postMessage( JSON.stringify({ method: 'setState', args: [ upcomingState ] }), '*' );
upcomingSlide.contentWindow.postMessage( JSON.stringify({ method: 'setState', args: [ data.state ] }), '*' );
upcomingSlide.contentWindow.postMessage( JSON.stringify({ method: 'next' }), '*' );
}