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 13 commits into
base: trunk
Choose a base branch
from
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 );
madhusudhand marked this conversation as resolved.
Show resolved Hide resolved

/**
* 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,
madhusudhand marked this conversation as resolved.
Show resolved Hide resolved
),
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