From c4e853dd0af42ee330e4483640987a1f172a6140 Mon Sep 17 00:00:00 2001 From: Benjamin de Oostfrees <68224180+deoostfrees@users.noreply.github.com> Date: Sun, 16 Jan 2022 17:02:39 +0100 Subject: [PATCH] Add toolbar, add function to calculate image dimension --- dist/css/parvus.css | 49 +++++++++++----------- dist/css/parvus.min.css | 2 +- dist/js/parvus.esm.js | 76 +++++++++++++++++++++++++--------- dist/js/parvus.esm.min.js | 2 +- dist/js/parvus.js | 76 +++++++++++++++++++++++++--------- dist/js/parvus.min.js | 2 +- src/js/parvus.js | 87 +++++++++++++++++++++++++++++---------- src/scss/parvus.scss | 52 +++++++++++------------ 8 files changed, 233 insertions(+), 113 deletions(-) diff --git a/dist/css/parvus.css b/dist/css/parvus.css index f9294b1..86e1f46 100644 --- a/dist/css/parvus.css +++ b/dist/css/parvus.css @@ -8,9 +8,7 @@ --parvus-button-hover-color: hsl(229, 24%, 33%); --parvus-button-hover-text: hsl(0, 0%, 100%); --parvus-loader-background-color: hsl(23, 40%, 96%); - --parvus-loader-color: hsl(228, 24%, 23%); - --parvus-image-max-height: 85vh; - --parvus-image-max-width: 85vw; } + --parvus-loader-color: hsl(228, 24%, 23%); } /** * Parvus trigger @@ -87,30 +85,32 @@ .parvus__slide { align-items: center; display: flex; - height: 100%; + flex-direction: column; + height: calc(100% - 4.75rem); justify-content: center; - width: 100%; } + padding-bottom: 1rem; + padding-left: 1rem; + padding-right: 1rem; + padding-top: 3.75rem; + width: calc(100% - 2rem); } @media screen and (prefers-reduced-motion: no-preference) { .parvus__slide { transition: visibility var(--parvus-transition-duration) var(--parvus-transition-timing-function); } } .parvus__slide:not(.parvus__slide--is-active) { visibility: hidden; } - .parvus__slide figure { - margin: 0; } - .parvus__slide figcaption { - padding: 1rem; - text-align: center; + .parvus__slide .parvus__caption { + color: var(--parvus-overlay-text); + padding-top: 0.5rem; + text-align: left; will-change: transform, opacity; } @media screen and (prefers-reduced-motion: no-preference) { - .parvus__slide figcaption { + .parvus__slide .parvus__caption { transition: transform var(--parvus-transition-duration) var(--parvus-transition-timing-function), opacity var(--parvus-transition-duration) var(--parvus-transition-timing-function); } } .parvus__slide img { display: block; height: auto; margin-left: auto; margin-right: auto; - max-height: var(--parvus-image-max-height); - max-width: var(--parvus-image-max-width); transform-origin: left top; width: auto; } .parvus__loader { @@ -133,6 +133,14 @@ right: 0; top: 0; z-index: 1; } + .parvus__toolbar { + align-items: center; + display: flex; + justify-content: space-between; + left: 1rem; + position: absolute; + right: 1rem; + top: 1rem; } .parvus__btn { appearance: none; background-color: var(--parvus-button-color); @@ -144,6 +152,7 @@ display: flex; font: inherit; padding: 0.3125rem; + position: relative; touch-action: manipulation; will-change: transform, opacity; z-index: 7; } @@ -153,10 +162,6 @@ .parvus__btn:hover { background-color: var(--parvus-button-hover-color); color: var(--parvus-button-hover-text); } - .parvus__btn--close { - position: absolute; - right: 1rem; - top: 1rem; } .parvus__btn--previous { left: 1rem; position: absolute; @@ -179,14 +184,8 @@ .parvus__btn[disabled] { display: none; } .parvus__counter { - align-items: center; - display: flex; - justify-content: center; - left: 1rem; - min-height: 2.75rem; - min-width: 2.75rem; - position: absolute; - top: 1rem; } + position: relative; + z-index: 7; } @media screen and (prefers-reduced-motion: no-preference) { .parvus__counter { transition: transform var(--parvus-transition-duration) var(--parvus-transition-timing-function), opacity var(--parvus-transition-duration) var(--parvus-transition-timing-function); } } diff --git a/dist/css/parvus.min.css b/dist/css/parvus.min.css index e2ac522..9a34fca 100644 --- a/dist/css/parvus.min.css +++ b/dist/css/parvus.min.css @@ -1 +1 @@ -:root{--parvus-transition-duration:300ms;--parvus-transition-timing-function:cubic-bezier(0.4,0,0.22,1);--parvus-overlay-color:#f9f4f1;--parvus-overlay-text:#2d3249;--parvus-button-color:#2d3249;--parvus-button-text:#fff;--parvus-button-hover-color:#404768;--parvus-button-hover-text:#fff;--parvus-loader-background-color:#f9f4f1;--parvus-loader-color:#2d3249;--parvus-image-max-height:85vh;--parvus-image-max-width:85vw}.parvus-zoom{display:block;position:relative}.parvus-zoom__indicator{align-items:center;background-color:var(--parvus-button-color);color:var(--parvus-button-text);display:flex;justify-content:center;line-height:1;padding:.5rem;position:absolute;right:.5rem;top:.5rem}.parvus-zoom__indicator svg{fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5;stroke:currentColor;height:1.5rem;pointer-events:none;width:1.5rem}.parvus-zoom img{display:block}.parvus{align-items:center;bottom:0;contain:strict;display:flex;font:normal normal 400 1.125rem/1.7 -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif;justify-content:center;left:0;line-height:1.667;overflow:hidden;position:fixed;right:0;top:0;z-index:1337}.parvus[aria-hidden=true]{display:none}.parvus__overlay{background-color:var(--parvus-overlay-color)}.parvus__overlay,.parvus__slider{bottom:0;left:0;position:absolute;right:0;top:0}.parvus__slider[aria-hidden=true]{display:none}@media screen and (prefers-reduced-motion:no-preference){.parvus__slider--animate:not(.parvus__slider--is-dragging){transition:transform var(--parvus-transition-duration) var(--parvus-transition-timing-function)}}.parvus__slider--is-draggable{cursor:grab}.parvus__slider--is-dragging{cursor:grabbing}.parvus__slide{align-items:center;display:flex;height:100%;justify-content:center;width:100%}@media screen and (prefers-reduced-motion:no-preference){.parvus__slide{transition:visibility var(--parvus-transition-duration) var(--parvus-transition-timing-function)}}.parvus__slide:not(.parvus__slide--is-active){visibility:hidden}.parvus__slide figure{margin:0}.parvus__slide figcaption{padding:1rem;text-align:center;will-change:transform,opacity}@media screen and (prefers-reduced-motion:no-preference){.parvus__slide figcaption{transition:transform var(--parvus-transition-duration) var(--parvus-transition-timing-function),opacity var(--parvus-transition-duration) var(--parvus-transition-timing-function)}}.parvus__slide img{display:block;height:auto;margin-left:auto;margin-right:auto;max-height:var(--parvus-image-max-height);max-width:var(--parvus-image-max-width);transform-origin:left top;width:auto}.parvus__loader{display:inline-block;height:6.25rem;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:6.25rem}.parvus__loader:before{animation:spin 1s infinite;border:.25rem solid var(--parvus-loader-background-color);border-radius:100%;border-top-color:var(--parvus-loader-color);bottom:0;content:"";left:0;position:absolute;right:0;top:0;z-index:1}.parvus__btn{appearance:none;background-color:var(--parvus-button-color);background-image:none;border:.0625rem solid transparent;border-radius:0;color:var(--parvus-button-text);cursor:pointer;display:flex;font:inherit;padding:.3125rem;touch-action:manipulation;will-change:transform,opacity;z-index:7}@media screen and (prefers-reduced-motion:no-preference){.parvus__btn{transition:transform var(--parvus-transition-duration) var(--parvus-transition-timing-function),opacity var(--parvus-transition-duration) var(--parvus-transition-timing-function)}}.parvus__btn:hover{background-color:var(--parvus-button-hover-color);color:var(--parvus-button-hover-text)}.parvus__btn--close{position:absolute;right:1rem;top:1rem}.parvus__btn--previous{left:1rem}.parvus__btn--next,.parvus__btn--previous{position:absolute;top:50%;transform:translateY(-50%)}.parvus__btn--next{right:1rem}.parvus__btn svg{fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:1;stroke:currentColor;height:2rem;pointer-events:none;width:2rem}.parvus__btn[disabled]{display:none}.parvus__counter{align-items:center;display:flex;justify-content:center;left:1rem;min-height:2.75rem;min-width:2.75rem;position:absolute;top:1rem}@media screen and (prefers-reduced-motion:no-preference){.parvus__counter{transition:transform var(--parvus-transition-duration) var(--parvus-transition-timing-function),opacity var(--parvus-transition-duration) var(--parvus-transition-timing-function)}}.parvus__counter[aria-hidden=true]{display:none}@media screen and (prefers-reduced-motion:no-preference){.parvus--is-closing .parvus__btn--close,.parvus--is-closing .parvus__btn--next,.parvus--is-closing .parvus__btn--previous,.parvus--is-closing .parvus__counter,.parvus--is-closing figcaption,.parvus--is-opening .parvus__btn--close,.parvus--is-opening .parvus__btn--next,.parvus--is-opening .parvus__btn--previous,.parvus--is-opening .parvus__counter,.parvus--is-opening figcaption{opacity:0}.parvus--is-vertical-closing .parvus__btn--close,.parvus--is-vertical-closing .parvus__counter{opacity:0;transform:translateY(-100%)}.parvus--is-vertical-closing .parvus__btn--previous{opacity:0;transform:translate(-100%,-50%)}.parvus--is-vertical-closing .parvus__btn--next{opacity:0;transform:translate(100%,-50%)}.parvus--is-vertical-closing figcaption{opacity:0;transform:translateY(100%)}}@keyframes spin{to{transform:rotate(1turn)}} \ No newline at end of file +:root{--parvus-transition-duration:300ms;--parvus-transition-timing-function:cubic-bezier(0.4,0,0.22,1);--parvus-overlay-color:#f9f4f1;--parvus-overlay-text:#2d3249;--parvus-button-color:#2d3249;--parvus-button-text:#fff;--parvus-button-hover-color:#404768;--parvus-button-hover-text:#fff;--parvus-loader-background-color:#f9f4f1;--parvus-loader-color:#2d3249}.parvus-zoom{display:block;position:relative}.parvus-zoom__indicator{align-items:center;background-color:var(--parvus-button-color);color:var(--parvus-button-text);display:flex;justify-content:center;line-height:1;padding:.5rem;position:absolute;right:.5rem;top:.5rem}.parvus-zoom__indicator svg{fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5;stroke:currentColor;height:1.5rem;pointer-events:none;width:1.5rem}.parvus-zoom img{display:block}.parvus{align-items:center;bottom:0;contain:strict;display:flex;font:normal normal 400 1.125rem/1.7 -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif;justify-content:center;left:0;line-height:1.667;overflow:hidden;position:fixed;right:0;top:0;z-index:1337}.parvus[aria-hidden=true]{display:none}.parvus__overlay{background-color:var(--parvus-overlay-color)}.parvus__overlay,.parvus__slider{bottom:0;left:0;position:absolute;right:0;top:0}.parvus__slider[aria-hidden=true]{display:none}@media screen and (prefers-reduced-motion:no-preference){.parvus__slider--animate:not(.parvus__slider--is-dragging){transition:transform var(--parvus-transition-duration) var(--parvus-transition-timing-function)}}.parvus__slider--is-draggable{cursor:grab}.parvus__slider--is-dragging{cursor:grabbing}.parvus__slide{align-items:center;display:flex;flex-direction:column;height:calc(100% - 4.75rem);justify-content:center;padding:3.75rem 1rem 1rem;width:calc(100% - 2rem)}@media screen and (prefers-reduced-motion:no-preference){.parvus__slide{transition:visibility var(--parvus-transition-duration) var(--parvus-transition-timing-function)}}.parvus__slide:not(.parvus__slide--is-active){visibility:hidden}.parvus__slide .parvus__caption{color:var(--parvus-overlay-text);padding-top:.5rem;text-align:left;will-change:transform,opacity}@media screen and (prefers-reduced-motion:no-preference){.parvus__slide .parvus__caption{transition:transform var(--parvus-transition-duration) var(--parvus-transition-timing-function),opacity var(--parvus-transition-duration) var(--parvus-transition-timing-function)}}.parvus__slide img{display:block;height:auto;margin-left:auto;margin-right:auto;transform-origin:left top;width:auto}.parvus__loader{display:inline-block;height:6.25rem;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:6.25rem}.parvus__loader:before{animation:spin 1s infinite;border:.25rem solid var(--parvus-loader-background-color);border-radius:100%;border-top-color:var(--parvus-loader-color);bottom:0;content:"";left:0;position:absolute;right:0;top:0;z-index:1}.parvus__toolbar{align-items:center;display:flex;justify-content:space-between;left:1rem;position:absolute;right:1rem;top:1rem}.parvus__btn{appearance:none;background-color:var(--parvus-button-color);background-image:none;border:.0625rem solid transparent;border-radius:0;color:var(--parvus-button-text);cursor:pointer;display:flex;font:inherit;padding:.3125rem;position:relative;touch-action:manipulation;will-change:transform,opacity;z-index:7}@media screen and (prefers-reduced-motion:no-preference){.parvus__btn{transition:transform var(--parvus-transition-duration) var(--parvus-transition-timing-function),opacity var(--parvus-transition-duration) var(--parvus-transition-timing-function)}}.parvus__btn:hover{background-color:var(--parvus-button-hover-color);color:var(--parvus-button-hover-text)}.parvus__btn--previous{left:1rem}.parvus__btn--next,.parvus__btn--previous{position:absolute;top:50%;transform:translateY(-50%)}.parvus__btn--next{right:1rem}.parvus__btn svg{fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:1;stroke:currentColor;height:2rem;pointer-events:none;width:2rem}.parvus__btn[disabled]{display:none}.parvus__counter{position:relative;z-index:7}@media screen and (prefers-reduced-motion:no-preference){.parvus__counter{transition:transform var(--parvus-transition-duration) var(--parvus-transition-timing-function),opacity var(--parvus-transition-duration) var(--parvus-transition-timing-function)}}.parvus__counter[aria-hidden=true]{display:none}@media screen and (prefers-reduced-motion:no-preference){.parvus--is-closing .parvus__btn--close,.parvus--is-closing .parvus__btn--next,.parvus--is-closing .parvus__btn--previous,.parvus--is-closing .parvus__counter,.parvus--is-closing figcaption,.parvus--is-opening .parvus__btn--close,.parvus--is-opening .parvus__btn--next,.parvus--is-opening .parvus__btn--previous,.parvus--is-opening .parvus__counter,.parvus--is-opening figcaption{opacity:0}.parvus--is-vertical-closing .parvus__btn--close,.parvus--is-vertical-closing .parvus__counter{opacity:0;transform:translateY(-100%)}.parvus--is-vertical-closing .parvus__btn--previous{opacity:0;transform:translate(-100%,-50%)}.parvus--is-vertical-closing .parvus__btn--next{opacity:0;transform:translate(100%,-50%)}.parvus--is-vertical-closing figcaption{opacity:0;transform:translateY(100%)}}@keyframes spin{to{transform:rotate(1turn)}} \ No newline at end of file diff --git a/dist/js/parvus.esm.js b/dist/js/parvus.esm.js index a8f08ca..0fa5d36 100644 --- a/dist/js/parvus.esm.js +++ b/dist/js/parvus.esm.js @@ -27,7 +27,8 @@ function Parvus(userOptions) { const GROUP_ATTS = { gallery: [], slider: null, - sliderElements: [] + sliderElements: [], + images: [] }; const GROUPS = {}; let newGroup = null; @@ -37,6 +38,9 @@ function Parvus(userOptions) { let lightbox = null; let lightboxOverlay = null; let lightboxOverlayOpacity = 1; + let toolbar = null; + let toolbarLeft = null; + let toolbarRight = null; let previousButton = null; let nextButton = null; let closeButton = null; @@ -283,15 +287,20 @@ function Parvus(userOptions) { lightboxOverlay.classList.add('parvus__overlay'); lightboxOverlay.style.opacity = 0; // Add lightbox overlay container to lightbox container - lightbox.appendChild(lightboxOverlay); // Create the close button + lightbox.appendChild(lightboxOverlay); // Create the toolbar + + toolbar = document.createElement('div'); + toolbar.className = 'parvus__toolbar'; + toolbarLeft = document.createElement('div'); + toolbarRight = document.createElement('div'); // Create the close button closeButton = document.createElement('button'); closeButton.className = 'parvus__btn parvus__btn--close'; closeButton.setAttribute('type', 'button'); closeButton.setAttribute('aria-label', config.l10n.closeButtonLabel); - closeButton.innerHTML = config.closeButtonIcon; // Add close button to lightbox container + closeButton.innerHTML = config.closeButtonIcon; // Add close button to right toolbar item - lightbox.appendChild(closeButton); // Create the previous button + toolbarRight.appendChild(closeButton); // Create the previous button previousButton = document.createElement('button'); previousButton.className = 'parvus__btn parvus__btn--previous'; @@ -310,9 +319,14 @@ function Parvus(userOptions) { lightbox.appendChild(nextButton); // Create the counter counter = document.createElement('div'); - counter.className = 'parvus__counter'; // Add counter to lightbox container + counter.className = 'parvus__counter'; // Add counter to left toolbar item + + toolbarLeft.appendChild(counter); // Add toolbar items to toolbar + + toolbar.appendChild(toolbarLeft); + toolbar.appendChild(toolbarRight); // Add toolbar to lightbox container - lightbox.appendChild(counter); // Add lightbox container to body + lightbox.appendChild(toolbar); // Add lightbox container to body document.body.appendChild(lightbox); }; @@ -343,7 +357,7 @@ function Parvus(userOptions) { SLIDER_ELEMENT.style.left = `${index * 100}%`; // Hide slide SLIDER_ELEMENT.setAttribute('aria-hidden', 'true'); - createImage(el, SLIDER_ELEMENT_CONTENT); // Add slide content container to slider element + createImage(index, el, SLIDER_ELEMENT_CONTENT); // Add slide content container to slider element SLIDER_ELEMENT.appendChild(SLIDER_ELEMENT_CONTENT); GROUPS[activeGroup].sliderElements[index] = SLIDER_ELEMENT; // Add slider element to slider @@ -438,8 +452,7 @@ function Parvus(userOptions) { throw new Error('Ups, I\'m already closed.'); } - const IMAGE_CONTAINER = GROUPS[activeGroup].sliderElements[currentIndex]; - const IMAGE = IMAGE_CONTAINER.querySelector('img'); + const IMAGE = GROUPS[activeGroup].images[currentIndex]; const IMAGE_SIZE = IMAGE.getBoundingClientRect(); const THUMBNAIL = config.backFocus ? GROUPS[activeGroup].gallery[currentIndex] : lastFocus; const THUMBNAIL_SIZE = THUMBNAIL.getBoundingClientRect(); @@ -522,6 +535,7 @@ function Parvus(userOptions) { const loadSlide = function loadSlide(index) { GROUPS[activeGroup].sliderElements[index].classList.add('parvus__slide--is-active'); GROUPS[activeGroup].sliderElements[index].setAttribute('aria-hidden', 'false'); + setImageDimension(GROUPS[activeGroup].sliderElements[index], GROUPS[activeGroup].images[index]); }; /** * Create Image @@ -530,12 +544,14 @@ function Parvus(userOptions) { */ - const createImage = function createImage(el, container) { + const createImage = function createImage(index, el, container) { const IMAGE = document.createElement('img'); - const FIGURE = document.createElement('figure'); - const FIGCAPTION = document.createElement('figcaption'); + const IMAGE_CONTAINER = document.createElement('div'); + const CAPTION_CONTAINER = document.createElement('div'); const THUMBNAIL = el.querySelector('img'); - const LOADING_INDICATOR = document.createElement('div'); // Create loading indicator + const LOADING_INDICATOR = document.createElement('div'); + IMAGE_CONTAINER.className = 'parvus__content'; + CAPTION_CONTAINER.className = 'parvus__caption'; // Create loading indicator LOADING_INDICATOR.className = 'parvus__loader'; LOADING_INDICATOR.setAttribute('role', 'progressbar'); @@ -569,7 +585,8 @@ function Parvus(userOptions) { } IMAGE.style.opacity = 0; - FIGURE.appendChild(IMAGE); // Add caption if available + IMAGE_CONTAINER.appendChild(IMAGE); + GROUPS[activeGroup].images[index] = IMAGE; // Add caption if available if (config.captions) { let captionData = null; @@ -591,12 +608,12 @@ function Parvus(userOptions) { } if (captionData !== null) { - FIGCAPTION.innerHTML = `

${captionData}

`; - FIGURE.appendChild(FIGCAPTION); + CAPTION_CONTAINER.innerHTML = `

${captionData}

`; } } - container.appendChild(FIGURE); + container.appendChild(IMAGE_CONTAINER); + container.appendChild(CAPTION_CONTAINER); }; /** * Load Image @@ -606,8 +623,7 @@ function Parvus(userOptions) { const loadImage = function loadImage(index) { - const IMAGE_CONTAINER = GROUPS[activeGroup].sliderElements[index]; - const IMAGE = IMAGE_CONTAINER.querySelector('img'); + const IMAGE = GROUPS[activeGroup].images[index]; const IMAGE_SIZE = IMAGE.getBoundingClientRect(); const THUMBNAIL = GROUPS[activeGroup].gallery[index]; const THUMBNAIL_SIZE = THUMBNAIL.getBoundingClientRect(); @@ -863,10 +879,32 @@ function Parvus(userOptions) { resizeTicking = true; BROWSER_WINDOW.requestAnimationFrame(() => { updateOffset(); + setImageDimension(GROUPS[activeGroup].sliderElements[currentIndex], GROUPS[activeGroup].images[currentIndex]); resizeTicking = false; }); } }; + /** + * Set image with + * + * @param {HTMLElement} slideEl + * @param {HTMLElement} imageEl + */ + + + const setImageDimension = function setImageDimension(slideEl, imageEl) { + const computedStyle = getComputedStyle(slideEl); + const captionRec = slideEl.querySelector('.parvus__caption').getBoundingClientRect(); + const srcHeight = imageEl.naturalHeight; + const srcWidth = imageEl.naturalWidth; + let maxHeight = slideEl.clientHeight; + let maxWidth = slideEl.clientWidth; + maxHeight -= parseFloat(computedStyle.paddingTop) + parseFloat(computedStyle.paddingBottom) + parseFloat(captionRec.height); + maxWidth -= parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight); + const ratio = Math.min(maxWidth / srcWidth || 0, maxHeight / srcHeight); + imageEl.style.width = `${srcWidth * ratio || 0}px`; + imageEl.style.height = `${srcHeight * ratio || 0}px`; + }; /** * Click event handler to trigger Parvus * diff --git a/dist/js/parvus.esm.min.js b/dist/js/parvus.esm.min.js index 1f9cf9d..938f0c4 100644 --- a/dist/js/parvus.esm.min.js +++ b/dist/js/parvus.esm.min.js @@ -8,4 +8,4 @@ * MIT license */ -var e={lightboxLabel:"This is a dialog window which overlays the main content of the page. The modal shows the enlarged image. Pressing the Escape key will close the modal and bring you back to where you were on the page.",lightboxLoadingIndicatorLabel:"Image loading",previousButtonLabel:"Previous image",nextButtonLabel:"Next image",closeButtonLabel:"Close dialog window"};function t(n){const i=window,s=["button:not([disabled]):not([inert])",'[tabindex]:not([tabindex^="-"]):not([inert])'],r={gallery:[],slider:null,sliderElements:[]},a={};let l=null,o=null,d=0,u={},c=null,p=null,g=1,h=null,m=null,v=null,f=null,b=0,y=0,w=0,A=0,E={},L=!1,_=!1,C=!1,x=null,$=null,S=null,T=!1,B=null,M=!0;const q=window.matchMedia("(prefers-reduced-motion)"),I=function(){q.matches?(M=!0,B=u.reducedTransitionDuration):(M=!1,B=u.transitionDuration)};q.addEventListener("change",I);const X=function(t){u=function(t){return{selector:".lightbox",gallerySelector:null,captions:!0,captionsSelector:"self",captionsAttribute:"data-caption",docClose:!0,scrollClose:!1,swipeClose:!0,threshold:50,backFocus:!0,transitionDuration:300,reducedTransitionDuration:.1,transitionTimingFunction:"cubic-bezier(0.4, 0, 0.22, 1)",lightboxIndicatorIcon:'',previousButtonIcon:'',nextButtonIcon:'',closeButtonIcon:'',l10n:e,fileTypes:/\.(png|jpe?g|webp|avif|svg)(\?.*)?$/i,...t}}(t);if(document.querySelectorAll(u.selector).length)if(I(),c||N(),null!==u.gallerySelector){document.querySelectorAll(u.gallerySelector).forEach(((e,t)=>{const n=t;e.querySelectorAll(u.selector).forEach((e=>{e.setAttribute("data-group",`parvus-gallery-${n}`),k(e)}))}));document.querySelectorAll(`${u.selector}:not(.parvus-trigger)`).forEach((e=>{k(e)}))}else{document.querySelectorAll(u.selector).forEach((e=>{k(e)}))}},Y=function(e){const t=Math.floor(1e4*Math.random());return e.hasAttribute("data-group")&&""!==e.getAttribute("data-group")||e.setAttribute("data-group",`default-${t}`),e.getAttribute("data-group")},k=function(e){if(!("A"===e.tagName&&e.hasAttribute("href")&&e.href.match(u.fileTypes)||"BUTTON"===e.tagName&&e.hasAttribute("data-target")&&e.getAttribute("data-target").match(u.fileTypes)))throw new Error(e,`Use a link with the 'href' attribute or a button with the 'data-target' attribute. Both attributes must have a path to the image file. Supported image file types: ${u.fileTypes}.`);var t;if(l=Y(e),Object.prototype.hasOwnProperty.call(a,l)||(a[l]=(t=r,JSON.parse(JSON.stringify(t)))),a[l].gallery.includes(e))throw new Error("Ups, element already added.");if(a[l].gallery.push(e),null!==e.querySelector("img")){const t=document.createElement("div");e.classList.add("parvus-zoom"),t.className="parvus-zoom__indicator",t.innerHTML=u.lightboxIndicatorIcon,e.appendChild(t)}e.classList.add("parvus-trigger"),e.addEventListener("click",ie),be()&&l===o&&(D(e,a[l].gallery.indexOf(e)),R(a[l].gallery.indexOf(e)),te(),G(),Q())},F=function(e){if(be()||!c||!e||!e.hasAttribute("data-group"))return;const t=Y(e);if(!a[t].gallery.includes(e))throw new Error("Ups, I can't find the element.");if(a[t].gallery.splice(a[t].gallery.indexOf(e),1),e.classList.contains("parvus-zoom")){const t=e.querySelector(".parvus-zoom__indicator");e.classList.remove("parvus-zoom"),e.removeChild(t)}e.removeEventListener("click",ie),e.classList.remove("parvus-trigger")},N=function(){c=document.createElement("div"),c.setAttribute("role","dialog"),c.setAttribute("aria-modal","true"),c.setAttribute("aria-hidden","true"),c.setAttribute("tabindex","-1"),c.setAttribute("aria-label",u.l10n.lightboxLabel),c.classList.add("parvus"),p=document.createElement("div"),p.classList.add("parvus__overlay"),p.style.opacity=0,c.appendChild(p),v=document.createElement("button"),v.className="parvus__btn parvus__btn--close",v.setAttribute("type","button"),v.setAttribute("aria-label",u.l10n.closeButtonLabel),v.innerHTML=u.closeButtonIcon,c.appendChild(v),h=document.createElement("button"),h.className="parvus__btn parvus__btn--previous",h.setAttribute("type","button"),h.setAttribute("aria-label",u.l10n.previousButtonLabel),h.innerHTML=u.previousButtonIcon,c.appendChild(h),m=document.createElement("button"),m.className="parvus__btn parvus__btn--next",m.setAttribute("type","button"),m.setAttribute("aria-label",u.l10n.nextButtonLabel),m.innerHTML=u.nextButtonIcon,c.appendChild(m),f=document.createElement("div"),f.className="parvus__counter",c.appendChild(f),document.body.appendChild(c)},D=function(e,t){const n=document.createElement("div"),i=document.createElement("div");n.className="parvus__slide",n.style.position="absolute",n.style.left=100*t+"%",n.setAttribute("aria-hidden","true"),P(e,i),n.appendChild(i),a[o].sliderElements[t]=n,t===d&&a[o].slider.appendChild(n),t>d?a[o].sliderElements[d].after(n):a[o].sliderElements[d].before(n)},H=function(e){if(!c||!e||!e.classList.contains("parvus-trigger")||be())return;if(o=Y(e),!a[o].gallery.includes(e))throw new Error("Ups, I can't find the element.");d=a[o].gallery.indexOf(e),x=document.activeElement;const t=window.location.href;history.pushState({parvus:"close"},"Image",t),ve();document.querySelectorAll('body > *:not([aria-hidden="true"])').forEach((e=>{e.setAttribute("aria-hidden","true"),e.classList.add("parvus-hidden")})),c.classList.add("parvus--is-opening"),c.setAttribute("aria-hidden","false"),a[o].slider=document.createElement("div"),a[o].slider.className="parvus__slider",a[o].slider.setAttribute("aria-hidden","true"),c.appendChild(a[o].slider),D(e,d),a[o].slider.setAttribute("aria-hidden","false"),V(),te(),Q(),ae(),U(d),R(d),requestAnimationFrame((()=>{c.classList.remove("parvus--is-opening"),p.style.opacity=1,p.style.transition=`opacity ${B}ms ${u.transitionTimingFunction}`,p.style.willChange="opacity"})),p.addEventListener("transitionend",(()=>{z(d+1),z(d-1)})),a[o].slider.classList.add("parvus__slider--animate");const n=new CustomEvent("open",{detail:{source:e}});c.dispatchEvent(n)},O=function(){if(!be())throw new Error("Ups, I'm already closed.");const e=a[o].sliderElements[d].querySelector("img"),t=e.getBoundingClientRect(),n=(u.backFocus?a[o].gallery[d]:x).getBoundingClientRect();fe(),Z(),null!==history.state&&"close"===history.state.parvus&&history.back();document.querySelectorAll(".parvus-hidden").forEach((e=>{e.removeAttribute("aria-hidden"),e.classList.remove("parvus-hidden")})),c.classList.add("parvus--is-closing"),requestAnimationFrame((()=>{b=n.width/t.width,y=n.height/t.height,w=n.left-t.left,A=n.top-t.top,e.style.transform=`translate(${w}px, ${A}px) scale(${b}, ${y})`,e.style.opacity=0,e.style.transition=`transform ${B}ms ${u.transitionTimingFunction}, opacity ${B}ms ${u.transitionTimingFunction} ${B/2}ms`,p.style.opacity=0,p.style.transition=`opacity ${B}ms ${u.transitionTimingFunction}`,p.style.willChange="auto"})),p.addEventListener("transitionend",(()=>{K(d),x=u.backFocus?a[o].gallery[d]:x,x.focus({preventScroll:!0}),c.setAttribute("aria-hidden","true"),c.classList.remove("parvus--is-closing"),c.classList.remove("parvus--is-vertical-closing"),a[o].slider.remove(),e.style.transform=""}),{once:!0});const i=new CustomEvent("close",{detail:{source:a[o].gallery[d]}});c.dispatchEvent(i)},z=function(e){void 0!==a[o].gallery[e]&&(D(a[o].gallery[e],e),R(e))},U=function(e){a[o].sliderElements[e].classList.add("parvus__slide--is-active"),a[o].sliderElements[e].setAttribute("aria-hidden","false")},P=function(e,t){const n=document.createElement("img"),i=document.createElement("figure"),s=document.createElement("figcaption"),r=e.querySelector("img"),a=document.createElement("div");if(a.className="parvus__loader",a.setAttribute("role","progressbar"),a.setAttribute("aria-label",u.l10n.lightboxLoadingIndicatorLabel),t.appendChild(a),n.onload=()=>{t.removeChild(a),n.setAttribute("width",n.naturalWidth),n.setAttribute("height",n.naturalHeight)},"A"===e.tagName?(n.setAttribute("src",e.href),n.alt=r?r.alt||"":e.getAttribute("data-alt")||""):(n.alt=e.getAttribute("data-alt")||"",n.setAttribute("src",e.getAttribute("data-target"))),e.hasAttribute("data-srcset")&&""!==e.getAttribute("data-srcset")&&n.setAttribute("srcset",e.getAttribute("data-srcset")),n.style.opacity=0,i.appendChild(n),u.captions){let t=null;if("self"===u.captionsSelector)e.hasAttribute(u.captionsAttribute)&&""!==e.getAttribute(u.captionsAttribute)&&(t=e.getAttribute(u.captionsAttribute));else if(null!==e.querySelector(u.captionsSelector)){const n=e.querySelector(u.captionsSelector);t=n.hasAttribute(u.captionsAttribute)&&""!==n.getAttribute(u.captionsAttribute)?n.getAttribute(u.captionsAttribute):n.innerHTML}null!==t&&(s.innerHTML=`

${t}

`,i.appendChild(s))}t.appendChild(i)},R=function(e){const t=a[o].sliderElements[e].querySelector("img"),n=t.getBoundingClientRect(),i=a[o].gallery[e].getBoundingClientRect();c.classList.contains("parvus--is-opening")?(b=i.width/n.width,y=i.height/n.height,w=i.left-n.left,A=i.top-n.top,requestAnimationFrame((()=>{t.style.transform=`translate(${w}px, ${A}px) scale(${b}, ${y})`,t.style.transition="transform 0s, opacity 0s",requestAnimationFrame((()=>{t.style.transform="",t.style.opacity=1,t.style.transition=`transform ${B}ms ${u.transitionTimingFunction}, opacity ${B/2}ms ${u.transitionTimingFunction}`}))}))):t.style.opacity=1},j=function(e){const t=d;if(!be())throw new Error("Ups, I'm closed.");if(!e&&0!==e)throw new Error("Ups, no slide specified.");if(e===d)throw new Error(`Ups, slide ${e} is already selected.`);if(-1===e||e>=a[o].gallery.length)throw new Error(`Ups, I can't find slide ${e}.`);K(t),U(e),R(e),et&&(d++,V(),te(),G("right"),z(e+1)),Q();const n=new CustomEvent("select",{detail:{source:a[o].gallery[d]}});c.dispatchEvent(n)},W=function(){d>0&&j(d-1)},J=function(){d0&&n>=u.threshold&&d>0?W():L&&e<0&&n>=u.threshold&&d!==a[o].gallery.length-1?J():_&&i>0?i>=u.threshold&&u.swipeClose?O():(p.style.opacity=1,c.classList.remove("parvus--is-vertical-closing"),V()):V()},te=function(){(u.swipeClose&&!a[o].slider.classList.contains("parvus__slider--is-draggable")||a[o].gallery.length>1&&!a[o].slider.classList.contains("parvus__slider--is-draggable"))&&a[o].slider.classList.add("parvus__slider--is-draggable"),1===a[o].gallery.length?(h.setAttribute("aria-hidden","true"),h.disabled=!0,m.setAttribute("aria-hidden","true"),m.disabled=!0):0===d?(h.setAttribute("aria-hidden","true"),h.disabled=!0,m.setAttribute("aria-hidden","false"),m.disabled=!1):d===a[o].gallery.length-1?(h.setAttribute("aria-hidden","false"),h.disabled=!1,m.setAttribute("aria-hidden","true"),m.disabled=!0):(h.setAttribute("aria-hidden","false"),h.disabled=!1,m.setAttribute("aria-hidden","false"),m.disabled=!1),1===a[o].gallery.length?f.setAttribute("aria-hidden","true"):f.setAttribute("aria-hidden","false")},ne=function(){T||(T=!0,i.requestAnimationFrame((()=>{V(),T=!1})))},ie=function(e){e.preventDefault(),H(this)},se=function(e){e.target===h?W():e.target===m?J():(e.target===v||!_&&!L&&e.target.classList.contains("parvus__slide")&&u.docClose)&&O(),e.stopPropagation()},re=function(){return Array.prototype.slice.call(c.querySelectorAll(`${s.join(", ")}`)).filter((function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)}))},ae=function(){re()[0].focus()},le=function(e){const t=re(),n=t.indexOf(document.activeElement);"Tab"===e.code?e.shiftKey&&0===n?(t[t.length-1].focus(),e.preventDefault()):e.shiftKey||n!==t.length-1||(t[0].focus(),e.preventDefault()):"Escape"===e.code?(e.preventDefault(),O()):"ArrowLeft"===e.code?(e.preventDefault(),W()):"ArrowRight"===e.code&&(e.preventDefault(),J())},oe=function(){O()},de=function(e){e.preventDefault(),e.stopPropagation(),L=!1,_=!1,C=!0,E.startX=e.pageX,E.startY=e.pageY,a[o].slider.classList.add("parvus__slider--is-dragging"),a[o].slider.style.willChange="transform"},ue=function(e){e.preventDefault(),C&&(E.endX=e.pageX,E.endY=e.pageY,me())},ce=function(e){e.stopPropagation(),C=!1,a[o].slider.classList.remove("parvus__slider--is-dragging"),a[o].slider.style.willChange="auto",(E.endX||E.endY)&&ee(),Z()},pe=function(e){e.stopPropagation(),L=!1,_=!1,C=!0,E.startX=e.touches[0].pageX,E.startY=e.touches[0].pageY,a[o].slider.classList.add("parvus__slider--is-dragging"),a[o].slider.style.willChange="transform"},ge=function(e){e.stopPropagation(),C&&(e.preventDefault(),E.endX=e.touches[0].pageX,E.endY=e.touches[0].pageY,me())},he=function(e){e.stopPropagation(),C=!1,a[o].slider.classList.remove("parvus__slider--is-dragging"),a[o].slider.style.willChange="auto",(E.endX||E.endY)&&ee(),Z()},me=function(){const e=E.startX-E.endX,t=E.endY-E.startY,n=Math.abs(t);Math.abs(e)>0&&!_&&a[o].gallery.length>1?(a[o].slider.style.transform=`translate3d(${S-Math.round(e)}px, 0, 0)`,L=!0,_=!1):Math.abs(t)>0&&!L&&u.swipeClose&&(n<=96&&!M&&(g=1-n/100),c.classList.add("parvus--is-vertical-closing"),p.style.opacity=g,a[o].slider.style.transform=`translate3d(${S}px, ${Math.round(t)}px, 0)`,L=!1,_=!0)},ve=function(){i.addEventListener("keydown",le),i.addEventListener("resize",ne),u.scrollClose&&i.addEventListener("wheel",oe),i.addEventListener("popstate",O),c.addEventListener("click",se),ye()&&(c.addEventListener("touchstart",pe),c.addEventListener("touchmove",ge),c.addEventListener("touchend",he)),c.addEventListener("mousedown",de),c.addEventListener("mouseup",ce),c.addEventListener("mousemove",ue)},fe=function(){i.removeEventListener("keydown",le),i.removeEventListener("resize",ne),u.scrollClose&&i.removeEventListener("wheel",oe),i.removeEventListener("popstate",O),c.removeEventListener("click",se),ye()&&(c.removeEventListener("touchstart",pe),c.removeEventListener("touchmove",ge),c.removeEventListener("touchend",he)),c.removeEventListener("mousedown",de),c.removeEventListener("mouseup",ce),c.removeEventListener("mousemove",ue)},be=function(){return"false"===c.getAttribute("aria-hidden")},ye=function(){return"ontouchstart"in window};return X(n),t.init=X,t.open=H,t.close=O,t.select=j,t.previous=W,t.next=J,t.currentIndex=function(){return d},t.add=k,t.remove=F,t.destroy=function(){if(!c)return;be()&&O(),c.remove();document.querySelectorAll(".parvus-trigger").forEach((e=>{F(e)}));const e=new CustomEvent("destroy");c.dispatchEvent(e)},t.isOpen=be,t.on=function(e,t){c&&c.addEventListener(e,t)},t.off=function(e,t){c&&c.removeEventListener(e,t)},t}export{t as default}; +var e={lightboxLabel:"This is a dialog window which overlays the main content of the page. The modal shows the enlarged image. Pressing the Escape key will close the modal and bring you back to where you were on the page.",lightboxLoadingIndicatorLabel:"Image loading",previousButtonLabel:"Previous image",nextButtonLabel:"Next image",closeButtonLabel:"Close dialog window"};function t(n){const i=window,s=["button:not([disabled]):not([inert])",'[tabindex]:not([tabindex^="-"]):not([inert])'],a={gallery:[],slider:null,sliderElements:[],images:[]},r={};let l=null,o=null,d=0,u={},c=null,p=null,g=1,h=null,m=null,v=null,f=null,b=null,y=null,w=null,A=0,E=0,L=0,_=0,C={},x=!1,$=!1,S=!1,T=null,B=null,M=null,q=!1,F=null,I=!0;const N=window.matchMedia("(prefers-reduced-motion)"),X=function(){N.matches?(I=!0,F=u.reducedTransitionDuration):(I=!1,F=u.transitionDuration)};N.addEventListener("change",X);const Y=function(t){u=function(t){return{selector:".lightbox",gallerySelector:null,captions:!0,captionsSelector:"self",captionsAttribute:"data-caption",docClose:!0,scrollClose:!1,swipeClose:!0,threshold:50,backFocus:!0,transitionDuration:300,reducedTransitionDuration:.1,transitionTimingFunction:"cubic-bezier(0.4, 0, 0.22, 1)",lightboxIndicatorIcon:'',previousButtonIcon:'',nextButtonIcon:'',closeButtonIcon:'',l10n:e,fileTypes:/\.(png|jpe?g|webp|avif|svg)(\?.*)?$/i,...t}}(t);if(document.querySelectorAll(u.selector).length)if(X(),c||O(),null!==u.gallerySelector){document.querySelectorAll(u.gallerySelector).forEach(((e,t)=>{const n=t;e.querySelectorAll(u.selector).forEach((e=>{e.setAttribute("data-group",`parvus-gallery-${n}`),D(e)}))}));document.querySelectorAll(`${u.selector}:not(.parvus-trigger)`).forEach((e=>{D(e)}))}else{document.querySelectorAll(u.selector).forEach((e=>{D(e)}))}},k=function(e){const t=Math.floor(1e4*Math.random());return e.hasAttribute("data-group")&&""!==e.getAttribute("data-group")||e.setAttribute("data-group",`default-${t}`),e.getAttribute("data-group")},D=function(e){if(!("A"===e.tagName&&e.hasAttribute("href")&&e.href.match(u.fileTypes)||"BUTTON"===e.tagName&&e.hasAttribute("data-target")&&e.getAttribute("data-target").match(u.fileTypes)))throw new Error(e,`Use a link with the 'href' attribute or a button with the 'data-target' attribute. Both attributes must have a path to the image file. Supported image file types: ${u.fileTypes}.`);var t;if(l=k(e),Object.prototype.hasOwnProperty.call(r,l)||(r[l]=(t=a,JSON.parse(JSON.stringify(t)))),r[l].gallery.includes(e))throw new Error("Ups, element already added.");if(r[l].gallery.push(e),null!==e.querySelector("img")){const t=document.createElement("div");e.classList.add("parvus-zoom"),t.className="parvus-zoom__indicator",t.innerHTML=u.lightboxIndicatorIcon,e.appendChild(t)}e.classList.add("parvus-trigger"),e.addEventListener("click",le),Ee()&&l===o&&(z(e,r[l].gallery.indexOf(e)),J(r[l].gallery.indexOf(e)),se(),ee(),te())},H=function(e){if(Ee()||!c||!e||!e.hasAttribute("data-group"))return;const t=k(e);if(!r[t].gallery.includes(e))throw new Error("Ups, I can't find the element.");if(r[t].gallery.splice(r[t].gallery.indexOf(e),1),e.classList.contains("parvus-zoom")){const t=e.querySelector(".parvus-zoom__indicator");e.classList.remove("parvus-zoom"),e.removeChild(t)}e.removeEventListener("click",le),e.classList.remove("parvus-trigger")},O=function(){c=document.createElement("div"),c.setAttribute("role","dialog"),c.setAttribute("aria-modal","true"),c.setAttribute("aria-hidden","true"),c.setAttribute("tabindex","-1"),c.setAttribute("aria-label",u.l10n.lightboxLabel),c.classList.add("parvus"),p=document.createElement("div"),p.classList.add("parvus__overlay"),p.style.opacity=0,c.appendChild(p),h=document.createElement("div"),h.className="parvus__toolbar",m=document.createElement("div"),v=document.createElement("div"),y=document.createElement("button"),y.className="parvus__btn parvus__btn--close",y.setAttribute("type","button"),y.setAttribute("aria-label",u.l10n.closeButtonLabel),y.innerHTML=u.closeButtonIcon,v.appendChild(y),f=document.createElement("button"),f.className="parvus__btn parvus__btn--previous",f.setAttribute("type","button"),f.setAttribute("aria-label",u.l10n.previousButtonLabel),f.innerHTML=u.previousButtonIcon,c.appendChild(f),b=document.createElement("button"),b.className="parvus__btn parvus__btn--next",b.setAttribute("type","button"),b.setAttribute("aria-label",u.l10n.nextButtonLabel),b.innerHTML=u.nextButtonIcon,c.appendChild(b),w=document.createElement("div"),w.className="parvus__counter",m.appendChild(w),h.appendChild(m),h.appendChild(v),c.appendChild(h),document.body.appendChild(c)},z=function(e,t){const n=document.createElement("div"),i=document.createElement("div");n.className="parvus__slide",n.style.position="absolute",n.style.left=100*t+"%",n.setAttribute("aria-hidden","true"),j(t,e,i),n.appendChild(i),r[o].sliderElements[t]=n,t===d&&r[o].slider.appendChild(n),t>d?r[o].sliderElements[d].after(n):r[o].sliderElements[d].before(n)},U=function(e){if(!c||!e||!e.classList.contains("parvus-trigger")||Ee())return;if(o=k(e),!r[o].gallery.includes(e))throw new Error("Ups, I can't find the element.");d=r[o].gallery.indexOf(e),T=document.activeElement;const t=window.location.href;history.pushState({parvus:"close"},"Image",t),we();document.querySelectorAll('body > *:not([aria-hidden="true"])').forEach((e=>{e.setAttribute("aria-hidden","true"),e.classList.add("parvus-hidden")})),c.classList.add("parvus--is-opening"),c.setAttribute("aria-hidden","false"),r[o].slider=document.createElement("div"),r[o].slider.className="parvus__slider",r[o].slider.setAttribute("aria-hidden","true"),c.appendChild(r[o].slider),z(e,d),r[o].slider.setAttribute("aria-hidden","false"),Z(),se(),te(),ue(),W(d),J(d),requestAnimationFrame((()=>{c.classList.remove("parvus--is-opening"),p.style.opacity=1,p.style.transition=`opacity ${F}ms ${u.transitionTimingFunction}`,p.style.willChange="opacity"})),p.addEventListener("transitionend",(()=>{R(d+1),R(d-1)})),r[o].slider.classList.add("parvus__slider--animate");const n=new CustomEvent("open",{detail:{source:e}});c.dispatchEvent(n)},P=function(){if(!Ee())throw new Error("Ups, I'm already closed.");const e=r[o].images[d],t=e.getBoundingClientRect(),n=(u.backFocus?r[o].gallery[d]:T).getBoundingClientRect();Ae(),ne(),null!==history.state&&"close"===history.state.parvus&&history.back();document.querySelectorAll(".parvus-hidden").forEach((e=>{e.removeAttribute("aria-hidden"),e.classList.remove("parvus-hidden")})),c.classList.add("parvus--is-closing"),requestAnimationFrame((()=>{A=n.width/t.width,E=n.height/t.height,L=n.left-t.left,_=n.top-t.top,e.style.transform=`translate(${L}px, ${_}px) scale(${A}, ${E})`,e.style.opacity=0,e.style.transition=`transform ${F}ms ${u.transitionTimingFunction}, opacity ${F}ms ${u.transitionTimingFunction} ${F/2}ms`,p.style.opacity=0,p.style.transition=`opacity ${F}ms ${u.transitionTimingFunction}`,p.style.willChange="auto"})),p.addEventListener("transitionend",(()=>{Q(d),T=u.backFocus?r[o].gallery[d]:T,T.focus({preventScroll:!0}),c.setAttribute("aria-hidden","true"),c.classList.remove("parvus--is-closing"),c.classList.remove("parvus--is-vertical-closing"),r[o].slider.remove(),e.style.transform=""}),{once:!0});const i=new CustomEvent("close",{detail:{source:r[o].gallery[d]}});c.dispatchEvent(i)},R=function(e){void 0!==r[o].gallery[e]&&(z(r[o].gallery[e],e),J(e))},W=function(e){r[o].sliderElements[e].classList.add("parvus__slide--is-active"),r[o].sliderElements[e].setAttribute("aria-hidden","false"),re(r[o].sliderElements[e],r[o].images[e])},j=function(e,t,n){const i=document.createElement("img"),s=document.createElement("div"),a=document.createElement("div"),l=t.querySelector("img"),d=document.createElement("div");if(s.className="parvus__content",a.className="parvus__caption",d.className="parvus__loader",d.setAttribute("role","progressbar"),d.setAttribute("aria-label",u.l10n.lightboxLoadingIndicatorLabel),n.appendChild(d),i.onload=()=>{n.removeChild(d),i.setAttribute("width",i.naturalWidth),i.setAttribute("height",i.naturalHeight)},"A"===t.tagName?(i.setAttribute("src",t.href),i.alt=l?l.alt||"":t.getAttribute("data-alt")||""):(i.alt=t.getAttribute("data-alt")||"",i.setAttribute("src",t.getAttribute("data-target"))),t.hasAttribute("data-srcset")&&""!==t.getAttribute("data-srcset")&&i.setAttribute("srcset",t.getAttribute("data-srcset")),i.style.opacity=0,s.appendChild(i),r[o].images[e]=i,u.captions){let e=null;if("self"===u.captionsSelector)t.hasAttribute(u.captionsAttribute)&&""!==t.getAttribute(u.captionsAttribute)&&(e=t.getAttribute(u.captionsAttribute));else if(null!==t.querySelector(u.captionsSelector)){const n=t.querySelector(u.captionsSelector);e=n.hasAttribute(u.captionsAttribute)&&""!==n.getAttribute(u.captionsAttribute)?n.getAttribute(u.captionsAttribute):n.innerHTML}null!==e&&(a.innerHTML=`

${e}

`)}n.appendChild(s),n.appendChild(a)},J=function(e){const t=r[o].images[e],n=t.getBoundingClientRect(),i=r[o].gallery[e].getBoundingClientRect();c.classList.contains("parvus--is-opening")?(A=i.width/n.width,E=i.height/n.height,L=i.left-n.left,_=i.top-n.top,requestAnimationFrame((()=>{t.style.transform=`translate(${L}px, ${_}px) scale(${A}, ${E})`,t.style.transition="transform 0s, opacity 0s",requestAnimationFrame((()=>{t.style.transform="",t.style.opacity=1,t.style.transition=`transform ${F}ms ${u.transitionTimingFunction}, opacity ${F/2}ms ${u.transitionTimingFunction}`}))}))):t.style.opacity=1},K=function(e){const t=d;if(!Ee())throw new Error("Ups, I'm closed.");if(!e&&0!==e)throw new Error("Ups, no slide specified.");if(e===d)throw new Error(`Ups, slide ${e} is already selected.`);if(-1===e||e>=r[o].gallery.length)throw new Error(`Ups, I can't find slide ${e}.`);Q(t),W(e),J(e),et&&(d++,Z(),se(),ee("right"),R(e+1)),te();const n=new CustomEvent("select",{detail:{source:r[o].gallery[d]}});c.dispatchEvent(n)},V=function(){d>0&&K(d-1)},G=function(){d0&&n>=u.threshold&&d>0?V():x&&e<0&&n>=u.threshold&&d!==r[o].gallery.length-1?G():$&&i>0?i>=u.threshold&&u.swipeClose?P():(p.style.opacity=1,c.classList.remove("parvus--is-vertical-closing"),Z()):Z()},se=function(){(u.swipeClose&&!r[o].slider.classList.contains("parvus__slider--is-draggable")||r[o].gallery.length>1&&!r[o].slider.classList.contains("parvus__slider--is-draggable"))&&r[o].slider.classList.add("parvus__slider--is-draggable"),1===r[o].gallery.length?(f.setAttribute("aria-hidden","true"),f.disabled=!0,b.setAttribute("aria-hidden","true"),b.disabled=!0):0===d?(f.setAttribute("aria-hidden","true"),f.disabled=!0,b.setAttribute("aria-hidden","false"),b.disabled=!1):d===r[o].gallery.length-1?(f.setAttribute("aria-hidden","false"),f.disabled=!1,b.setAttribute("aria-hidden","true"),b.disabled=!0):(f.setAttribute("aria-hidden","false"),f.disabled=!1,b.setAttribute("aria-hidden","false"),b.disabled=!1),1===r[o].gallery.length?w.setAttribute("aria-hidden","true"):w.setAttribute("aria-hidden","false")},ae=function(){q||(q=!0,i.requestAnimationFrame((()=>{Z(),re(r[o].sliderElements[d],r[o].images[d]),q=!1})))},re=function(e,t){const n=getComputedStyle(e),i=e.querySelector(".parvus__caption").getBoundingClientRect(),s=t.naturalHeight,a=t.naturalWidth;let r=e.clientHeight,l=e.clientWidth;r-=parseFloat(n.paddingTop)+parseFloat(n.paddingBottom)+parseFloat(i.height),l-=parseFloat(n.paddingLeft)+parseFloat(n.paddingRight);const o=Math.min(l/a||0,r/s);t.style.width=`${a*o||0}px`,t.style.height=`${s*o||0}px`},le=function(e){e.preventDefault(),U(this)},oe=function(e){e.target===f?V():e.target===b?G():(e.target===y||!$&&!x&&e.target.classList.contains("parvus__slide")&&u.docClose)&&P(),e.stopPropagation()},de=function(){return Array.prototype.slice.call(c.querySelectorAll(`${s.join(", ")}`)).filter((function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)}))},ue=function(){de()[0].focus()},ce=function(e){const t=de(),n=t.indexOf(document.activeElement);"Tab"===e.code?e.shiftKey&&0===n?(t[t.length-1].focus(),e.preventDefault()):e.shiftKey||n!==t.length-1||(t[0].focus(),e.preventDefault()):"Escape"===e.code?(e.preventDefault(),P()):"ArrowLeft"===e.code?(e.preventDefault(),V()):"ArrowRight"===e.code&&(e.preventDefault(),G())},pe=function(){P()},ge=function(e){e.preventDefault(),e.stopPropagation(),x=!1,$=!1,S=!0,C.startX=e.pageX,C.startY=e.pageY,r[o].slider.classList.add("parvus__slider--is-dragging"),r[o].slider.style.willChange="transform"},he=function(e){e.preventDefault(),S&&(C.endX=e.pageX,C.endY=e.pageY,ye())},me=function(e){e.stopPropagation(),S=!1,r[o].slider.classList.remove("parvus__slider--is-dragging"),r[o].slider.style.willChange="auto",(C.endX||C.endY)&&ie(),ne()},ve=function(e){e.stopPropagation(),x=!1,$=!1,S=!0,C.startX=e.touches[0].pageX,C.startY=e.touches[0].pageY,r[o].slider.classList.add("parvus__slider--is-dragging"),r[o].slider.style.willChange="transform"},fe=function(e){e.stopPropagation(),S&&(e.preventDefault(),C.endX=e.touches[0].pageX,C.endY=e.touches[0].pageY,ye())},be=function(e){e.stopPropagation(),S=!1,r[o].slider.classList.remove("parvus__slider--is-dragging"),r[o].slider.style.willChange="auto",(C.endX||C.endY)&&ie(),ne()},ye=function(){const e=C.startX-C.endX,t=C.endY-C.startY,n=Math.abs(t);Math.abs(e)>0&&!$&&r[o].gallery.length>1?(r[o].slider.style.transform=`translate3d(${M-Math.round(e)}px, 0, 0)`,x=!0,$=!1):Math.abs(t)>0&&!x&&u.swipeClose&&(n<=96&&!I&&(g=1-n/100),c.classList.add("parvus--is-vertical-closing"),p.style.opacity=g,r[o].slider.style.transform=`translate3d(${M}px, ${Math.round(t)}px, 0)`,x=!1,$=!0)},we=function(){i.addEventListener("keydown",ce),i.addEventListener("resize",ae),u.scrollClose&&i.addEventListener("wheel",pe),i.addEventListener("popstate",P),c.addEventListener("click",oe),Le()&&(c.addEventListener("touchstart",ve),c.addEventListener("touchmove",fe),c.addEventListener("touchend",be)),c.addEventListener("mousedown",ge),c.addEventListener("mouseup",me),c.addEventListener("mousemove",he)},Ae=function(){i.removeEventListener("keydown",ce),i.removeEventListener("resize",ae),u.scrollClose&&i.removeEventListener("wheel",pe),i.removeEventListener("popstate",P),c.removeEventListener("click",oe),Le()&&(c.removeEventListener("touchstart",ve),c.removeEventListener("touchmove",fe),c.removeEventListener("touchend",be)),c.removeEventListener("mousedown",ge),c.removeEventListener("mouseup",me),c.removeEventListener("mousemove",he)},Ee=function(){return"false"===c.getAttribute("aria-hidden")},Le=function(){return"ontouchstart"in window};return Y(n),t.init=Y,t.open=U,t.close=P,t.select=K,t.previous=V,t.next=G,t.currentIndex=function(){return d},t.add=D,t.remove=H,t.destroy=function(){if(!c)return;Ee()&&P(),c.remove();document.querySelectorAll(".parvus-trigger").forEach((e=>{H(e)}));const e=new CustomEvent("destroy");c.dispatchEvent(e)},t.isOpen=Ee,t.on=function(e,t){c&&c.addEventListener(e,t)},t.off=function(e,t){c&&c.removeEventListener(e,t)},t}export{t as default}; diff --git a/dist/js/parvus.js b/dist/js/parvus.js index 9df8b53..e174b10 100644 --- a/dist/js/parvus.js +++ b/dist/js/parvus.js @@ -33,7 +33,8 @@ const GROUP_ATTS = { gallery: [], slider: null, - sliderElements: [] + sliderElements: [], + images: [] }; const GROUPS = {}; let newGroup = null; @@ -43,6 +44,9 @@ let lightbox = null; let lightboxOverlay = null; let lightboxOverlayOpacity = 1; + let toolbar = null; + let toolbarLeft = null; + let toolbarRight = null; let previousButton = null; let nextButton = null; let closeButton = null; @@ -289,15 +293,20 @@ lightboxOverlay.classList.add('parvus__overlay'); lightboxOverlay.style.opacity = 0; // Add lightbox overlay container to lightbox container - lightbox.appendChild(lightboxOverlay); // Create the close button + lightbox.appendChild(lightboxOverlay); // Create the toolbar + + toolbar = document.createElement('div'); + toolbar.className = 'parvus__toolbar'; + toolbarLeft = document.createElement('div'); + toolbarRight = document.createElement('div'); // Create the close button closeButton = document.createElement('button'); closeButton.className = 'parvus__btn parvus__btn--close'; closeButton.setAttribute('type', 'button'); closeButton.setAttribute('aria-label', config.l10n.closeButtonLabel); - closeButton.innerHTML = config.closeButtonIcon; // Add close button to lightbox container + closeButton.innerHTML = config.closeButtonIcon; // Add close button to right toolbar item - lightbox.appendChild(closeButton); // Create the previous button + toolbarRight.appendChild(closeButton); // Create the previous button previousButton = document.createElement('button'); previousButton.className = 'parvus__btn parvus__btn--previous'; @@ -316,9 +325,14 @@ lightbox.appendChild(nextButton); // Create the counter counter = document.createElement('div'); - counter.className = 'parvus__counter'; // Add counter to lightbox container + counter.className = 'parvus__counter'; // Add counter to left toolbar item + + toolbarLeft.appendChild(counter); // Add toolbar items to toolbar + + toolbar.appendChild(toolbarLeft); + toolbar.appendChild(toolbarRight); // Add toolbar to lightbox container - lightbox.appendChild(counter); // Add lightbox container to body + lightbox.appendChild(toolbar); // Add lightbox container to body document.body.appendChild(lightbox); }; @@ -349,7 +363,7 @@ SLIDER_ELEMENT.style.left = `${index * 100}%`; // Hide slide SLIDER_ELEMENT.setAttribute('aria-hidden', 'true'); - createImage(el, SLIDER_ELEMENT_CONTENT); // Add slide content container to slider element + createImage(index, el, SLIDER_ELEMENT_CONTENT); // Add slide content container to slider element SLIDER_ELEMENT.appendChild(SLIDER_ELEMENT_CONTENT); GROUPS[activeGroup].sliderElements[index] = SLIDER_ELEMENT; // Add slider element to slider @@ -444,8 +458,7 @@ throw new Error('Ups, I\'m already closed.'); } - const IMAGE_CONTAINER = GROUPS[activeGroup].sliderElements[currentIndex]; - const IMAGE = IMAGE_CONTAINER.querySelector('img'); + const IMAGE = GROUPS[activeGroup].images[currentIndex]; const IMAGE_SIZE = IMAGE.getBoundingClientRect(); const THUMBNAIL = config.backFocus ? GROUPS[activeGroup].gallery[currentIndex] : lastFocus; const THUMBNAIL_SIZE = THUMBNAIL.getBoundingClientRect(); @@ -528,6 +541,7 @@ const loadSlide = function loadSlide(index) { GROUPS[activeGroup].sliderElements[index].classList.add('parvus__slide--is-active'); GROUPS[activeGroup].sliderElements[index].setAttribute('aria-hidden', 'false'); + setImageDimension(GROUPS[activeGroup].sliderElements[index], GROUPS[activeGroup].images[index]); }; /** * Create Image @@ -536,12 +550,14 @@ */ - const createImage = function createImage(el, container) { + const createImage = function createImage(index, el, container) { const IMAGE = document.createElement('img'); - const FIGURE = document.createElement('figure'); - const FIGCAPTION = document.createElement('figcaption'); + const IMAGE_CONTAINER = document.createElement('div'); + const CAPTION_CONTAINER = document.createElement('div'); const THUMBNAIL = el.querySelector('img'); - const LOADING_INDICATOR = document.createElement('div'); // Create loading indicator + const LOADING_INDICATOR = document.createElement('div'); + IMAGE_CONTAINER.className = 'parvus__content'; + CAPTION_CONTAINER.className = 'parvus__caption'; // Create loading indicator LOADING_INDICATOR.className = 'parvus__loader'; LOADING_INDICATOR.setAttribute('role', 'progressbar'); @@ -575,7 +591,8 @@ } IMAGE.style.opacity = 0; - FIGURE.appendChild(IMAGE); // Add caption if available + IMAGE_CONTAINER.appendChild(IMAGE); + GROUPS[activeGroup].images[index] = IMAGE; // Add caption if available if (config.captions) { let captionData = null; @@ -597,12 +614,12 @@ } if (captionData !== null) { - FIGCAPTION.innerHTML = `

${captionData}

`; - FIGURE.appendChild(FIGCAPTION); + CAPTION_CONTAINER.innerHTML = `

${captionData}

`; } } - container.appendChild(FIGURE); + container.appendChild(IMAGE_CONTAINER); + container.appendChild(CAPTION_CONTAINER); }; /** * Load Image @@ -612,8 +629,7 @@ const loadImage = function loadImage(index) { - const IMAGE_CONTAINER = GROUPS[activeGroup].sliderElements[index]; - const IMAGE = IMAGE_CONTAINER.querySelector('img'); + const IMAGE = GROUPS[activeGroup].images[index]; const IMAGE_SIZE = IMAGE.getBoundingClientRect(); const THUMBNAIL = GROUPS[activeGroup].gallery[index]; const THUMBNAIL_SIZE = THUMBNAIL.getBoundingClientRect(); @@ -869,10 +885,32 @@ resizeTicking = true; BROWSER_WINDOW.requestAnimationFrame(() => { updateOffset(); + setImageDimension(GROUPS[activeGroup].sliderElements[currentIndex], GROUPS[activeGroup].images[currentIndex]); resizeTicking = false; }); } }; + /** + * Set image with + * + * @param {HTMLElement} slideEl + * @param {HTMLElement} imageEl + */ + + + const setImageDimension = function setImageDimension(slideEl, imageEl) { + const computedStyle = getComputedStyle(slideEl); + const captionRec = slideEl.querySelector('.parvus__caption').getBoundingClientRect(); + const srcHeight = imageEl.naturalHeight; + const srcWidth = imageEl.naturalWidth; + let maxHeight = slideEl.clientHeight; + let maxWidth = slideEl.clientWidth; + maxHeight -= parseFloat(computedStyle.paddingTop) + parseFloat(computedStyle.paddingBottom) + parseFloat(captionRec.height); + maxWidth -= parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight); + const ratio = Math.min(maxWidth / srcWidth || 0, maxHeight / srcHeight); + imageEl.style.width = `${srcWidth * ratio || 0}px`; + imageEl.style.height = `${srcHeight * ratio || 0}px`; + }; /** * Click event handler to trigger Parvus * diff --git a/dist/js/parvus.min.js b/dist/js/parvus.min.js index f0c1e85..3b40e70 100644 --- a/dist/js/parvus.min.js +++ b/dist/js/parvus.min.js @@ -8,4 +8,4 @@ * MIT license */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Parvus=t()}(this,(function(){"use strict";var e={lightboxLabel:"This is a dialog window which overlays the main content of the page. The modal shows the enlarged image. Pressing the Escape key will close the modal and bring you back to where you were on the page.",lightboxLoadingIndicatorLabel:"Image loading",previousButtonLabel:"Previous image",nextButtonLabel:"Next image",closeButtonLabel:"Close dialog window"};return function t(n){const i=window,s=["button:not([disabled]):not([inert])",'[tabindex]:not([tabindex^="-"]):not([inert])'],r={gallery:[],slider:null,sliderElements:[]},a={};let o=null,l=null,d=0,u={},c=null,p=null,g=1,h=null,f=null,m=null,v=null,b=0,y=0,w=0,A=0,E={},L=!1,_=!1,x=!1,C=null,$=null,S=null,T=!1,B=null,M=!0;const q=window.matchMedia("(prefers-reduced-motion)"),I=function(){q.matches?(M=!0,B=u.reducedTransitionDuration):(M=!1,B=u.transitionDuration)};q.addEventListener("change",I);const X=function(t){u=function(t){return{selector:".lightbox",gallerySelector:null,captions:!0,captionsSelector:"self",captionsAttribute:"data-caption",docClose:!0,scrollClose:!1,swipeClose:!0,threshold:50,backFocus:!0,transitionDuration:300,reducedTransitionDuration:.1,transitionTimingFunction:"cubic-bezier(0.4, 0, 0.22, 1)",lightboxIndicatorIcon:'',previousButtonIcon:'',nextButtonIcon:'',closeButtonIcon:'',l10n:e,fileTypes:/\.(png|jpe?g|webp|avif|svg)(\?.*)?$/i,...t}}(t);if(document.querySelectorAll(u.selector).length)if(I(),c||N(),null!==u.gallerySelector){document.querySelectorAll(u.gallerySelector).forEach(((e,t)=>{const n=t;e.querySelectorAll(u.selector).forEach((e=>{e.setAttribute("data-group",`parvus-gallery-${n}`),k(e)}))}));document.querySelectorAll(`${u.selector}:not(.parvus-trigger)`).forEach((e=>{k(e)}))}else{document.querySelectorAll(u.selector).forEach((e=>{k(e)}))}},Y=function(e){const t=Math.floor(1e4*Math.random());return e.hasAttribute("data-group")&&""!==e.getAttribute("data-group")||e.setAttribute("data-group",`default-${t}`),e.getAttribute("data-group")},k=function(e){if(!("A"===e.tagName&&e.hasAttribute("href")&&e.href.match(u.fileTypes)||"BUTTON"===e.tagName&&e.hasAttribute("data-target")&&e.getAttribute("data-target").match(u.fileTypes)))throw new Error(e,`Use a link with the 'href' attribute or a button with the 'data-target' attribute. Both attributes must have a path to the image file. Supported image file types: ${u.fileTypes}.`);var t;if(o=Y(e),Object.prototype.hasOwnProperty.call(a,o)||(a[o]=(t=r,JSON.parse(JSON.stringify(t)))),a[o].gallery.includes(e))throw new Error("Ups, element already added.");if(a[o].gallery.push(e),null!==e.querySelector("img")){const t=document.createElement("div");e.classList.add("parvus-zoom"),t.className="parvus-zoom__indicator",t.innerHTML=u.lightboxIndicatorIcon,e.appendChild(t)}e.classList.add("parvus-trigger"),e.addEventListener("click",ie),be()&&o===l&&(D(e,a[o].gallery.indexOf(e)),R(a[o].gallery.indexOf(e)),te(),G(),Q())},F=function(e){if(be()||!c||!e||!e.hasAttribute("data-group"))return;const t=Y(e);if(!a[t].gallery.includes(e))throw new Error("Ups, I can't find the element.");if(a[t].gallery.splice(a[t].gallery.indexOf(e),1),e.classList.contains("parvus-zoom")){const t=e.querySelector(".parvus-zoom__indicator");e.classList.remove("parvus-zoom"),e.removeChild(t)}e.removeEventListener("click",ie),e.classList.remove("parvus-trigger")},N=function(){c=document.createElement("div"),c.setAttribute("role","dialog"),c.setAttribute("aria-modal","true"),c.setAttribute("aria-hidden","true"),c.setAttribute("tabindex","-1"),c.setAttribute("aria-label",u.l10n.lightboxLabel),c.classList.add("parvus"),p=document.createElement("div"),p.classList.add("parvus__overlay"),p.style.opacity=0,c.appendChild(p),m=document.createElement("button"),m.className="parvus__btn parvus__btn--close",m.setAttribute("type","button"),m.setAttribute("aria-label",u.l10n.closeButtonLabel),m.innerHTML=u.closeButtonIcon,c.appendChild(m),h=document.createElement("button"),h.className="parvus__btn parvus__btn--previous",h.setAttribute("type","button"),h.setAttribute("aria-label",u.l10n.previousButtonLabel),h.innerHTML=u.previousButtonIcon,c.appendChild(h),f=document.createElement("button"),f.className="parvus__btn parvus__btn--next",f.setAttribute("type","button"),f.setAttribute("aria-label",u.l10n.nextButtonLabel),f.innerHTML=u.nextButtonIcon,c.appendChild(f),v=document.createElement("div"),v.className="parvus__counter",c.appendChild(v),document.body.appendChild(c)},D=function(e,t){const n=document.createElement("div"),i=document.createElement("div");n.className="parvus__slide",n.style.position="absolute",n.style.left=100*t+"%",n.setAttribute("aria-hidden","true"),U(e,i),n.appendChild(i),a[l].sliderElements[t]=n,t===d&&a[l].slider.appendChild(n),t>d?a[l].sliderElements[d].after(n):a[l].sliderElements[d].before(n)},H=function(e){if(!c||!e||!e.classList.contains("parvus-trigger")||be())return;if(l=Y(e),!a[l].gallery.includes(e))throw new Error("Ups, I can't find the element.");d=a[l].gallery.indexOf(e),C=document.activeElement;const t=window.location.href;history.pushState({parvus:"close"},"Image",t),me();document.querySelectorAll('body > *:not([aria-hidden="true"])').forEach((e=>{e.setAttribute("aria-hidden","true"),e.classList.add("parvus-hidden")})),c.classList.add("parvus--is-opening"),c.setAttribute("aria-hidden","false"),a[l].slider=document.createElement("div"),a[l].slider.className="parvus__slider",a[l].slider.setAttribute("aria-hidden","true"),c.appendChild(a[l].slider),D(e,d),a[l].slider.setAttribute("aria-hidden","false"),V(),te(),Q(),ae(),P(d),R(d),requestAnimationFrame((()=>{c.classList.remove("parvus--is-opening"),p.style.opacity=1,p.style.transition=`opacity ${B}ms ${u.transitionTimingFunction}`,p.style.willChange="opacity"})),p.addEventListener("transitionend",(()=>{z(d+1),z(d-1)})),a[l].slider.classList.add("parvus__slider--animate");const n=new CustomEvent("open",{detail:{source:e}});c.dispatchEvent(n)},O=function(){if(!be())throw new Error("Ups, I'm already closed.");const e=a[l].sliderElements[d].querySelector("img"),t=e.getBoundingClientRect(),n=(u.backFocus?a[l].gallery[d]:C).getBoundingClientRect();ve(),Z(),null!==history.state&&"close"===history.state.parvus&&history.back();document.querySelectorAll(".parvus-hidden").forEach((e=>{e.removeAttribute("aria-hidden"),e.classList.remove("parvus-hidden")})),c.classList.add("parvus--is-closing"),requestAnimationFrame((()=>{b=n.width/t.width,y=n.height/t.height,w=n.left-t.left,A=n.top-t.top,e.style.transform=`translate(${w}px, ${A}px) scale(${b}, ${y})`,e.style.opacity=0,e.style.transition=`transform ${B}ms ${u.transitionTimingFunction}, opacity ${B}ms ${u.transitionTimingFunction} ${B/2}ms`,p.style.opacity=0,p.style.transition=`opacity ${B}ms ${u.transitionTimingFunction}`,p.style.willChange="auto"})),p.addEventListener("transitionend",(()=>{K(d),C=u.backFocus?a[l].gallery[d]:C,C.focus({preventScroll:!0}),c.setAttribute("aria-hidden","true"),c.classList.remove("parvus--is-closing"),c.classList.remove("parvus--is-vertical-closing"),a[l].slider.remove(),e.style.transform=""}),{once:!0});const i=new CustomEvent("close",{detail:{source:a[l].gallery[d]}});c.dispatchEvent(i)},z=function(e){void 0!==a[l].gallery[e]&&(D(a[l].gallery[e],e),R(e))},P=function(e){a[l].sliderElements[e].classList.add("parvus__slide--is-active"),a[l].sliderElements[e].setAttribute("aria-hidden","false")},U=function(e,t){const n=document.createElement("img"),i=document.createElement("figure"),s=document.createElement("figcaption"),r=e.querySelector("img"),a=document.createElement("div");if(a.className="parvus__loader",a.setAttribute("role","progressbar"),a.setAttribute("aria-label",u.l10n.lightboxLoadingIndicatorLabel),t.appendChild(a),n.onload=()=>{t.removeChild(a),n.setAttribute("width",n.naturalWidth),n.setAttribute("height",n.naturalHeight)},"A"===e.tagName?(n.setAttribute("src",e.href),n.alt=r?r.alt||"":e.getAttribute("data-alt")||""):(n.alt=e.getAttribute("data-alt")||"",n.setAttribute("src",e.getAttribute("data-target"))),e.hasAttribute("data-srcset")&&""!==e.getAttribute("data-srcset")&&n.setAttribute("srcset",e.getAttribute("data-srcset")),n.style.opacity=0,i.appendChild(n),u.captions){let t=null;if("self"===u.captionsSelector)e.hasAttribute(u.captionsAttribute)&&""!==e.getAttribute(u.captionsAttribute)&&(t=e.getAttribute(u.captionsAttribute));else if(null!==e.querySelector(u.captionsSelector)){const n=e.querySelector(u.captionsSelector);t=n.hasAttribute(u.captionsAttribute)&&""!==n.getAttribute(u.captionsAttribute)?n.getAttribute(u.captionsAttribute):n.innerHTML}null!==t&&(s.innerHTML=`

${t}

`,i.appendChild(s))}t.appendChild(i)},R=function(e){const t=a[l].sliderElements[e].querySelector("img"),n=t.getBoundingClientRect(),i=a[l].gallery[e].getBoundingClientRect();c.classList.contains("parvus--is-opening")?(b=i.width/n.width,y=i.height/n.height,w=i.left-n.left,A=i.top-n.top,requestAnimationFrame((()=>{t.style.transform=`translate(${w}px, ${A}px) scale(${b}, ${y})`,t.style.transition="transform 0s, opacity 0s",requestAnimationFrame((()=>{t.style.transform="",t.style.opacity=1,t.style.transition=`transform ${B}ms ${u.transitionTimingFunction}, opacity ${B/2}ms ${u.transitionTimingFunction}`}))}))):t.style.opacity=1},j=function(e){const t=d;if(!be())throw new Error("Ups, I'm closed.");if(!e&&0!==e)throw new Error("Ups, no slide specified.");if(e===d)throw new Error(`Ups, slide ${e} is already selected.`);if(-1===e||e>=a[l].gallery.length)throw new Error(`Ups, I can't find slide ${e}.`);K(t),P(e),R(e),et&&(d++,V(),te(),G("right"),z(e+1)),Q();const n=new CustomEvent("select",{detail:{source:a[l].gallery[d]}});c.dispatchEvent(n)},W=function(){d>0&&j(d-1)},J=function(){d0&&n>=u.threshold&&d>0?W():L&&e<0&&n>=u.threshold&&d!==a[l].gallery.length-1?J():_&&i>0?i>=u.threshold&&u.swipeClose?O():(p.style.opacity=1,c.classList.remove("parvus--is-vertical-closing"),V()):V()},te=function(){(u.swipeClose&&!a[l].slider.classList.contains("parvus__slider--is-draggable")||a[l].gallery.length>1&&!a[l].slider.classList.contains("parvus__slider--is-draggable"))&&a[l].slider.classList.add("parvus__slider--is-draggable"),1===a[l].gallery.length?(h.setAttribute("aria-hidden","true"),h.disabled=!0,f.setAttribute("aria-hidden","true"),f.disabled=!0):0===d?(h.setAttribute("aria-hidden","true"),h.disabled=!0,f.setAttribute("aria-hidden","false"),f.disabled=!1):d===a[l].gallery.length-1?(h.setAttribute("aria-hidden","false"),h.disabled=!1,f.setAttribute("aria-hidden","true"),f.disabled=!0):(h.setAttribute("aria-hidden","false"),h.disabled=!1,f.setAttribute("aria-hidden","false"),f.disabled=!1),1===a[l].gallery.length?v.setAttribute("aria-hidden","true"):v.setAttribute("aria-hidden","false")},ne=function(){T||(T=!0,i.requestAnimationFrame((()=>{V(),T=!1})))},ie=function(e){e.preventDefault(),H(this)},se=function(e){e.target===h?W():e.target===f?J():(e.target===m||!_&&!L&&e.target.classList.contains("parvus__slide")&&u.docClose)&&O(),e.stopPropagation()},re=function(){return Array.prototype.slice.call(c.querySelectorAll(`${s.join(", ")}`)).filter((function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)}))},ae=function(){re()[0].focus()},oe=function(e){const t=re(),n=t.indexOf(document.activeElement);"Tab"===e.code?e.shiftKey&&0===n?(t[t.length-1].focus(),e.preventDefault()):e.shiftKey||n!==t.length-1||(t[0].focus(),e.preventDefault()):"Escape"===e.code?(e.preventDefault(),O()):"ArrowLeft"===e.code?(e.preventDefault(),W()):"ArrowRight"===e.code&&(e.preventDefault(),J())},le=function(){O()},de=function(e){e.preventDefault(),e.stopPropagation(),L=!1,_=!1,x=!0,E.startX=e.pageX,E.startY=e.pageY,a[l].slider.classList.add("parvus__slider--is-dragging"),a[l].slider.style.willChange="transform"},ue=function(e){e.preventDefault(),x&&(E.endX=e.pageX,E.endY=e.pageY,fe())},ce=function(e){e.stopPropagation(),x=!1,a[l].slider.classList.remove("parvus__slider--is-dragging"),a[l].slider.style.willChange="auto",(E.endX||E.endY)&&ee(),Z()},pe=function(e){e.stopPropagation(),L=!1,_=!1,x=!0,E.startX=e.touches[0].pageX,E.startY=e.touches[0].pageY,a[l].slider.classList.add("parvus__slider--is-dragging"),a[l].slider.style.willChange="transform"},ge=function(e){e.stopPropagation(),x&&(e.preventDefault(),E.endX=e.touches[0].pageX,E.endY=e.touches[0].pageY,fe())},he=function(e){e.stopPropagation(),x=!1,a[l].slider.classList.remove("parvus__slider--is-dragging"),a[l].slider.style.willChange="auto",(E.endX||E.endY)&&ee(),Z()},fe=function(){const e=E.startX-E.endX,t=E.endY-E.startY,n=Math.abs(t);Math.abs(e)>0&&!_&&a[l].gallery.length>1?(a[l].slider.style.transform=`translate3d(${S-Math.round(e)}px, 0, 0)`,L=!0,_=!1):Math.abs(t)>0&&!L&&u.swipeClose&&(n<=96&&!M&&(g=1-n/100),c.classList.add("parvus--is-vertical-closing"),p.style.opacity=g,a[l].slider.style.transform=`translate3d(${S}px, ${Math.round(t)}px, 0)`,L=!1,_=!0)},me=function(){i.addEventListener("keydown",oe),i.addEventListener("resize",ne),u.scrollClose&&i.addEventListener("wheel",le),i.addEventListener("popstate",O),c.addEventListener("click",se),ye()&&(c.addEventListener("touchstart",pe),c.addEventListener("touchmove",ge),c.addEventListener("touchend",he)),c.addEventListener("mousedown",de),c.addEventListener("mouseup",ce),c.addEventListener("mousemove",ue)},ve=function(){i.removeEventListener("keydown",oe),i.removeEventListener("resize",ne),u.scrollClose&&i.removeEventListener("wheel",le),i.removeEventListener("popstate",O),c.removeEventListener("click",se),ye()&&(c.removeEventListener("touchstart",pe),c.removeEventListener("touchmove",ge),c.removeEventListener("touchend",he)),c.removeEventListener("mousedown",de),c.removeEventListener("mouseup",ce),c.removeEventListener("mousemove",ue)},be=function(){return"false"===c.getAttribute("aria-hidden")},ye=function(){return"ontouchstart"in window};return X(n),t.init=X,t.open=H,t.close=O,t.select=j,t.previous=W,t.next=J,t.currentIndex=function(){return d},t.add=k,t.remove=F,t.destroy=function(){if(!c)return;be()&&O(),c.remove();document.querySelectorAll(".parvus-trigger").forEach((e=>{F(e)}));const e=new CustomEvent("destroy");c.dispatchEvent(e)},t.isOpen=be,t.on=function(e,t){c&&c.addEventListener(e,t)},t.off=function(e,t){c&&c.removeEventListener(e,t)},t}})); +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Parvus=t()}(this,(function(){"use strict";var e={lightboxLabel:"This is a dialog window which overlays the main content of the page. The modal shows the enlarged image. Pressing the Escape key will close the modal and bring you back to where you were on the page.",lightboxLoadingIndicatorLabel:"Image loading",previousButtonLabel:"Previous image",nextButtonLabel:"Next image",closeButtonLabel:"Close dialog window"};return function t(n){const i=window,s=["button:not([disabled]):not([inert])",'[tabindex]:not([tabindex^="-"]):not([inert])'],a={gallery:[],slider:null,sliderElements:[],images:[]},r={};let l=null,o=null,d=0,u={},c=null,p=null,g=1,h=null,m=null,v=null,f=null,b=null,y=null,w=null,A=0,E=0,L=0,_=0,C={},x=!1,$=!1,S=!1,T=null,B=null,M=null,q=!1,F=null,I=!0;const N=window.matchMedia("(prefers-reduced-motion)"),X=function(){N.matches?(I=!0,F=u.reducedTransitionDuration):(I=!1,F=u.transitionDuration)};N.addEventListener("change",X);const Y=function(t){u=function(t){return{selector:".lightbox",gallerySelector:null,captions:!0,captionsSelector:"self",captionsAttribute:"data-caption",docClose:!0,scrollClose:!1,swipeClose:!0,threshold:50,backFocus:!0,transitionDuration:300,reducedTransitionDuration:.1,transitionTimingFunction:"cubic-bezier(0.4, 0, 0.22, 1)",lightboxIndicatorIcon:'',previousButtonIcon:'',nextButtonIcon:'',closeButtonIcon:'',l10n:e,fileTypes:/\.(png|jpe?g|webp|avif|svg)(\?.*)?$/i,...t}}(t);if(document.querySelectorAll(u.selector).length)if(X(),c||O(),null!==u.gallerySelector){document.querySelectorAll(u.gallerySelector).forEach(((e,t)=>{const n=t;e.querySelectorAll(u.selector).forEach((e=>{e.setAttribute("data-group",`parvus-gallery-${n}`),D(e)}))}));document.querySelectorAll(`${u.selector}:not(.parvus-trigger)`).forEach((e=>{D(e)}))}else{document.querySelectorAll(u.selector).forEach((e=>{D(e)}))}},k=function(e){const t=Math.floor(1e4*Math.random());return e.hasAttribute("data-group")&&""!==e.getAttribute("data-group")||e.setAttribute("data-group",`default-${t}`),e.getAttribute("data-group")},D=function(e){if(!("A"===e.tagName&&e.hasAttribute("href")&&e.href.match(u.fileTypes)||"BUTTON"===e.tagName&&e.hasAttribute("data-target")&&e.getAttribute("data-target").match(u.fileTypes)))throw new Error(e,`Use a link with the 'href' attribute or a button with the 'data-target' attribute. Both attributes must have a path to the image file. Supported image file types: ${u.fileTypes}.`);var t;if(l=k(e),Object.prototype.hasOwnProperty.call(r,l)||(r[l]=(t=a,JSON.parse(JSON.stringify(t)))),r[l].gallery.includes(e))throw new Error("Ups, element already added.");if(r[l].gallery.push(e),null!==e.querySelector("img")){const t=document.createElement("div");e.classList.add("parvus-zoom"),t.className="parvus-zoom__indicator",t.innerHTML=u.lightboxIndicatorIcon,e.appendChild(t)}e.classList.add("parvus-trigger"),e.addEventListener("click",le),Ee()&&l===o&&(z(e,r[l].gallery.indexOf(e)),J(r[l].gallery.indexOf(e)),se(),ee(),te())},H=function(e){if(Ee()||!c||!e||!e.hasAttribute("data-group"))return;const t=k(e);if(!r[t].gallery.includes(e))throw new Error("Ups, I can't find the element.");if(r[t].gallery.splice(r[t].gallery.indexOf(e),1),e.classList.contains("parvus-zoom")){const t=e.querySelector(".parvus-zoom__indicator");e.classList.remove("parvus-zoom"),e.removeChild(t)}e.removeEventListener("click",le),e.classList.remove("parvus-trigger")},O=function(){c=document.createElement("div"),c.setAttribute("role","dialog"),c.setAttribute("aria-modal","true"),c.setAttribute("aria-hidden","true"),c.setAttribute("tabindex","-1"),c.setAttribute("aria-label",u.l10n.lightboxLabel),c.classList.add("parvus"),p=document.createElement("div"),p.classList.add("parvus__overlay"),p.style.opacity=0,c.appendChild(p),h=document.createElement("div"),h.className="parvus__toolbar",m=document.createElement("div"),v=document.createElement("div"),y=document.createElement("button"),y.className="parvus__btn parvus__btn--close",y.setAttribute("type","button"),y.setAttribute("aria-label",u.l10n.closeButtonLabel),y.innerHTML=u.closeButtonIcon,v.appendChild(y),f=document.createElement("button"),f.className="parvus__btn parvus__btn--previous",f.setAttribute("type","button"),f.setAttribute("aria-label",u.l10n.previousButtonLabel),f.innerHTML=u.previousButtonIcon,c.appendChild(f),b=document.createElement("button"),b.className="parvus__btn parvus__btn--next",b.setAttribute("type","button"),b.setAttribute("aria-label",u.l10n.nextButtonLabel),b.innerHTML=u.nextButtonIcon,c.appendChild(b),w=document.createElement("div"),w.className="parvus__counter",m.appendChild(w),h.appendChild(m),h.appendChild(v),c.appendChild(h),document.body.appendChild(c)},z=function(e,t){const n=document.createElement("div"),i=document.createElement("div");n.className="parvus__slide",n.style.position="absolute",n.style.left=100*t+"%",n.setAttribute("aria-hidden","true"),j(t,e,i),n.appendChild(i),r[o].sliderElements[t]=n,t===d&&r[o].slider.appendChild(n),t>d?r[o].sliderElements[d].after(n):r[o].sliderElements[d].before(n)},P=function(e){if(!c||!e||!e.classList.contains("parvus-trigger")||Ee())return;if(o=k(e),!r[o].gallery.includes(e))throw new Error("Ups, I can't find the element.");d=r[o].gallery.indexOf(e),T=document.activeElement;const t=window.location.href;history.pushState({parvus:"close"},"Image",t),we();document.querySelectorAll('body > *:not([aria-hidden="true"])').forEach((e=>{e.setAttribute("aria-hidden","true"),e.classList.add("parvus-hidden")})),c.classList.add("parvus--is-opening"),c.setAttribute("aria-hidden","false"),r[o].slider=document.createElement("div"),r[o].slider.className="parvus__slider",r[o].slider.setAttribute("aria-hidden","true"),c.appendChild(r[o].slider),z(e,d),r[o].slider.setAttribute("aria-hidden","false"),Z(),se(),te(),ue(),W(d),J(d),requestAnimationFrame((()=>{c.classList.remove("parvus--is-opening"),p.style.opacity=1,p.style.transition=`opacity ${F}ms ${u.transitionTimingFunction}`,p.style.willChange="opacity"})),p.addEventListener("transitionend",(()=>{R(d+1),R(d-1)})),r[o].slider.classList.add("parvus__slider--animate");const n=new CustomEvent("open",{detail:{source:e}});c.dispatchEvent(n)},U=function(){if(!Ee())throw new Error("Ups, I'm already closed.");const e=r[o].images[d],t=e.getBoundingClientRect(),n=(u.backFocus?r[o].gallery[d]:T).getBoundingClientRect();Ae(),ne(),null!==history.state&&"close"===history.state.parvus&&history.back();document.querySelectorAll(".parvus-hidden").forEach((e=>{e.removeAttribute("aria-hidden"),e.classList.remove("parvus-hidden")})),c.classList.add("parvus--is-closing"),requestAnimationFrame((()=>{A=n.width/t.width,E=n.height/t.height,L=n.left-t.left,_=n.top-t.top,e.style.transform=`translate(${L}px, ${_}px) scale(${A}, ${E})`,e.style.opacity=0,e.style.transition=`transform ${F}ms ${u.transitionTimingFunction}, opacity ${F}ms ${u.transitionTimingFunction} ${F/2}ms`,p.style.opacity=0,p.style.transition=`opacity ${F}ms ${u.transitionTimingFunction}`,p.style.willChange="auto"})),p.addEventListener("transitionend",(()=>{Q(d),T=u.backFocus?r[o].gallery[d]:T,T.focus({preventScroll:!0}),c.setAttribute("aria-hidden","true"),c.classList.remove("parvus--is-closing"),c.classList.remove("parvus--is-vertical-closing"),r[o].slider.remove(),e.style.transform=""}),{once:!0});const i=new CustomEvent("close",{detail:{source:r[o].gallery[d]}});c.dispatchEvent(i)},R=function(e){void 0!==r[o].gallery[e]&&(z(r[o].gallery[e],e),J(e))},W=function(e){r[o].sliderElements[e].classList.add("parvus__slide--is-active"),r[o].sliderElements[e].setAttribute("aria-hidden","false"),re(r[o].sliderElements[e],r[o].images[e])},j=function(e,t,n){const i=document.createElement("img"),s=document.createElement("div"),a=document.createElement("div"),l=t.querySelector("img"),d=document.createElement("div");if(s.className="parvus__content",a.className="parvus__caption",d.className="parvus__loader",d.setAttribute("role","progressbar"),d.setAttribute("aria-label",u.l10n.lightboxLoadingIndicatorLabel),n.appendChild(d),i.onload=()=>{n.removeChild(d),i.setAttribute("width",i.naturalWidth),i.setAttribute("height",i.naturalHeight)},"A"===t.tagName?(i.setAttribute("src",t.href),i.alt=l?l.alt||"":t.getAttribute("data-alt")||""):(i.alt=t.getAttribute("data-alt")||"",i.setAttribute("src",t.getAttribute("data-target"))),t.hasAttribute("data-srcset")&&""!==t.getAttribute("data-srcset")&&i.setAttribute("srcset",t.getAttribute("data-srcset")),i.style.opacity=0,s.appendChild(i),r[o].images[e]=i,u.captions){let e=null;if("self"===u.captionsSelector)t.hasAttribute(u.captionsAttribute)&&""!==t.getAttribute(u.captionsAttribute)&&(e=t.getAttribute(u.captionsAttribute));else if(null!==t.querySelector(u.captionsSelector)){const n=t.querySelector(u.captionsSelector);e=n.hasAttribute(u.captionsAttribute)&&""!==n.getAttribute(u.captionsAttribute)?n.getAttribute(u.captionsAttribute):n.innerHTML}null!==e&&(a.innerHTML=`

${e}

`)}n.appendChild(s),n.appendChild(a)},J=function(e){const t=r[o].images[e],n=t.getBoundingClientRect(),i=r[o].gallery[e].getBoundingClientRect();c.classList.contains("parvus--is-opening")?(A=i.width/n.width,E=i.height/n.height,L=i.left-n.left,_=i.top-n.top,requestAnimationFrame((()=>{t.style.transform=`translate(${L}px, ${_}px) scale(${A}, ${E})`,t.style.transition="transform 0s, opacity 0s",requestAnimationFrame((()=>{t.style.transform="",t.style.opacity=1,t.style.transition=`transform ${F}ms ${u.transitionTimingFunction}, opacity ${F/2}ms ${u.transitionTimingFunction}`}))}))):t.style.opacity=1},K=function(e){const t=d;if(!Ee())throw new Error("Ups, I'm closed.");if(!e&&0!==e)throw new Error("Ups, no slide specified.");if(e===d)throw new Error(`Ups, slide ${e} is already selected.`);if(-1===e||e>=r[o].gallery.length)throw new Error(`Ups, I can't find slide ${e}.`);Q(t),W(e),J(e),et&&(d++,Z(),se(),ee("right"),R(e+1)),te();const n=new CustomEvent("select",{detail:{source:r[o].gallery[d]}});c.dispatchEvent(n)},V=function(){d>0&&K(d-1)},G=function(){d0&&n>=u.threshold&&d>0?V():x&&e<0&&n>=u.threshold&&d!==r[o].gallery.length-1?G():$&&i>0?i>=u.threshold&&u.swipeClose?U():(p.style.opacity=1,c.classList.remove("parvus--is-vertical-closing"),Z()):Z()},se=function(){(u.swipeClose&&!r[o].slider.classList.contains("parvus__slider--is-draggable")||r[o].gallery.length>1&&!r[o].slider.classList.contains("parvus__slider--is-draggable"))&&r[o].slider.classList.add("parvus__slider--is-draggable"),1===r[o].gallery.length?(f.setAttribute("aria-hidden","true"),f.disabled=!0,b.setAttribute("aria-hidden","true"),b.disabled=!0):0===d?(f.setAttribute("aria-hidden","true"),f.disabled=!0,b.setAttribute("aria-hidden","false"),b.disabled=!1):d===r[o].gallery.length-1?(f.setAttribute("aria-hidden","false"),f.disabled=!1,b.setAttribute("aria-hidden","true"),b.disabled=!0):(f.setAttribute("aria-hidden","false"),f.disabled=!1,b.setAttribute("aria-hidden","false"),b.disabled=!1),1===r[o].gallery.length?w.setAttribute("aria-hidden","true"):w.setAttribute("aria-hidden","false")},ae=function(){q||(q=!0,i.requestAnimationFrame((()=>{Z(),re(r[o].sliderElements[d],r[o].images[d]),q=!1})))},re=function(e,t){const n=getComputedStyle(e),i=e.querySelector(".parvus__caption").getBoundingClientRect(),s=t.naturalHeight,a=t.naturalWidth;let r=e.clientHeight,l=e.clientWidth;r-=parseFloat(n.paddingTop)+parseFloat(n.paddingBottom)+parseFloat(i.height),l-=parseFloat(n.paddingLeft)+parseFloat(n.paddingRight);const o=Math.min(l/a||0,r/s);t.style.width=`${a*o||0}px`,t.style.height=`${s*o||0}px`},le=function(e){e.preventDefault(),P(this)},oe=function(e){e.target===f?V():e.target===b?G():(e.target===y||!$&&!x&&e.target.classList.contains("parvus__slide")&&u.docClose)&&U(),e.stopPropagation()},de=function(){return Array.prototype.slice.call(c.querySelectorAll(`${s.join(", ")}`)).filter((function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)}))},ue=function(){de()[0].focus()},ce=function(e){const t=de(),n=t.indexOf(document.activeElement);"Tab"===e.code?e.shiftKey&&0===n?(t[t.length-1].focus(),e.preventDefault()):e.shiftKey||n!==t.length-1||(t[0].focus(),e.preventDefault()):"Escape"===e.code?(e.preventDefault(),U()):"ArrowLeft"===e.code?(e.preventDefault(),V()):"ArrowRight"===e.code&&(e.preventDefault(),G())},pe=function(){U()},ge=function(e){e.preventDefault(),e.stopPropagation(),x=!1,$=!1,S=!0,C.startX=e.pageX,C.startY=e.pageY,r[o].slider.classList.add("parvus__slider--is-dragging"),r[o].slider.style.willChange="transform"},he=function(e){e.preventDefault(),S&&(C.endX=e.pageX,C.endY=e.pageY,ye())},me=function(e){e.stopPropagation(),S=!1,r[o].slider.classList.remove("parvus__slider--is-dragging"),r[o].slider.style.willChange="auto",(C.endX||C.endY)&&ie(),ne()},ve=function(e){e.stopPropagation(),x=!1,$=!1,S=!0,C.startX=e.touches[0].pageX,C.startY=e.touches[0].pageY,r[o].slider.classList.add("parvus__slider--is-dragging"),r[o].slider.style.willChange="transform"},fe=function(e){e.stopPropagation(),S&&(e.preventDefault(),C.endX=e.touches[0].pageX,C.endY=e.touches[0].pageY,ye())},be=function(e){e.stopPropagation(),S=!1,r[o].slider.classList.remove("parvus__slider--is-dragging"),r[o].slider.style.willChange="auto",(C.endX||C.endY)&&ie(),ne()},ye=function(){const e=C.startX-C.endX,t=C.endY-C.startY,n=Math.abs(t);Math.abs(e)>0&&!$&&r[o].gallery.length>1?(r[o].slider.style.transform=`translate3d(${M-Math.round(e)}px, 0, 0)`,x=!0,$=!1):Math.abs(t)>0&&!x&&u.swipeClose&&(n<=96&&!I&&(g=1-n/100),c.classList.add("parvus--is-vertical-closing"),p.style.opacity=g,r[o].slider.style.transform=`translate3d(${M}px, ${Math.round(t)}px, 0)`,x=!1,$=!0)},we=function(){i.addEventListener("keydown",ce),i.addEventListener("resize",ae),u.scrollClose&&i.addEventListener("wheel",pe),i.addEventListener("popstate",U),c.addEventListener("click",oe),Le()&&(c.addEventListener("touchstart",ve),c.addEventListener("touchmove",fe),c.addEventListener("touchend",be)),c.addEventListener("mousedown",ge),c.addEventListener("mouseup",me),c.addEventListener("mousemove",he)},Ae=function(){i.removeEventListener("keydown",ce),i.removeEventListener("resize",ae),u.scrollClose&&i.removeEventListener("wheel",pe),i.removeEventListener("popstate",U),c.removeEventListener("click",oe),Le()&&(c.removeEventListener("touchstart",ve),c.removeEventListener("touchmove",fe),c.removeEventListener("touchend",be)),c.removeEventListener("mousedown",ge),c.removeEventListener("mouseup",me),c.removeEventListener("mousemove",he)},Ee=function(){return"false"===c.getAttribute("aria-hidden")},Le=function(){return"ontouchstart"in window};return Y(n),t.init=Y,t.open=P,t.close=U,t.select=K,t.previous=V,t.next=G,t.currentIndex=function(){return d},t.add=D,t.remove=H,t.destroy=function(){if(!c)return;Ee()&&U(),c.remove();document.querySelectorAll(".parvus-trigger").forEach((e=>{H(e)}));const e=new CustomEvent("destroy");c.dispatchEvent(e)},t.isOpen=Ee,t.on=function(e,t){c&&c.addEventListener(e,t)},t.off=function(e,t){c&&c.removeEventListener(e,t)},t}})); diff --git a/src/js/parvus.js b/src/js/parvus.js index 1da4da3..1699f22 100644 --- a/src/js/parvus.js +++ b/src/js/parvus.js @@ -14,7 +14,8 @@ export default function Parvus (userOptions) { const GROUP_ATTS = { gallery: [], slider: null, - sliderElements: [] + sliderElements: [], + images: [] } const GROUPS = {} let newGroup = null @@ -24,6 +25,9 @@ export default function Parvus (userOptions) { let lightbox = null let lightboxOverlay = null let lightboxOverlayOpacity = 1 + let toolbar = null + let toolbarLeft = null + let toolbarRight = null let previousButton = null let nextButton = null let closeButton = null @@ -287,6 +291,14 @@ export default function Parvus (userOptions) { // Add lightbox overlay container to lightbox container lightbox.appendChild(lightboxOverlay) + // Create the toolbar + toolbar = document.createElement('div') + toolbar.className = 'parvus__toolbar' + + toolbarLeft = document.createElement('div') + + toolbarRight = document.createElement('div') + // Create the close button closeButton = document.createElement('button') closeButton.className = 'parvus__btn parvus__btn--close' @@ -294,8 +306,8 @@ export default function Parvus (userOptions) { closeButton.setAttribute('aria-label', config.l10n.closeButtonLabel) closeButton.innerHTML = config.closeButtonIcon - // Add close button to lightbox container - lightbox.appendChild(closeButton) + // Add close button to right toolbar item + toolbarRight.appendChild(closeButton) // Create the previous button previousButton = document.createElement('button') @@ -321,8 +333,15 @@ export default function Parvus (userOptions) { counter = document.createElement('div') counter.className = 'parvus__counter' - // Add counter to lightbox container - lightbox.appendChild(counter) + // Add counter to left toolbar item + toolbarLeft.appendChild(counter) + + // Add toolbar items to toolbar + toolbar.appendChild(toolbarLeft) + toolbar.appendChild(toolbarRight) + + // Add toolbar to lightbox container + lightbox.appendChild(toolbar) // Add lightbox container to body document.body.appendChild(lightbox) @@ -357,7 +376,7 @@ export default function Parvus (userOptions) { // Hide slide SLIDER_ELEMENT.setAttribute('aria-hidden', 'true') - createImage(el, SLIDER_ELEMENT_CONTENT) + createImage(index, el, SLIDER_ELEMENT_CONTENT) // Add slide content container to slider element SLIDER_ELEMENT.appendChild(SLIDER_ELEMENT_CONTENT) @@ -474,8 +493,7 @@ export default function Parvus (userOptions) { throw new Error('Ups, I\'m already closed.') } - const IMAGE_CONTAINER = GROUPS[activeGroup].sliderElements[currentIndex] - const IMAGE = IMAGE_CONTAINER.querySelector('img') + const IMAGE = GROUPS[activeGroup].images[currentIndex] const IMAGE_SIZE = IMAGE.getBoundingClientRect() const THUMBNAIL = config.backFocus ? GROUPS[activeGroup].gallery[currentIndex] : lastFocus const THUMBNAIL_SIZE = THUMBNAIL.getBoundingClientRect() @@ -574,6 +592,8 @@ export default function Parvus (userOptions) { const loadSlide = function loadSlide (index) { GROUPS[activeGroup].sliderElements[index].classList.add('parvus__slide--is-active') GROUPS[activeGroup].sliderElements[index].setAttribute('aria-hidden', 'false') + + setImageDimension(GROUPS[activeGroup].sliderElements[index], GROUPS[activeGroup].images[index]) } /** @@ -581,13 +601,16 @@ export default function Parvus (userOptions) { * * @param {number} index - Index to load */ - const createImage = function createImage (el, container) { + const createImage = function createImage (index, el, container) { const IMAGE = document.createElement('img') - const FIGURE = document.createElement('figure') - const FIGCAPTION = document.createElement('figcaption') + const IMAGE_CONTAINER = document.createElement('div') + const CAPTION_CONTAINER = document.createElement('div') const THUMBNAIL = el.querySelector('img') const LOADING_INDICATOR = document.createElement('div') + IMAGE_CONTAINER.className = 'parvus__content' + CAPTION_CONTAINER.className = 'parvus__caption' + // Create loading indicator LOADING_INDICATOR.className = 'parvus__loader' LOADING_INDICATOR.setAttribute('role', 'progressbar') @@ -624,7 +647,9 @@ export default function Parvus (userOptions) { IMAGE.style.opacity = 0 - FIGURE.appendChild(IMAGE) + IMAGE_CONTAINER.appendChild(IMAGE) + + GROUPS[activeGroup].images[index] = IMAGE // Add caption if available if (config.captions) { @@ -647,16 +672,12 @@ export default function Parvus (userOptions) { } if (captionData !== null) { - FIGCAPTION.innerHTML = `

${captionData}

` - - FIGURE.appendChild(FIGCAPTION) + CAPTION_CONTAINER.innerHTML = `

${captionData}

` } - - - } - container.appendChild(FIGURE) + container.appendChild(IMAGE_CONTAINER) + container.appendChild(CAPTION_CONTAINER) } /** @@ -665,8 +686,7 @@ export default function Parvus (userOptions) { * @param {number} index - Index to load */ const loadImage = function loadImage (index) { - const IMAGE_CONTAINER = GROUPS[activeGroup].sliderElements[index] - const IMAGE = IMAGE_CONTAINER.querySelector('img') + const IMAGE = GROUPS[activeGroup].images[index] const IMAGE_SIZE = IMAGE.getBoundingClientRect() const THUMBNAIL = GROUPS[activeGroup].gallery[index] const THUMBNAIL_SIZE = THUMBNAIL.getBoundingClientRect() @@ -925,12 +945,37 @@ export default function Parvus (userOptions) { BROWSER_WINDOW.requestAnimationFrame(() => { updateOffset() + setImageDimension(GROUPS[activeGroup].sliderElements[currentIndex], GROUPS[activeGroup].images[currentIndex]) resizeTicking = false }) } } + /** + * Set image with + * + * @param {HTMLElement} slideEl + * @param {HTMLElement} imageEl + */ + const setImageDimension = function setImageDimension (slideEl, imageEl) { + const computedStyle = getComputedStyle(slideEl) + const captionRec = slideEl.querySelector('.parvus__caption').getBoundingClientRect() + const srcHeight = imageEl.naturalHeight + const srcWidth = imageEl.naturalWidth + + let maxHeight = slideEl.clientHeight + let maxWidth = slideEl.clientWidth + + maxHeight -= parseFloat(computedStyle.paddingTop) + parseFloat(computedStyle.paddingBottom) + parseFloat(captionRec.height) + maxWidth -= parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight) + + const ratio = Math.min(maxWidth / srcWidth || 0, maxHeight / srcHeight) + + imageEl.style.width = `${srcWidth * ratio || 0}px` + imageEl.style.height = `${srcHeight * ratio || 0}px` + } + /** * Click event handler to trigger Parvus * diff --git a/src/scss/parvus.scss b/src/scss/parvus.scss index 331ce2d..2c99c82 100644 --- a/src/scss/parvus.scss +++ b/src/scss/parvus.scss @@ -13,9 +13,6 @@ --parvus-loader-background-color: hsl(23, 40%, 96%); --parvus-loader-color: hsl(228, 24%, 23%); - - --parvus-image-max-height: 85vh; - --parvus-image-max-width: 85vw; } /** @@ -123,9 +120,14 @@ &__slide { align-items: center; display: flex; - height: 100%; + flex-direction: column; + height: calc(100% - 4.75rem); justify-content: center; - width: 100%; + padding-bottom: 1rem; + padding-left: 1rem; + padding-right: 1rem; + padding-top: 3.75rem; + width: calc(100% - 2rem); @media screen and (prefers-reduced-motion: no-preference) { transition: visibility var(--parvus-transition-duration) var(--parvus-transition-timing-function); @@ -135,14 +137,10 @@ visibility: hidden; } - - & figure { - margin: 0; - } - - & figcaption { - padding: 1rem; - text-align: center; + & .parvus__caption { + color: var(--parvus-overlay-text); + padding-top: 0.5rem; + text-align: left; will-change: transform, opacity; @media screen and (prefers-reduced-motion: no-preference) { @@ -155,8 +153,6 @@ height: auto; margin-left: auto; margin-right: auto; - max-height: var(--parvus-image-max-height); - max-width: var(--parvus-image-max-width); transform-origin: left top; width: auto; } @@ -187,6 +183,16 @@ } } + &__toolbar { + align-items: center; + display: flex; + justify-content: space-between; + left: 1rem; + position: absolute; + right: 1rem; + top: 1rem; + } + &__btn { appearance: none; background-color: var(--parvus-button-color); @@ -198,6 +204,7 @@ display: flex; font: inherit; padding: 0.3125rem; + position: relative; touch-action: manipulation; will-change: transform, opacity; z-index: 7; @@ -213,9 +220,7 @@ &--close { - position: absolute; - right: 1rem; - top: 1rem; + } &--previous { @@ -249,14 +254,9 @@ } &__counter { - align-items: center; - display: flex; - justify-content: center; - left: 1rem; - min-height: 2.75rem; - min-width: 2.75rem; - position: absolute; - top: 1rem; + position: relative; + z-index: 7; + @media screen and (prefers-reduced-motion: no-preference) { transition: transform var(--parvus-transition-duration) var(--parvus-transition-timing-function), opacity var(--parvus-transition-duration) var(--parvus-transition-timing-function);