Skip to content

Commit

Permalink
Clean up code; fix bug, add comments
Browse files Browse the repository at this point in the history
Mostly moved code around, renamed variables for clarity, and
add comments.

Fixed a bug wherein the lightbox wouldn't close on scroll
when using a fade animation.
  • Loading branch information
artemiomorales committed Jun 14, 2023
1 parent c60a628 commit 7ea0889
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 132 deletions.
15 changes: 11 additions & 4 deletions lib/block-supports/behaviors.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,12 @@ function gutenberg_render_behaviors_support_lightbox( $block_content, $block ) {
}
$content = $processor->get_updated_html();

$lightbox_animation = $lightbox_settings['animation'];
$lightbox_animation = '';
if ( isset( $lightbox_settings['animation'] ) ) {
$lightbox_animation = $lightbox_settings['animation'];
}

// We want to store the src in the context so we can set it dynamically when the lightbox is opened.
$z = new WP_HTML_Tag_Processor( $content );
$z->next_tag( 'img' );
if ( isset( $block['attrs']['id'] ) ) {
Expand All @@ -89,7 +93,10 @@ function gutenberg_render_behaviors_support_lightbox( $block_content, $block ) {
$w->next_tag( 'figure' );
$w->add_class( 'wp-lightbox-container' );
$w->set_attribute( 'data-wp-interactive', true );
$w->set_attribute( 'data-wp-context', '{ "core": { "image": { "initialized": false, "imageSrc": "' . $img_src . '", "lightboxEnabled": false, "lightboxAnimation": "' . $lightbox_animation . '", "animateOutEnabled": false } } }' );
$w->set_attribute(
'data-wp-context',
sprintf( '{ "core":{ "image": { "initialized": false, "imageSrc": "%s", "lightboxEnabled": false, "lightboxAnimation": "%s", "hideAnimationEnabled": false } } }', $img_src, $lightbox_animation )
);
$body_content = $w->get_updated_html();

// Wrap the image in the body content with a button.
Expand All @@ -101,7 +108,7 @@ function gutenberg_render_behaviors_support_lightbox( $block_content, $block ) {
'</div>';
$body_content = preg_replace( '/<img[^>]+>/', $button, $body_content );

// Add directive to expand modal image if appropriate.
// Add src to the modal image.
$m = new WP_HTML_Tag_Processor( $content );
$m->next_tag( 'img' );
$m->set_attribute( 'data-wp-bind--src', 'selectors.core.image.imageSrc' );
Expand All @@ -120,7 +127,7 @@ function gutenberg_render_behaviors_support_lightbox( $block_content, $block ) {
aria-label="$dialog_label"
data-wp-class--initialized="context.core.image.initialized"
data-wp-class--active="context.core.image.lightboxEnabled"
data-wp-class--animateOutEnabled="context.core.image.animateOutEnabled"
data-wp-class--hideAnimationEnabled="context.core.image.hideAnimationEnabled"
data-wp-bind--aria-hidden="!context.core.image.lightboxEnabled"
data-wp-bind--aria-modal="context.core.image.lightboxEnabled"
data-wp-effect="effects.core.image.initLightbox"
Expand Down
227 changes: 114 additions & 113 deletions packages/block-library/src/image/interactivity.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,139 +25,42 @@ store( {
context.core.image.initialized = true;
context.core.image.lastFocusedElement =
window.document.activeElement;
context.core.image.scrollPosition = window.scrollY;
context.core.image.scrollDelta = 0;

// Since the img is hidden and its src not loaded until
// the lightbox is opened, let's create an img element on the fly
// so we can get the dimensions we need to calculate the styles
const imgDom = document.createElement( 'img' );

imgDom.onload = function () {
// Enable the lightbox only after the image
// is loaded to prevent flashing of unstyled content
context.core.image.lightboxEnabled = true;
if ( context.core.image.lightboxAnimation === 'zoom' ) {
let targetWidth = imgDom.naturalWidth;
let targetHeight = imgDom.naturalHeight;

const figureStyle = window.getComputedStyle(
context.core.image.figureRef
);

const topPadding = parseInt(
figureStyle.getPropertyValue( 'padding-top' )
);
const bottomPadding = parseInt(
figureStyle.getPropertyValue( 'padding-bottom' )
);
const figureWidth =
context.core.image.figureRef.clientWidth;
let horizontalPadding = 0;
if ( figureWidth > 480 ) {
horizontalPadding = 40;
} else if ( figureWidth > 1920 ) {
horizontalPadding = 80;
}

const figureHeight =
context.core.image.figureRef.clientHeight -
topPadding -
bottomPadding;

// Check difference between the image and figure dimensions
const widthOverflow = Math.abs(
Math.min( figureWidth - targetWidth, 0 )
);
const heightOverflow = Math.abs(
Math.min( figureHeight - targetHeight, 0 )
);

// If image is larger than the figure, resize along its largest axis
if ( widthOverflow > 0 || heightOverflow > 0 ) {
if ( widthOverflow > heightOverflow ) {
targetWidth =
figureWidth - horizontalPadding * 2;
targetHeight =
imgDom.naturalHeight *
( targetWidth / imgDom.naturalWidth );
} else {
targetHeight = figureHeight;
targetWidth =
imgDom.naturalWidth *
( targetHeight / imgDom.naturalHeight );
}
}

const { x: leftPosition, y: topPosition } =
event.target.nextElementSibling.getBoundingClientRect();
const scaleWidth =
event.target.nextElementSibling.offsetWidth /
targetWidth;

const scaleHeight =
event.target.nextElementSibling.offsetHeight /
targetHeight;
let targetLeft = 0;
if ( targetWidth >= figureWidth ) {
targetLeft = horizontalPadding;
} else {
targetLeft = ( figureWidth - targetWidth ) / 2;
}

let targetTop = 0;
if ( targetHeight >= figureHeight ) {
targetTop = topPadding;
} else {
targetTop =
( figureHeight - targetHeight ) / 2 +
topPadding;
}
const root = document.documentElement;

root.style.setProperty(
'--lightbox-image-max-width',
targetWidth + 'px'
);
root.style.setProperty(
'--lightbox-image-max-height',
targetHeight + 'px'
);
root.style.setProperty(
'--lightbox-initial-left-position',
leftPosition + 'px'
);
root.style.setProperty(
'--lightbox-initial-top-position',
topPosition + 'px'
);
root.style.setProperty(
'--lightbox-target-left-position',
targetLeft + 'px'
);
root.style.setProperty(
'--lightbox-target-top-position',
targetTop + 'px'
);
root.style.setProperty(
'--lightbox-scale-width',
scaleWidth
);
root.style.setProperty(
'--lightbox-scale-height',
scaleHeight
);
setZoomStyles( imgDom, context, event );
}

// Hide overflow only when the animation is in progress,
// otherwise the removal of the scrollbars will draw attention
// to itself and look like an error
document.documentElement.classList.add(
'has-lightbox-open'
);
};
imgDom.setAttribute( 'src', context.core.image.imageSrc );
},
hideLightbox: async ( { context, event } ) => {
context.core.image.animateOutEnabled = true;
context.core.image.hideAnimationEnabled = true;
if ( context.core.image.lightboxEnabled ) {
// If scrolling, wait a moment before closing the lightbox.
if ( context.core.image.lightboxAnimation === 'fade' ) {
context.core.image.scrollDelta += event.deltaY;
if (
event.type === 'mousewheel' &&
Math.abs(
window.scrollY -
context.core.image.scrollPosition
) < 5
context.core.image.scrollDelta
) < 10
) {
return;
}
Expand Down Expand Up @@ -258,3 +161,101 @@ store( {
},
},
} );

function setZoomStyles( imgDom, context, event ) {
let targetWidth = imgDom.naturalWidth;
let targetHeight = imgDom.naturalHeight;

const figureStyle = window.getComputedStyle( context.core.image.figureRef );
const topPadding = parseInt(
figureStyle.getPropertyValue( 'padding-top' )
);
const bottomPadding = parseInt(
figureStyle.getPropertyValue( 'padding-bottom' )
);

// As per the design, let's allow the image to stretch
// to the full width of its containing figure, but for the height,
// constrain it to the padding settings
const containerWidth = context.core.image.figureRef.clientWidth;
const containerHeight =
context.core.image.figureRef.clientHeight - topPadding - bottomPadding;

// Check difference between the image and figure dimensions
const widthOverflow = Math.abs(
Math.min( containerWidth - targetWidth, 0 )
);
const heightOverflow = Math.abs(
Math.min( containerHeight - targetHeight, 0 )
);

// The lightbox image has `positione:absolute` and
// ignores its parent's padding, so let's set the padding here,
// to be used when calculating the image width and positioning
let horizontalPadding = 0;
if ( containerWidth > 480 ) {
horizontalPadding = 40;
} else if ( containerWidth > 1920 ) {
horizontalPadding = 80;
}

// If image is larger than its container, resize along its largest axis
if ( widthOverflow > 0 || heightOverflow > 0 ) {
if ( widthOverflow > heightOverflow ) {
targetWidth = containerWidth - horizontalPadding * 2;
targetHeight =
imgDom.naturalHeight * ( targetWidth / imgDom.naturalWidth );
} else {
targetHeight = containerHeight;
targetWidth =
imgDom.naturalWidth * ( targetHeight / imgDom.naturalHeight );
}
}

// The reference img element lies adjacent to the event target button in the DOM
const { x: originLeft, y: originTop } =
event.target.nextElementSibling.getBoundingClientRect();
const scaleWidth =
event.target.nextElementSibling.offsetWidth / targetWidth;
const scaleHeight =
event.target.nextElementSibling.offsetHeight / targetHeight;

// Get values used to center the image
let targetLeft = 0;
if ( targetWidth >= containerWidth ) {
targetLeft = horizontalPadding;
} else {
targetLeft = ( containerWidth - targetWidth ) / 2;
}
let targetTop = 0;
if ( targetHeight >= containerHeight ) {
targetTop = topPadding;
} else {
targetTop = ( containerHeight - targetHeight ) / 2 + topPadding;
}

const root = document.documentElement;
root.style.setProperty( '--lightbox-scale-width', scaleWidth );
root.style.setProperty( '--lightbox-scale-height', scaleHeight );
root.style.setProperty( '--lightbox-image-max-width', targetWidth + 'px' );
root.style.setProperty(
'--lightbox-image-max-height',
targetHeight + 'px'
);
root.style.setProperty(
'--lightbox-initial-left-position',
originLeft + 'px'
);
root.style.setProperty(
'--lightbox-initial-top-position',
originTop + 'px'
);
root.style.setProperty(
'--lightbox-target-left-position',
targetLeft + 'px'
);
root.style.setProperty(
'--lightbox-target-top-position',
targetTop + 'px'
);
}
27 changes: 12 additions & 15 deletions packages/block-library/src/image/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -234,18 +234,18 @@
&.fade {
&.active {
visibility: visible;
animation: both turn-on-visibility 250ms;
animation: both turn-on-visibility 0.25s;

img {
animation: both turn-on-visibility 300ms;
animation: both turn-on-visibility 0.3s;
}
}
&.animateoutenabled {
&.hideanimationenabled {
&:not(.active) {
animation: both turn-off-visibility 300ms;
animation: both turn-off-visibility 0.3s;

img {
animation: both turn-off-visibility 250ms;
animation: both turn-off-visibility 0.25s;
}
}
}
Expand All @@ -266,20 +266,20 @@
animation: lightbox-zoom-in 0.4s forwards;

@media (prefers-reduced-motion) {
animation: both turn-on-visibility 0.3s;
animation: both turn-on-visibility 0.4s;
}
}
.scrim {
animation: turn-on-visibility 0.4s forwards;
}
}
&.animateoutenabled {
&.hideanimationenabled {
&:not(.active) {
.wp-block-image img {
animation: lightbox-zoom-out 0.4s forwards;

@media (prefers-reduced-motion) {
animation: both turn-on-visibility 0.3s;
animation: both turn-off-visibility 0.4s;
}
}
.scrim {
Expand All @@ -290,6 +290,10 @@
}
}

html.has-lightbox-open {
overflow: hidden;
}

@keyframes turn-on-visibility {
0% {
opacity: 0;
Expand All @@ -314,12 +318,6 @@
}
}

// This line causes the zoom animation to jump
//
html.has-lightbox-open {
overflow: hidden;
}

@keyframes lightbox-zoom-in {
0% {
left: var(--lightbox-initial-left-position);
Expand All @@ -344,7 +342,6 @@ html.has-lightbox-open {
visibility: visible;
}
100% {

left: var(--lightbox-initial-left-position);
top: var(--lightbox-initial-top-position);
transform: scale(var(--lightbox-scale-width), var(--lightbox-scale-height));
Expand Down

0 comments on commit 7ea0889

Please sign in to comment.