Skip to content

Commit

Permalink
Try using popover API for image lightbox.
Browse files Browse the repository at this point in the history
  • Loading branch information
felixarntz committed Jan 16, 2025
1 parent 5688333 commit f31f627
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 25 deletions.
11 changes: 6 additions & 5 deletions packages/block-library/src/image/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ function block_core_image_render_lightbox( $block_content, $block ) {
// Sets an event callback on the `img` because the `figure` element can also
// contain a caption, and we don't want to trigger the lightbox when the
// caption is clicked.
$p->set_attribute( 'data-wp-on-async--click', 'actions.showLightbox' );
$p->set_attribute( 'data-wp-on--click', 'actions.showLightbox' );
$p->set_attribute( 'data-wp-class--hide', 'state.isContentHidden' );
$p->set_attribute( 'data-wp-class--show', 'state.isContentVisible' );

Expand All @@ -226,12 +226,13 @@ function block_core_image_render_lightbox( $block_content, $block ) {
$button =
$img[0]
. '<button
popovertarget="wp-core-image-lightbox-overlay"
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="' . esc_attr( $aria_label ) . '"
data-wp-init="callbacks.initTriggerButton"
data-wp-on-async--click="actions.showLightbox"
data-wp-on--click="actions.setCurrentImage"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
>
Expand Down Expand Up @@ -270,15 +271,17 @@ function block_core_image_print_lightbox_overlay() {

echo <<<HTML
<div
id="wp-core-image-lightbox-overlay"
popover="auto"
class="wp-lightbox-overlay zoom"
data-wp-interactive="core/image"
data-wp-context='{}'
data-wp-bind--role="state.roleAttribute"
data-wp-bind--aria-label="state.currentImage.ariaLabel"
data-wp-bind--aria-modal="state.ariaModal"
data-wp-class--active="state.overlayEnabled"
data-wp-class--show-closing-animation="state.showClosingAnimation"
data-wp-watch="callbacks.setOverlayFocus"
data-wp-on--toggle="actions.handleToggle"
data-wp-on--keydown="actions.handleKeydown"
data-wp-on-async--touchstart="actions.handleTouchStart"
data-wp-on--touchmove="actions.handleTouchMove"
Expand All @@ -287,7 +290,6 @@ class="wp-lightbox-overlay zoom"
data-wp-on-async-window--resize="callbacks.setOverlayStyles"
data-wp-on-async-window--scroll="actions.handleScroll"
data-wp-bind--style="state.overlayStyles"
tabindex="-1"
>
<button type="button" aria-label="$close_button_label" style="fill: $close_button_color" class="close-button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" aria-hidden="true" focusable="false"><path d="m13.06 12 6.47-6.47-1.06-1.06L12 10.94 5.53 4.47 4.47 5.53 10.94 12l-6.47 6.47 1.06 1.06L12 13.06l6.47 6.47 1.06-1.06L13.06 12Z"></path></svg>
Expand All @@ -302,7 +304,6 @@ class="wp-lightbox-overlay zoom"
<img data-wp-bind--alt="state.currentImage.alt" data-wp-bind--class="state.currentImage.imgClassNames" data-wp-bind--style="state.imgStyles" data-wp-bind--src="state.enlargedSrc">
</figure>
</div>
<div class="scrim" style="background-color: $background_color" aria-hidden="true"></div>
</div>
HTML;
}
Expand Down
28 changes: 16 additions & 12 deletions packages/block-library/src/image/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -269,18 +269,20 @@
background: none;
}

.scrim {
width: 100%;
height: 100%;
position: absolute;
z-index: 2000000;
&::backdrop {
background-color: rgb(255, 255, 255);
opacity: 0.9;
}

&[popover] {
margin: 0;
padding: 0;
border: 0;
}

// When fading, make the image come in slightly slower
// or faster than the scrim to give a sense of depth.
&.active {
// or faster than the backdrop to give a sense of depth.
&:popover-open {
visibility: visible;
@media not (prefers-reduced-motion) {
animation: both turn-on-visibility 0.25s;
Expand All @@ -292,7 +294,8 @@
}
}
&.show-closing-animation {
&:not(.active) {
&:not(:popover-open) {
display: block;
@media not (prefers-reduced-motion) {
animation: both turn-off-visibility 0.35s;
}
Expand All @@ -306,7 +309,7 @@

@media not (prefers-reduced-motion) {
&.zoom {
&.active {
&:popover-open {
opacity: 1;
visibility: visible;
animation: none;
Expand All @@ -317,12 +320,13 @@
animation: none;
}
}
.scrim {
&::backdrop {
animation: turn-on-visibility 0.4s forwards;
}
}
&.show-closing-animation {
&:not(.active) {
&:not(:popover-open) {
display: block;
animation: none;
.lightbox-image-container {
animation: lightbox-zoom-out 0.4s;
Expand All @@ -331,7 +335,7 @@
animation: none;
}
}
.scrim {
&::backdrop {
animation: turn-off-visibility 0.4s forwards;
}
}
Expand Down
51 changes: 43 additions & 8 deletions packages/block-library/src/image/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,26 +84,52 @@ const { state, actions, callbacks } = store(
},
actions: {
showLightbox() {
if ( ! actions.setCurrentImage() ) {
return;
}

const lightboxOverlay = document.querySelector(
'#wp-core-image-lightbox-overlay[popover]'
);
if ( lightboxOverlay ) {
lightboxOverlay.showPopover();
}
},
hideLightbox() {
const lightboxOverlay = document.querySelector(
'#wp-core-image-lightbox-overlay[popover]'
);
if ( lightboxOverlay ) {
lightboxOverlay.hidePopover();
}
},
setCurrentImage() {
const { imageId } = getContext();

// Bails out if the image has not loaded yet.
if ( ! state.metadata[ imageId ].imageRef?.complete ) {
return;
return false;
}

state.currentImageId = imageId;
return true;
},
resetCurrentImage() {
state.currentImageId = null;
},
handleShowLightbox() {
// Stores the positions of the scroll to fix it until the overlay is
// closed.
state.scrollTopReset = document.documentElement.scrollTop;
state.scrollLeftReset = document.documentElement.scrollLeft;

// Sets the current expanded image in the state and enables the overlay.
state.overlayEnabled = true;
state.currentImageId = imageId;

// Computes the styles of the overlay for the animation.
callbacks.setOverlayStyles();
},
hideLightbox() {
handleHideLightbox() {
if ( state.overlayEnabled ) {
// Starts the overlay closing animation. The showClosingAnimation
// class is used to avoid showing it on page load.
Expand All @@ -123,11 +149,24 @@ const { state, actions, callbacks } = store(
preventScroll: true,
} );

// Resets the closing animation class.
state.showClosingAnimation = false;

// Resets the current image id to mark the overlay as closed.
state.currentImageId = null;
actions.resetCurrentImage();
}, 450 );
}
},
handleToggle( event ) {
if ( event.newState === 'open' && ! state.overlayEnabled ) {
actions.handleShowLightbox();
} else if (
event.newState !== 'open' &&
state.overlayEnabled
) {
actions.handleHideLightbox();
}
},
handleKeydown( event ) {
if ( state.overlayEnabled ) {
// Focuses the close button when the user presses the tab key.
Expand All @@ -136,10 +175,6 @@ const { state, actions, callbacks } = store(
const { ref } = getElement();
ref.querySelector( 'button' ).focus();
}
// Closes the lightbox when the user presses the escape key.
if ( event.key === 'Escape' ) {
actions.hideLightbox();
}
}
},
handleTouchMove( event ) {
Expand Down

0 comments on commit f31f627

Please sign in to comment.