Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gallery: Add lightbox support #62906

Open
wants to merge 30 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
508c70e
add lightbox support to gallery block
madhusudhand Jul 15, 2024
98bba76
disable and hide next/prev icons based on device
madhusudhand Jul 25, 2024
cc48519
remove view.js from gallery
madhusudhand Jul 25, 2024
c2611d0
fix a lint issue
madhusudhand Jul 25, 2024
e09b8ee
rename isGallery to hasNavigation and imageInit method
madhusudhand Jul 26, 2024
4d4a509
adjust button opacity when disabled
madhusudhand Jul 26, 2024
5dbfaed
address accessiability of lightbox navigation
madhusudhand Jul 26, 2024
ccbe9dc
fix accessibility: dynamic aria-label based on current image
madhusudhand Aug 13, 2024
5e0df68
Try to fix a11y issues
t-hamano Aug 16, 2024
0579c8e
Improve screen reader reading
t-hamano Aug 22, 2024
dfcca2f
move translations to server
madhusudhand Aug 29, 2024
408cf80
reset gallery_id after each gallery processing
madhusudhand Aug 30, 2024
3716092
fix php lint errors
madhusudhand Aug 30, 2024
f14acc0
Merge remote-tracking branch 'origin/trunk' into gallery/lightbox
luisherranz Dec 6, 2024
1077e73
Use block context to pass down a gallery ID
luisherranz Dec 6, 2024
3387ac0
Merge branch 'trunk' into gallery/lightbox
luisherranz Feb 19, 2025
fd51250
Fix frontend implementation
luisherranz Feb 19, 2025
016ae8d
Merge branch 'trunk' into gallery/lightbox
t-hamano Feb 21, 2025
d229233
Fix Screen reader double reading
t-hamano Feb 21, 2025
e68f3a2
Don't hide lightbox when hitting Enter on prev/next buttons
t-hamano Feb 21, 2025
4e0b31a
Match visual order with DOM order
t-hamano Feb 21, 2025
24524c6
Do not apply opacity to focus styles on disabled prev/next buttons
t-hamano Feb 21, 2025
c7608c3
Add a tooltip to navigation button
t-hamano Feb 21, 2025
230ab34
Add `cursor:pointer` to navigation buttons
t-hamano Feb 23, 2025
a9aa62b
Add focus trap
t-hamano Feb 23, 2025
7ede46a
Add "Lightbox navigation" option
t-hamano Feb 23, 2025
deeaf40
Restore aria-live/aria-atomic
t-hamano Feb 23, 2025
4f1cde2
Ajust z-index values
t-hamano Feb 23, 2025
1da0337
Regenerate fixtures
t-hamano Feb 23, 2025
0ed7d4c
Fix PHP lint error
t-hamano Feb 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions packages/block-library/src/gallery/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,35 @@ function block_core_gallery_data_id_backcompatibility( $parsed_block ) {

add_filter( 'render_block_data', 'block_core_gallery_data_id_backcompatibility' );

/**
* Handles interactivity state initialization for Gallery Block.
*
* @since 6.7.0
*
* @param string $block_content Rendered block content.
* @param array $block Block object.
*
* @return string Filtered block content.
*/
function block_core_gallery_interactivity_state( $block_content, $block ) {
if ( 'core/gallery' !== $block['blockName'] ) {
return $block_content;
}

$unique_gallery_id = uniqid();
wp_interactivity_state(
'core/gallery',
array(
'images' => array(),
'galleryId' => $unique_gallery_id,
)
);

return $block_content;
}

add_filter( 'render_block_data', 'block_core_gallery_interactivity_state', 15, 2 );

/**
* Renders the `core/gallery` block on the server.
*
Expand Down Expand Up @@ -121,6 +150,23 @@ function block_core_gallery_render( $attributes, $content ) {
)
);

$state = wp_interactivity_state( 'core/gallery' );
$gallery_id = $state['galleryId'];

$processed_content->set_attribute( 'data-wp-interactive', 'core/gallery' );
$processed_content->set_attribute(
'data-wp-context',
wp_json_encode(
array(
'galleryId' => $gallery_id,
'lightbox' => true,
),
JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
)
);

add_filter( 'render_block_core/gallery', 'block_core_gallery_render_lightbox' );

// The WP_HTML_Tag_Processor class calls get_updated_html() internally
// when the instance is treated as a string, but here we explicitly
// convert it to a string.
Expand Down Expand Up @@ -166,6 +212,66 @@ static function () use ( $image_blocks, &$i ) {

return $content;
}

/**
* Handles state updates needed for the lightbox behavior in a Gallery Block.
*
* Now that the Gallery Block contains inner Image Blocks,
* we add translations for the screen reader text before rendering the gallery
* so that the Image Block can pick it up in its render_callback.
*
* @since 6.7.0
*
* @param string $block_content Rendered block content.
*
* @return string Filtered block content.
*/
function block_core_gallery_render_lightbox( $block_content ) {
$state = wp_interactivity_state( 'core/gallery' );
$gallery_id = $state['galleryId'];
$images = $state['images'][ $gallery_id ] ?? array();
$translations = array();

if ( ! empty( $images ) ) {
if ( 1 === count( $images ) ) {
$image_id = $images[0];
$translations[ $image_id ] = __( 'Enlarged image', 'gutenberg' );
} else {
for ( $i = 0; $i < count( $images ); $i++ ) {
$image_id = $images[ $i ];
/* translators: %1$s: current image index, %2$s: total number of images */
$translations[ $image_id ] = sprintf( __( 'Enlarged image %1$s of %2$s', 'gutenberg' ), $i + 1, count( $images ) );
}
}

$image_state = wp_interactivity_state( 'core/image' );

foreach ( $translations as $image_id => $translation ) {
$alt = $image_state['metadata'][ $image_id ]['alt'];
wp_interactivity_state(
'core/image',
array(
'metadata' => array(
$image_id => array(
'screenReaderText' => empty( $alt ) ? $translation : "$translation: $alt",
),
),
)
);
}
}

// reset galleryId
wp_interactivity_state(
'core/gallery',
array(
'galleryId' => null,
)
);

return $block_content;
}

/**
* Registers the `core/gallery` block on server.
*
Expand Down
53 changes: 39 additions & 14 deletions packages/block-library/src/image/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,18 +161,14 @@ function block_core_image_render_lightbox( $block_content, $block ) {
return $block_content;
}

$alt = $p->get_attribute( 'alt' );
$img_uploaded_src = $p->get_attribute( 'src' );
$img_class_names = $p->get_attribute( 'class' );
$img_styles = $p->get_attribute( 'style' );
$img_width = 'none';
$img_height = 'none';
$aria_label = __( 'Enlarge image' );

if ( $alt ) {
/* translators: %s: Image alt text. */
$aria_label = sprintf( __( 'Enlarge image: %s' ), $alt );
}
$alt = $p->get_attribute( 'alt' );
$img_uploaded_src = $p->get_attribute( 'src' );
$img_class_names = $p->get_attribute( 'class' );
$img_styles = $p->get_attribute( 'style' );
$img_width = 'none';
$img_height = 'none';
$aria_label = __( 'Enlarge image' );
$screen_reader_text = __( 'Enlarged image' );

if ( isset( $block['attrs']['id'] ) ) {
$img_uploaded_src = wp_get_attachment_url( $block['attrs']['id'] );
Expand Down Expand Up @@ -202,13 +198,32 @@ function block_core_image_render_lightbox( $block_content, $block ) {
'targetWidth' => $img_width,
'targetHeight' => $img_height,
'scaleAttr' => $block['attrs']['scale'] ?? false,
'ariaLabel' => $aria_label,
'alt' => $alt,
'screenReaderText' => empty( $alt ) ? $screen_reader_text : "$screen_reader_text: $alt",
),
),
)
);

$state = wp_interactivity_state( 'core/gallery' );
$gallery_id = $state['galleryId'];
if ( isset( $gallery_id ) ) {
$images = $state['images'][ $gallery_id ];
if ( ! isset( $images ) ) {
$images = array();
}
$images[] = $unique_image_id;

wp_interactivity_state(
'core/gallery',
array(
'images' => array(
$gallery_id => $images,
),
)
);
}

$p->add_class( 'wp-lightbox-container' );
$p->set_attribute( 'data-wp-interactive', 'core/image' );
$p->set_attribute(
Expand Down Expand Up @@ -268,6 +283,9 @@ class="lightbox-trigger"
*/
function block_core_image_print_lightbox_overlay() {
$close_button_label = esc_attr__( 'Close' );
$dialog_label = esc_attr__( 'Enlarged images' );
Copy link
Member

@gziolo gziolo Aug 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This label Enlarged images now applies to both the single image and the group of images in the gallery. Previously, the message announced was way more accurate for a single image:

Screenshot 2024-08-21 at 17 20 23

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I adjusted the screen reader reading. NVDA reads it out as follows, but how about your software?

9bca3f2b0333352215b61aa97526289c.mp4

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's how it should work. e4ebf7d is a step in the right direction 👍🏻

$prev_button_label = esc_attr__( 'Previous' );
$next_button_label = esc_attr__( 'Next' );

// If the current theme does NOT have a `theme.json`, or the colors are not
// defined, it needs to set the background color & close button color to some
Expand All @@ -287,10 +305,10 @@ function block_core_image_print_lightbox_overlay() {
echo <<<HTML
<div
class="wp-lightbox-overlay zoom"
aria-label="$dialog_label"
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"
Expand All @@ -307,6 +325,12 @@ class="wp-lightbox-overlay zoom"
<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>
</button>
<button type="button" aria-label="$prev_button_label" style="fill: $close_button_color" class="prev-button" data-wp-bind--hidden="!state.hasNavigation" data-wp-on--click="actions.showPreviousImage" data-wp-bind--aria-disabled="!state.hasPreviousImage">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="28" height="28" aria-hidden="true" focusable="false"><path d="M14.6 7l-1.2-1L8 12l5.4 6 1.2-1-4.6-5z"></path></svg>
</button>
<button type="button" aria-label="$next_button_label" style="fill: $close_button_color" class="next-button" data-wp-bind--hidden="!state.hasNavigation" data-wp-on--click="actions.showNextImage" data-wp-bind--aria-disabled="!state.hasNextImage">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="28" height="28" aria-hidden="true" focusable="false"><path d="M10.6 6L9.4 7l4.6 5-4.6 5 1.2 1 5.4-6z"></path></svg>
</button>
<div class="lightbox-image-container">
<figure data-wp-bind--class="state.currentImage.figureClassNames" data-wp-bind--style="state.figureStyles">
<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.currentImage.currentSrc">
Expand All @@ -317,6 +341,7 @@ 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 data-wp-watch="callbacks.setScreenReaderText" aria-live="polite" aria-atomic="true" class="lightbox-speak screen-reader-text"></div>
<div class="scrim" style="background-color: $background_color" aria-hidden="true"></div>
<style data-wp-text="state.overlayStyles"></style>
</div>
Expand Down
42 changes: 42 additions & 0 deletions packages/block-library/src/image/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,48 @@
}
}

.prev-button,
.next-button {
display: none;
position: absolute;
top: 50%;
transform: translateY(-50%);
padding: 0;
cursor: pointer;
z-index: 5000000;
min-width: 40px; // equivalent to $button-size-next-default-40px
min-height: 40px; // equivalent to $button-size-next-default-40px;
align-items: center;
justify-content: center;

&[hidden] {
display: none;
}

&[aria-disabled="true"] {
opacity: 0.3;
}

&:hover,
&:focus,
&:not(:hover):not(:active):not(.has-background) {
background: none;
border: none;
}

@include break-mobile() {
display: flex;
}
}

.prev-button {
left: calc(env(safe-area-inset-left) + 16px); // equivalent to $grid-unit-20
}

.next-button {
right: calc(env(safe-area-inset-right) + 16px); // equivalent to $grid-unit-20
}

.lightbox-image-container {
position: absolute;
overflow: hidden;
Expand Down
Loading
Loading