<section><a href="#selector" data-type="html" class="lightbox" data-group="inline">
		インラインのHTML
	</a>

	<div style="display: none;">
		<div id="selector" data-group="iframe">
			hogehoge
			<a href="#">foo</a>
		</div>
	</div>
</section>
<section>
	<a href="https://www.youtube.com/embed/Yds5jgqmYpE?autoplay=1" data-type="iframe" class="lightbox" data-group="iframe-youtube" data-width="1120" data-height="630">
		Youtube(直接リンクする場合)
	</a>
</section>
<section>
	<a href="#" data-type="youtube" data-id="RK1K2bCg4J8" class="lightbox" data-group="youtube">
		Youtube(idを指定するタイプ)
	</a>
</section>
<section>
	<a href="https://via.placeholder.com/600.jpg" class="lightbox" data-group="gallery">
		画像グループ1
	</a> | 
	<a href="https://via.placeholder.com/500.jpg" class="lightbox" data-group="gallery">
		画像グループ2
	</a> | 
	<a href="https://via.placeholder.com/300.jpg" class="lightbox" data-group="gallery">
		画像グループ3
	</a>
</section>

<section>

</section>
:root {
	--base-font-size: 18px;
	--transition-duration: 0.3s;
	--transition-timing-function: cubic-bezier(0.19, 1, 0.22, 1);
	--zoom-icon-background: rgba(25, 41, 56, 0.94);
	--zoom-icon-color: #fff;
	--lightbox-background: rgba(25, 41, 56, 0.94);
	--lightbox-z-index: 1337;
	--caption-background: hsla(0, 0%, 100%, 0.94);
	--caption-color: #192938;
	--counter-background: transparent;
	--counter-color: #fff;
	--button-background: transparent;
	--button-color: #fff;
	--loader-color: #fff;
	--slide-max-height: 85vh;
	--slide-max-width: 85vw;
}
.tobii-zoom {
	border: 0;
	box-shadow: none;
	display: inline-block;
	position: relative;
	text-decoration: none;
}
.tobii-zoom img {
	display: block;
}
.tobii-zoom__icon {
	align-items: center;
	background-color: var(--zoom-icon-background);
	top: 0.44444em;
	color: var(--zoom-icon-color);
	display: flex;
	height: 1.77778em;
	justify-content: center;
	line-height: 1;
	position: absolute;
	right: 0.44444em;
	width: 1.77778em;
}
.tobii-zoom__icon svg {
	fill: none;
	height: 1.33333em;
	pointer-events: none;
	stroke-linecap: round;
	stroke-linejoin: round;
	stroke-width: 1.5;
	stroke: currentColor;
	width: 1.33333em;
}
.tobii-is-open {
	overflow-y: hidden;
}
.tobii {
	background-color: var(--lightbox-background);
	bottom: 0;
	box-sizing: border-box;
	contain: strict;
	font-size: var(--base-font-size);
	left: 0;
	line-height: 1.5;
	overflow: hidden;
	position: fixed;
	right: 0;
	top: 0;
	z-index: var(--lightbox-z-index);
}
.tobii[aria-hidden="true"] {
	display: none;
}
.tobii *,
.tobii :after,
.tobii :before {
	box-sizing: inherit;
}
.tobii__slider {
	bottom: 0;
	left: 0;
	position: absolute;
	right: 0;
	top: 0;
	will-change: transform;
}
.tobii__slider[aria-hidden="true"] {
	display: none;
}
@media screen and (prefers-reduced-motion: no-preference) {
	.tobii__slider--animate:not(.tobii__slider--is-dragging) {
		transition-duration: var(--transition-duration);
		transition-property: transform;
		transition-timing-function: var(--transition-timing-function);
	}
}
.tobii__slider--is-draggable [data-type] {
	cursor: grab;
}
.tobii__slider--is-dragging [data-type] {
	cursor: grabbing;
}
.tobii__slide {
	align-items: center;
	display: flex;
	height: 100%;
	justify-content: center;
	width: 100%;
}
.tobii__slide:not(.tobii__slide--is-active) {
	visibility: hidden;
}
@media screen and (prefers-reduced-motion: no-preference) {
	.tobii__slide:not(.tobii__slide--is-active) {
		transition-duration: var(--transition-duration);
		transition-property: visibility;
		transition-timing-function: var(--transition-timing-function);
	}
}
.tobii__slide [data-type] {
	max-height: var(--slide-max-height);
	max-width: var(--slide-max-width);
	overflow: hidden;
	overflow-y: auto;
	-ms-scroll-chaining: none;
	overscroll-behavior: contain;
}
.tobii__slide iframe,
.tobii__slide video {
	display: block !important;
}
.tobii__slide figure {
	margin: 0;
	position: relative;
}
.tobii__slide figure > img {
	display: block;
	height: auto;
	max-height: var(--slide-max-height);
	max-width: var(--slide-max-width);
	width: auto;
}
.tobii__slide figure > figcaption {
	background-color: var(--caption-background);
	bottom: 0;
	color: var(--caption-color);
	padding: 0.22222em 0.44444em;
	position: absolute;
	white-space: pre-wrap;
	width: 100%;
}
.tobii__slide [data-type="html"] video {
	cursor: auto;
	max-height: var(--slide-max-height);
	max-width: var(--slide-max-width);
}
.tobii__slide [data-type="iframe"] {
	-webkit-overflow-scrolling: touch;
	transform: translateZ(0);
}
.tobii__slide [data-type="iframe"] iframe {
	height: var(--slide-max-height);
	width: var(--slide-max-width);
}
.tobii__btn {
	-webkit-appearance: none;
	appearance: none;
	background-color: var(--button-background);
	border: 0.05556em solid transparent;
	color: var(--button-color);
	cursor: pointer;
	font: inherit;
	line-height: 1;
	margin: 0;
	opacity: 0.5;
	padding: 0;
	position: absolute;
	touch-action: manipulation;
	will-change: opacity;
	z-index: 1;
}
@media screen and (prefers-reduced-motion: no-preference) {
	.tobii__btn {
		transition-duration: var(--transition-duration);
		transition-property: opacity, transform;
		transition-timing-function: var(--transition-timing-function);
		will-change: opacity, transform;
	}
}
.tobii__btn svg {
	fill: none;
	height: 3.33333em;
	pointer-events: none;
	stroke-linecap: round;
	stroke-linejoin: round;
	stroke-width: 1;
	stroke: currentColor;
	width: 3.33333em;
}
.tobii__btn:active,
.tobii__btn:focus,
.tobii__btn:hover {
	opacity: 1;
}
.tobii__btn--next,
.tobii__btn--previous {
	top: 50%;
	transform: translateY(-50%);
}
.tobii__btn--previous {
	left: 0.88889em;
}
.tobii__btn--next {
	right: 0.88889em;
}
.tobii__btn--close {
	right: 0.88889em;
	top: 0.88889em;
}
.tobii__btn:disabled,
.tobii__btn[aria-hidden="true"] {
	display: none;
}
.tobii__counter {
	background-color: var(--counter-background);
	color: var(--counter-color);
	font-size: 1.11111em;
	left: 1em;
	line-height: 1;
	position: absolute;
	top: 2.22222em;
	z-index: 1;
}
.tobii__counter[aria-hidden="true"] {
	display: none;
}
.tobii__loader {
	display: inline-block;
	height: 5.55556em;
	left: 50%;
	position: absolute;
	top: 50%;
	transform: translate(-50%, -50%);
	width: 5.55556em;
}
.tobii__loader:before {
	animation: spin 1s infinite;
	border-radius: 100%;
	border: 0.22222em solid #949ba3;
	border-top: 0.22222em solid var(--loader-color);
	bottom: 0;
	content: "";
	left: 0;
	position: absolute;
	right: 0;
	top: 0;
	z-index: 1;
}
@keyframes spin {
	to {
		transform: rotate(1turn);
	}
}
.tobii__slide .tobii-html {
	background: #fff;
	padding: 10px 20px;
	max-width: 800px;
}
section {
	margin: 1em;
}
/**
 * Tobii
 *
 * @author midzer
 * @version 2.0.7
 * @url https://github.com/midzer/tobii
 *
 * MIT License
 */
export default function Tobii(userOptions) {
	/**
	 * Global variables
	 *
	 */
	const FOCUSABLE_ELEMENTS = [
		'a[href]:not([tabindex^="-"]):not([inert])',
		'area[href]:not([tabindex^="-"]):not([inert])',
		"input:not([disabled]):not([inert])",
		"select:not([disabled]):not([inert])",
		"textarea:not([disabled]):not([inert])",
		"button:not([disabled]):not([inert])",
		'iframe:not([tabindex^="-"]):not([inert])',
		'audio:not([tabindex^="-"]):not([inert])',
		'video:not([tabindex^="-"]):not([inert])',
		'[contenteditable]:not([tabindex^="-"]):not([inert])',
		'[tabindex]:not([tabindex^="-"]):not([inert])'
	];
	const WAITING_ELS = [];
	const GROUP_ATTS = {
		gallery: [],
		slider: null,
		sliderElements: [],
		elementsLength: 0,
		currentIndex: 0,
		x: 0
	};
	const PLAYER = [];

	let config = {};
	let figcaptionId = 0;
	let lightbox = null;
	let prevButton = null;
	let nextButton = null;
	let closeButton = null;
	let counter = null;
	let drag = {};
	let isDraggingX = false;
	let isDraggingY = false;
	let pointerDown = false;
	let lastFocus = null;
	let offset = null;
	let offsetTmp = null;
	let resizeTicking = false;
	let isYouTubeDependencieLoaded = false;
	let playerId = 0;
	let groups = {};
	let newGroup = null;
	let activeGroup = null;

	/**
	 * Merge default options with user options
	 *
	 * @param {Object} userOptions - Optional user options
	 * @returns {Object} - Custom options
	 */
	const mergeOptions = (userOptions) => {
		// Default options
		const OPTIONS = {
			selector: ".lightbox",
			captions: true,
			captionsSelector: "img",
			captionAttribute: "alt",
			captionText: null,
			nav: "auto",
			navText: [
				'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path stroke="none" d="M0 0h24v24H0z"/><polyline points="15 6 9 12 15 18" /></svg>',
				'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path stroke="none" d="M0 0h24v24H0z"/><polyline points="9 6 15 12 9 18" /></svg>'
			],
			navLabel: ["Previous image", "Next image"],
			close: true,
			closeText:
				'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path stroke="none" d="M0 0h24v24H0z"/><line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" /></svg>',
			closeLabel: "Close lightbox",
			loadingIndicatorLabel: "Image loading",
			counter: true,
			download: false, // TODO
			downloadText: "", // TODO
			downloadLabel: "Download image", // TODO
			keyboard: true,
			zoom: true,
			zoomText:
				'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path stroke="none" d="M0 0h24v24H0z"/><polyline points="16 4 20 4 20 8" /><line x1="14" y1="10" x2="20" y2="4" /><polyline points="8 20 4 20 4 16" /><line x1="4" y1="20" x2="10" y2="14" /><polyline points="16 20 20 20 20 16" /><line x1="14" y1="14" x2="20" y2="20" /><polyline points="8 4 4 4 4 8" /><line x1="4" y1="4" x2="10" y2="10" /></svg>',
			docClose: true,
			swipeClose: true,
			hideScrollbar: true,
			draggable: true,
			threshold: 100,
			rtl: false, // TODO
			loop: false, // TODO
			autoplayVideo: false,
			modal: false,
			theme: "tobii--theme-default"
		};

		return {
			...OPTIONS,
			...userOptions
		};
	};

	/**
	 * Types - you can add new type to support something new
	 *
	 */
	const SUPPORTED_ELEMENTS = {
		image: {
			checkSupport(el) {
				return (
					!el.hasAttribute("data-type") &&
					el.href.match(/\.(png|jpe?g|tiff|tif|gif|bmp|webp|avif|svg|ico)(\?.*)?$/i)
				);
			},

			init(el, container) {
				const FIGURE = document.createElement("figure");
				const FIGCAPTION = document.createElement("figcaption");
				const IMAGE = document.createElement("img");
				const THUMBNAIL = el.querySelector("img");
				const LOADING_INDICATOR = document.createElement("div");

				// Hide figure until the image is loaded
				FIGURE.style.opacity = "0";

				if (THUMBNAIL) {
					IMAGE.alt = THUMBNAIL.alt || "";
				}

				IMAGE.setAttribute("src", "");
				IMAGE.setAttribute("data-src", el.href);

				if (el.hasAttribute("data-srcset")) {
					IMAGE.setAttribute("srcset", el.getAttribute("data-srcset"));
				}

				// Add image to figure
				FIGURE.appendChild(IMAGE);

				// Create figcaption
				if (config.captions) {
					if (typeof config.captionText === "function") {
						FIGCAPTION.textContent = config.captionText(el);
					} else if (
						config.captionsSelector === "self" &&
						el.getAttribute(config.captionAttribute)
					) {
						FIGCAPTION.textContent = el.getAttribute(config.captionAttribute);
					} else if (
						config.captionsSelector === "img" &&
						THUMBNAIL &&
						THUMBNAIL.getAttribute(config.captionAttribute)
					) {
						FIGCAPTION.textContent = THUMBNAIL.getAttribute(config.captionAttribute);
					}

					if (FIGCAPTION.textContent) {
						FIGCAPTION.id = `tobii-figcaption-${figcaptionId}`;
						FIGURE.appendChild(FIGCAPTION);

						IMAGE.setAttribute("aria-labelledby", FIGCAPTION.id);

						++figcaptionId;
					}
				}

				// Add figure to container
				container.appendChild(FIGURE);

				// Create loading indicator
				LOADING_INDICATOR.className = "tobii__loader";
				LOADING_INDICATOR.setAttribute("role", "progressbar");
				LOADING_INDICATOR.setAttribute("aria-label", config.loadingIndicatorLabel);

				// Add loading indicator to container
				container.appendChild(LOADING_INDICATOR);

				// Register type
				container.setAttribute("data-type", "image");
				container.classList.add("tobii-image");
			},

			onPreload(container) {
				// Same as preload
				SUPPORTED_ELEMENTS.image.onLoad(container);
			},

			onLoad(container) {
				const IMAGE = container.querySelector("img");

				if (!IMAGE.hasAttribute("data-src")) {
					return;
				}

				const FIGURE = container.querySelector("figure");
				const LOADING_INDICATOR = container.querySelector(".tobii__loader");

				IMAGE.onload = () => {
					container.removeChild(LOADING_INDICATOR);
					FIGURE.style.opacity = "1";
				};

				IMAGE.setAttribute("src", IMAGE.getAttribute("data-src"));
				IMAGE.removeAttribute("data-src");
			},

			onLeave(container) {
				// Nothing
			},

			onCleanup(container) {
				// Nothing
			}
		},

		html: {
			checkSupport(el) {
				return checkType(el, "html");
			},

			init(el, container) {
				const TARGET_SELECTOR = el.hasAttribute("data-target")
					? el.getAttribute("data-target")
					: el.getAttribute("href");
				const TARGET = document.querySelector(TARGET_SELECTOR);

				if (!TARGET) {
					throw new Error(`Ups, I can't find the target ${TARGET_SELECTOR}.`);
				}

				// Add content to container
				container.appendChild(TARGET);

				// Register type
				container.setAttribute("data-type", "html");
				container.classList.add("tobii-html");
			},

			onPreload(container) {
				// Nothing
			},

			onLoad(container) {
				const VIDEO = container.querySelector("video");

				if (VIDEO) {
					if (VIDEO.hasAttribute("data-time") && VIDEO.readyState > 0) {
						// Continue where video was stopped
						VIDEO.currentTime = VIDEO.getAttribute("data-time");
					}

					if (config.autoplayVideo) {
						// Start playback (and loading if necessary)
						VIDEO.play();
					}
				}
			},

			onLeave(container) {
				const VIDEO = container.querySelector("video");

				if (VIDEO) {
					if (!VIDEO.paused) {
						// Stop if video is playing
						VIDEO.pause();
					}

					// Backup currentTime (needed for revisit)
					if (VIDEO.readyState > 0) {
						VIDEO.setAttribute("data-time", VIDEO.currentTime);
					}
				}
			},

			onCleanup(container) {
				const VIDEO = container.querySelector("video");

				if (VIDEO) {
					if (
						VIDEO.readyState > 0 &&
						VIDEO.readyState < 3 &&
						VIDEO.duration !== VIDEO.currentTime
					) {
						// Some data has been loaded but not the whole package.
						// In order to save bandwidth, stop downloading as soon as possible.
						const VIDEO_CLONE = VIDEO.cloneNode(true);

						removeSources(VIDEO);
						VIDEO.load();

						VIDEO.parentNode.removeChild(VIDEO);

						container.appendChild(VIDEO_CLONE);
					}
				}
			}
		},

		iframe: {
			checkSupport(el) {
				return checkType(el, "iframe");
			},

			init(el, container) {
				const IFRAME = document.createElement("iframe");
				const HREF = el.hasAttribute("data-target")
					? el.getAttribute("data-target")
					: el.getAttribute("href");

				IFRAME.setAttribute("frameborder", "0");
				IFRAME.setAttribute("src", "");
				IFRAME.setAttribute("allowfullscreen", "");
				IFRAME.setAttribute("data-src", HREF);

				// Hide until loaded
				IFRAME.style.opacity = "0";

				// set allow parameters
				if (HREF.indexOf("youtube.com") > -1) {
					IFRAME.setAttribute(
						"allow",
						"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
					);
				} else if (HREF.indexOf("vimeo.com") > -1) {
					IFRAME.setAttribute("allow", "autoplay; picture-in-picture");
				} else if (el.hasAttribute("data-allow")) {
					IFRAME.setAttribute("allow", el.getAttribute("data-allow"));
				}

				if (el.getAttribute("data-width")) {
					IFRAME.style.maxWidth = `${el.getAttribute("data-width")}px`;
				}

				if (el.getAttribute("data-height")) {
					IFRAME.style.maxHeight = `${el.getAttribute("data-height")}px`;
				}

				// Add iframe to container
				container.appendChild(IFRAME);

				// Register type
				container.setAttribute("data-type", "iframe");
				container.classList.add("tobii-iframe");
			},

			onPreload(container) {
				// Nothing
			},

			onLoad(container) {
				const IFRAME = container.querySelector("iframe");
				IFRAME.setAttribute("src", IFRAME.getAttribute("data-src"));

				IFRAME.onload = () => {
					IFRAME.style.opacity = "1";
				};
			},

			onLeave(container) {
				// Nothing
			},

			onCleanup(container) {
				const IFRAME = container.querySelector("iframe");
				IFRAME.setAttribute("src", "");
				IFRAME.style.opacity = "0";
			}
		},

		youtube: {
			checkSupport(el) {
				return checkType(el, "youtube");
			},

			init(el, container) {
				const IFRAME_PLACEHOLDER = document.createElement("div");

				// Add iframePlaceholder to container
				container.appendChild(IFRAME_PLACEHOLDER);

				PLAYER[playerId] = new window.YT.Player(IFRAME_PLACEHOLDER, {
					host: "https://www.youtube-nocookie.com",
					height: el.getAttribute("data-height") || "360",
					width: el.getAttribute("data-width") || "640",
					videoId: el.getAttribute("data-id"),
					playerVars: {
						controls: el.getAttribute("data-controls") || 1,
						rel: 0,
						playsinline: 1
					}
				});

				// Set player ID
				container.setAttribute("data-player", playerId);

				// Register type
				container.setAttribute("data-type", "youtube");
				container.classList.add("tobii-youtube");

				playerId++;
			},

			onPreload(container) {
				// Nothing
			},

			onLoad(container) {
				if (config.autoplayVideo) {
					PLAYER[container.getAttribute("data-player")].playVideo();
				}
			},

			onLeave(container) {
				if (PLAYER[container.getAttribute("data-player")].getPlayerState() === 1) {
					PLAYER[container.getAttribute("data-player")].pauseVideo();
				}
			},

			onCleanup(container) {
				if (PLAYER[container.getAttribute("data-player")].getPlayerState() === 1) {
					PLAYER[container.getAttribute("data-player")].pauseVideo();
				}
			}
		}
	};

	/**
	 * Init
	 *
	 */
	const init = (userOptions) => {
		// Merge user options into defaults
		config = mergeOptions(userOptions);

		// Check if the lightbox already exists
		if (!lightbox) {
			createLightbox();
		}

		// Get a list of all elements within the document
		const LIGHTBOX_TRIGGER_ELS = document.querySelectorAll(config.selector);

		if (!LIGHTBOX_TRIGGER_ELS) {
			throw new Error(
				`Ups, I can't find the selector ${config.selector} on this website.`
			);
		}

		// Execute a few things once per element
		LIGHTBOX_TRIGGER_ELS.forEach((lightboxTriggerEl) => {
			checkDependencies(lightboxTriggerEl);
		});
	};

	/**
	 * Check dependencies
	 *
	 * @param {HTMLElement} el - Element to add
	 */
	const checkDependencies = (el) => {
		// Check if there is a YouTube video and if the YouTube iframe-API is ready
		if (
			document.querySelector('[data-type="youtube"]') !== null &&
			!isYouTubeDependencieLoaded
		) {
			if (document.getElementById("iframe_api") === null) {
				const TAG = document.createElement("script");
				const FIRST_SCRIPT_TAG = document.getElementsByTagName("script")[0];

				TAG.id = "iframe_api";
				TAG.src = "https://www.youtube.com/iframe_api";

				FIRST_SCRIPT_TAG.parentNode.insertBefore(TAG, FIRST_SCRIPT_TAG);
			}

			if (WAITING_ELS.indexOf(el) === -1) {
				WAITING_ELS.push(el);
			}

			window.onYouTubePlayerAPIReady = () => {
				WAITING_ELS.forEach((waitingEl) => {
					add(waitingEl);
				});

				isYouTubeDependencieLoaded = true;
			};
		} else {
			add(el);
		}
	};

	/**
	 * Get group name from element
	 *
	 * @param {HTMLElement} el
	 * @return {string}
	 */
	const getGroupName = (el) => {
		return el.hasAttribute("data-group")
			? el.getAttribute("data-group")
			: "default";
	};

	/**
	 * Copy an object. (The secure way)
	 *
	 * @param {object} object
	 * @return {object}
	 */
	const copyObject = (object) => {
		return JSON.parse(JSON.stringify(object));
	};

	/**
	 * Add element
	 *
	 * @param {HTMLElement} el - Element to add
	 */
	const add = (el) => {
		newGroup = getGroupName(el);

		if (!Object.prototype.hasOwnProperty.call(groups, newGroup)) {
			groups[newGroup] = copyObject(GROUP_ATTS);

			createSlider();
		}

		// Check if element already exists
		if (groups[newGroup].gallery.indexOf(el) === -1) {
			groups[newGroup].gallery.push(el);
			groups[newGroup].elementsLength++;

			// Set zoom icon if necessary
			if (config.zoom && el.querySelector("img")) {
				const TOBII_ZOOM = document.createElement("div");

				TOBII_ZOOM.className = "tobii-zoom__icon";
				TOBII_ZOOM.innerHTML = config.zoomText;

				el.classList.add("tobii-zoom");
				el.appendChild(TOBII_ZOOM);
			}

			// Bind click event handler
			el.addEventListener("click", triggerTobii);

			createSlide(el);

			if (isOpen() && newGroup === activeGroup) {
				updateConfig();
				updateLightbox();
			}
		} else {
			throw new Error("Ups, element already added.");
		}
	};

	/**
	 * Remove element
	 *
	 * @param {HTMLElement} el - Element to remove
	 */
	const remove = (el) => {
		const GROUP_NAME = getGroupName(el);

		// Check if element exists
		if (groups[GROUP_NAME].gallery.indexOf(el) === -1) {
			throw new Error(`Ups, I can't find a slide for the element ${el}.`);
		} else {
			const SLIDE_INDEX = groups[GROUP_NAME].gallery.indexOf(el);
			const SLIDE_EL = groups[GROUP_NAME].sliderElements[SLIDE_INDEX];

			// If the element to be removed is the currently visible slide
			if (
				isOpen() &&
				GROUP_NAME === activeGroup &&
				SLIDE_INDEX === groups[GROUP_NAME].currentIndex
			) {
				if (groups[GROUP_NAME].elementsLength === 1) {
					close();
					throw new Error("Ups, I've closed. There are no slides more to show.");
				} else {
					// TODO If there is only one slide left, deactivate horizontal dragging/ swiping
					// TODO Recalculate counter
					// TODO Set new absolute position per slide

					// If the first slide is displayed
					if (groups[GROUP_NAME].currentIndex === 0) {
						next();
					} else {
						previous();
					}
				}
			}

			// TODO Remove element
			// groups[GROUP_NAME].gallery.splice(groups[GROUP_NAME].gallery.indexOf(el)) don't work
			groups[GROUP_NAME].elementsLength--;

			// Remove zoom icon if necessary
			if (config.zoom && el.querySelector(".tobii-zoom__icon")) {
				const ZOOM_ICON = el.querySelector(".tobii-zoom__icon");

				ZOOM_ICON.parentNode.classList.remove("tobii-zoom");
				ZOOM_ICON.parentNode.removeChild(ZOOM_ICON);
			}

			// Unbind click event handler
			el.removeEventListener("click", triggerTobii);

			// Remove slide
			SLIDE_EL.parentNode.removeChild(SLIDE_EL);
		}
	};

	/**
	 * Create the lightbox
	 *
	 */
	const createLightbox = () => {
		// Create the lightbox container
		lightbox = document.createElement("div");
		lightbox.setAttribute("role", "dialog");
		lightbox.setAttribute("aria-hidden", "true");
		lightbox.classList.add("tobii");

		// Adc theme class
		lightbox.classList.add(config.theme);

		// Create the previous button
		prevButton = document.createElement("button");
		prevButton.className = "tobii__btn tobii__btn--previous";
		prevButton.setAttribute("type", "button");
		prevButton.setAttribute("aria-label", config.navLabel[0]);
		prevButton.innerHTML = config.navText[0];
		lightbox.appendChild(prevButton);

		// Create the next button
		nextButton = document.createElement("button");
		nextButton.className = "tobii__btn tobii__btn--next";
		nextButton.setAttribute("type", "button");
		nextButton.setAttribute("aria-label", config.navLabel[1]);
		nextButton.innerHTML = config.navText[1];
		lightbox.appendChild(nextButton);

		// Create the close button
		closeButton = document.createElement("button");
		closeButton.className = "tobii__btn tobii__btn--close";
		closeButton.setAttribute("type", "button");
		closeButton.setAttribute("aria-label", config.closeLabel);
		closeButton.innerHTML = config.closeText;
		lightbox.appendChild(closeButton);

		// Create the counter
		counter = document.createElement("div");
		counter.className = "tobii__counter";
		lightbox.appendChild(counter);

		document.body.appendChild(lightbox);
	};

	/**
	 * Create a slider
	 */
	const createSlider = () => {
		groups[newGroup].slider = document.createElement("div");
		groups[newGroup].slider.className = "tobii__slider";

		// Hide slider
		groups[newGroup].slider.setAttribute("aria-hidden", "true");

		lightbox.appendChild(groups[newGroup].slider);
	};

	/**
	 * Create a slide
	 *
	 */
	const createSlide = (el) => {
		// Detect type
		for (const index in SUPPORTED_ELEMENTS) {
			if (Object.prototype.hasOwnProperty.call(SUPPORTED_ELEMENTS, index)) {
				if (SUPPORTED_ELEMENTS[index].checkSupport(el)) {
					// Create slide elements
					const SLIDER_ELEMENT = document.createElement("div");
					const SLIDER_ELEMENT_CONTENT = document.createElement("div");

					SLIDER_ELEMENT.className = "tobii__slide";
					SLIDER_ELEMENT.style.position = "absolute";
					SLIDER_ELEMENT.style.left = `${groups[newGroup].x * 100}%`;

					// Hide slide
					SLIDER_ELEMENT.setAttribute("aria-hidden", "true");

					// Create type elements
					SUPPORTED_ELEMENTS[index].init(el, SLIDER_ELEMENT_CONTENT);

					// Add slide content container to slider element
					SLIDER_ELEMENT.appendChild(SLIDER_ELEMENT_CONTENT);

					// Add slider element to slider
					groups[newGroup].slider.appendChild(SLIDER_ELEMENT);
					groups[newGroup].sliderElements.push(SLIDER_ELEMENT);

					++groups[newGroup].x;

					break;
				}
			}
		}
	};

	/**
	 * Open Tobii
	 *
	 * @param {number} index - Index to load
	 */
	const open = (index) => {
		activeGroup = activeGroup !== null ? activeGroup : newGroup;

		if (isOpen()) {
			throw new Error("Ups, I'm aleady open.");
		}

		if (!isOpen()) {
			if (!index) {
				index = 0;
			}

			if (index === -1 || index >= groups[activeGroup].elementsLength) {
				throw new Error(`Ups, I can't find slide ${index}.`);
			}
		}

		if (config.hideScrollbar) {
			document.documentElement.classList.add("tobii-is-open");
			document.body.classList.add("tobii-is-open");
		}

		updateConfig();

		// Hide close if necessary
		if (!config.close) {
			closeButton.disabled = false;
			closeButton.setAttribute("aria-hidden", "true");
		}

		// Save user’s focus
		lastFocus = document.activeElement;

		// Use `history.pushState()` to make sure the "Back" button behavior
		// that aligns with the user's expectations
		const stateObj = {
			tobii: "close"
		};
		const url = window.location.href;

		window.history.pushState(stateObj, "Image", url);

		// Set current index
		groups[activeGroup].currentIndex = index;

		clearDrag();
		bindEvents();

		// Load slide
		load(groups[activeGroup].currentIndex);

		// Show slider
		groups[activeGroup].slider.setAttribute("aria-hidden", "false");

		// Show lightbox
		lightbox.setAttribute("aria-hidden", "false");

		updateLightbox();

		// Preload previous and next slide
		preload(groups[activeGroup].currentIndex + 1);
		preload(groups[activeGroup].currentIndex - 1);

		// Hack to prevent animation during opening
		setTimeout(() => {
			groups[activeGroup].slider.classList.add("tobii__slider--animate");
		}, 1000);

		// Create and dispatch a new event
		const openEvent = new window.CustomEvent("open", {
			detail: {
				group: activeGroup
			}
		});

		lightbox.dispatchEvent(openEvent);
	};

	/**
	 * Close Tobii
	 *
	 */
	const close = () => {
		if (!isOpen()) {
			throw new Error("Ups, I'm already closed.");
		}

		if (config.hideScrollbar) {
			document.documentElement.classList.remove("tobii-is-open");
			document.body.classList.remove("tobii-is-open");
		}

		unbindEvents();

		// Remove entry in browser history
		if (window.history.state !== null) {
			if (window.history.state.tobii === "close") {
				window.history.back();
			}
		}

		// Reenable the user’s focus
		lastFocus.focus();

		// Don't forget to cleanup our current element
		leave(groups[activeGroup].currentIndex);
		cleanup(groups[activeGroup].currentIndex);

		// Hide lightbox
		lightbox.setAttribute("aria-hidden", "true");

		// Hide slider
		groups[activeGroup].slider.setAttribute("aria-hidden", "true");

		// Reset current index
		groups[activeGroup].currentIndex = 0;

		// Remove the hack to prevent animation during opening
		groups[activeGroup].slider.classList.remove("tobii__slider--animate");

		// Create and dispatch a new event
		const closeEvent = new window.CustomEvent("close", {
			detail: {
				group: activeGroup
			}
		});
		lightbox.dispatchEvent(closeEvent);
	};

	/**
	 * Preload slide
	 *
	 * @param {number} index - Index to preload
	 */
	const preload = (index) => {
		if (groups[activeGroup].sliderElements[index] === undefined) {
			return;
		}

		const CONTAINER = groups[activeGroup].sliderElements[index].querySelector(
			"[data-type]"
		);
		const TYPE = CONTAINER.getAttribute("data-type");

		SUPPORTED_ELEMENTS[TYPE].onPreload(CONTAINER);
	};

	/**
	 * Load slide
	 * Will be called when opening the lightbox or moving index
	 *
	 * @param {number} index - Index to load
	 */
	const load = (index) => {
		if (groups[activeGroup].sliderElements[index] === undefined) {
			return;
		}

		const CONTAINER = groups[activeGroup].sliderElements[index].querySelector(
			"[data-type]"
		);
		const TYPE = CONTAINER.getAttribute("data-type");

		// Add active slide class
		groups[activeGroup].sliderElements[index].classList.add(
			"tobii__slide--is-active"
		);
		groups[activeGroup].sliderElements[index].setAttribute(
			"aria-hidden",
			"false"
		);

		SUPPORTED_ELEMENTS[TYPE].onLoad(CONTAINER);
	};

	/**
	 * Select a slide
	 *
	 * @param {number} index - Index to select
	 */
	const select = (index) => {
		const currIndex = groups[activeGroup].currentIndex;

		if (!isOpen()) {
			throw new Error("Ups, I'm closed.");
		}

		if (isOpen()) {
			if (!index && index !== 0) {
				throw new Error("Ups, no slide specified.");
			}

			if (index === groups[activeGroup].currentIndex) {
				throw new Error(`Ups, slide ${index} is already selected.`);
			}

			if (index === -1 || index >= groups[activeGroup].elementsLength) {
				throw new Error(`Ups, I can't find slide ${index}.`);
			}
		}

		// Set current index
		groups[activeGroup].currentIndex = index;

		leave(currIndex);
		load(index);

		if (index < currIndex) {
			updateLightbox("left");
			cleanup(currIndex);
			preload(index - 1);
		}

		if (index > currIndex) {
			updateLightbox("right");
			cleanup(currIndex);
			preload(index + 1);
		}
	};

	/**
	 * Select the previous slide
	 *
	 */
	const previous = () => {
		if (!isOpen()) {
			throw new Error("Ups, I'm closed.");
		}

		if (groups[activeGroup].currentIndex > 0) {
			leave(groups[activeGroup].currentIndex);
			load(--groups[activeGroup].currentIndex);
			updateLightbox("left");
			cleanup(groups[activeGroup].currentIndex + 1);
			preload(groups[activeGroup].currentIndex - 1);
		}

		// Create and dispatch a new event
		const previousEvent = new window.CustomEvent("previous", {
			detail: {
				group: activeGroup
			}
		});

		lightbox.dispatchEvent(previousEvent);
	};

	/**
	 * Select the next slide
	 *
	 */
	const next = () => {
		if (!isOpen()) {
			throw new Error("Ups, I'm closed.");
		}

		if (
			groups[activeGroup].currentIndex <
			groups[activeGroup].elementsLength - 1
		) {
			leave(groups[activeGroup].currentIndex);
			load(++groups[activeGroup].currentIndex);
			updateLightbox("right");
			cleanup(groups[activeGroup].currentIndex - 1);
			preload(groups[activeGroup].currentIndex + 1);
		}

		// Create and dispatch a new event
		const nextEvent = new window.CustomEvent("next", {
			detail: {
				group: activeGroup
			}
		});

		lightbox.dispatchEvent(nextEvent);
	};

	/**
	 * Select a group
	 *
	 * @param {string} name - Name of the group to select
	 */
	const selectGroup = (name) => {
		if (isOpen()) {
			throw new Error("Ups, I'm open.");
		}

		if (!name) {
			throw new Error("Ups, no group specified.");
		}

		if (name && !Object.prototype.hasOwnProperty.call(groups, name)) {
			throw new Error(`Ups, I don't have a group called "${name}".`);
		}

		activeGroup = name;
	};

	/**
	 * Leave slide
	 * Will be called before moving index
	 *
	 * @param {number} index - Index to leave
	 */
	const leave = (index) => {
		if (groups[activeGroup].sliderElements[index] === undefined) {
			return;
		}

		const CONTAINER = groups[activeGroup].sliderElements[index].querySelector(
			"[data-type]"
		);
		const TYPE = CONTAINER.getAttribute("data-type");

		// Remove active slide class
		groups[activeGroup].sliderElements[index].classList.remove(
			"tobii__slide--is-active"
		);
		groups[activeGroup].sliderElements[index].setAttribute("aria-hidden", "true");

		SUPPORTED_ELEMENTS[TYPE].onLeave(CONTAINER);
	};

	/**
	 * Cleanup slide
	 * Will be called after moving index
	 *
	 * @param {number} index - Index to cleanup
	 */
	const cleanup = (index) => {
		if (groups[activeGroup].sliderElements[index] === undefined) {
			return;
		}

		const CONTAINER = groups[activeGroup].sliderElements[index].querySelector(
			"[data-type]"
		);
		const TYPE = CONTAINER.getAttribute("data-type");

		SUPPORTED_ELEMENTS[TYPE].onCleanup(CONTAINER);
	};

	/**
	 * Update offset
	 *
	 */
	const updateOffset = () => {
		activeGroup = activeGroup !== null ? activeGroup : newGroup;

		offset = -groups[activeGroup].currentIndex * lightbox.offsetWidth;

		groups[activeGroup].slider.style.transform = `translate3d(${offset}px, 0, 0)`;
		offsetTmp = offset;
	};

	/**
	 * Update counter
	 *
	 */
	const updateCounter = () => {
		counter.textContent = `${groups[activeGroup].currentIndex + 1}/${
			groups[activeGroup].elementsLength
		}`;
	};

	/**
	 * Update focus
	 *
	 * @param {string} dir - Current slide direction
	 */
	const updateFocus = (dir) => {
		if (
			(config.nav === true || config.nav === "auto") &&
			!isTouchDevice() &&
			groups[activeGroup].elementsLength > 1
		) {
			prevButton.setAttribute("aria-hidden", "true");
			prevButton.disabled = true;
			nextButton.setAttribute("aria-hidden", "true");
			nextButton.disabled = true;

			// If there is only one slide
			if (groups[activeGroup].elementsLength === 1) {
				if (config.close) {
					closeButton.focus();
				}
			} else {
				// If the first slide is displayed
				if (groups[activeGroup].currentIndex === 0) {
					nextButton.setAttribute("aria-hidden", "false");
					nextButton.disabled = false;

					nextButton.focus();

					// If the last slide is displayed
				} else if (
					groups[activeGroup].currentIndex ===
					groups[activeGroup].elementsLength - 1
				) {
					prevButton.setAttribute("aria-hidden", "false");
					prevButton.disabled = false;

					prevButton.focus();
				} else {
					prevButton.setAttribute("aria-hidden", "false");
					prevButton.disabled = false;
					nextButton.setAttribute("aria-hidden", "false");
					nextButton.disabled = false;

					if (dir === "left") {
						prevButton.focus();
					} else {
						nextButton.focus();
					}
				}
			}
		} else if (config.close) {
			closeButton.focus();
		}
	};

	/**
	 * Clear drag after touchend and mousup event
	 *
	 */
	const clearDrag = () => {
		drag = {
			startX: 0,
			endX: 0,
			startY: 0,
			endY: 0
		};
	};

	/**
	 * Recalculate drag / swipe event
	 *
	 */
	const updateAfterDrag = () => {
		const MOVEMENT_X = drag.endX - drag.startX;
		const MOVEMENT_Y = drag.endY - drag.startY;
		const MOVEMENT_X_DISTANCE = Math.abs(MOVEMENT_X);
		const MOVEMENT_Y_DISTANCE = Math.abs(MOVEMENT_Y);

		if (
			MOVEMENT_X > 0 &&
			MOVEMENT_X_DISTANCE > config.threshold &&
			groups[activeGroup].currentIndex > 0
		) {
			previous();
		} else if (
			MOVEMENT_X < 0 &&
			MOVEMENT_X_DISTANCE > config.threshold &&
			groups[activeGroup].currentIndex !== groups[activeGroup].elementsLength - 1
		) {
			next();
		} else if (
			MOVEMENT_Y < 0 &&
			MOVEMENT_Y_DISTANCE > config.threshold &&
			config.swipeClose
		) {
			close();
		} else {
			updateOffset();
		}
	};

	/**
	 * Resize event using requestAnimationFrame
	 *
	 */
	const resizeHandler = () => {
		if (!resizeTicking) {
			resizeTicking = true;

			window.requestAnimationFrame(() => {
				updateOffset();

				resizeTicking = false;
			});
		}
	};

	/**
	 * Click event handler to trigger Tobii
	 *
	 */
	const triggerTobii = (event) => {
		event.preventDefault();

		activeGroup = getGroupName(event.currentTarget);

		open(groups[activeGroup].gallery.indexOf(event.currentTarget));
	};

	/**
	 * Click event handler
	 *
	 */
	const clickHandler = (event) => {
		if (event.target === prevButton) {
			previous();
		} else if (event.target === nextButton) {
			next();
		} else if (
			event.target === closeButton ||
			(isDraggingX === false &&
				isDraggingY === false &&
				event.target.classList.contains("tobii__slide") &&
				config.docClose)
		) {
			close();
		}

		event.stopPropagation();
	};

	/**
	 * Get the focusable children of the given element
	 *
	 * @return {Array<Element>}
	 */
	const getFocusableChildren = () => {
		return Array.prototype.slice
			.call(
				lightbox.querySelectorAll(
					`.tobii__btn:not([disabled]), .tobii__slide--is-active + ${FOCUSABLE_ELEMENTS.join(
						", .tobii__slide--is-active "
					)}`
				)
			)
			.filter((child) => {
				return !!(
					child.offsetWidth ||
					child.offsetHeight ||
					child.getClientRects().length
				);
			});
	};

	/**
	 * Keydown event handler
	 *
	 * @TODO: Remove the deprecated event.keyCode when Edge support event.code and we drop f*cking IE
	 * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
	 */
	const keydownHandler = (event) => {
		const FOCUSABLE_CHILDREN = getFocusableChildren();
		const FOCUSED_ITEM_INDEX = FOCUSABLE_CHILDREN.indexOf(document.activeElement);

		if (event.keyCode === 9 || event.code === "Tab") {
			// If the SHIFT key is being pressed while tabbing (moving backwards) and
			// the currently focused item is the first one, move the focus to the last
			// focusable item from the slide
			if (event.shiftKey && FOCUSED_ITEM_INDEX === 0) {
				FOCUSABLE_CHILDREN[FOCUSABLE_CHILDREN.length - 1].focus();
				event.preventDefault();
				// If the SHIFT key is not being pressed (moving forwards) and the currently
				// focused item is the last one, move the focus to the first focusable item
				// from the slide
			} else if (
				!event.shiftKey &&
				FOCUSED_ITEM_INDEX === FOCUSABLE_CHILDREN.length - 1
			) {
				FOCUSABLE_CHILDREN[0].focus();
				event.preventDefault();
			}
		} else if (event.keyCode === 27 || event.code === "Escape") {
			// `ESC` Key: Close Tobii
			event.preventDefault();
			close();
		} else if (event.keyCode === 37 || event.code === "ArrowLeft") {
			// `PREV` Key: Show the previous slide
			event.preventDefault();
			previous();
		} else if (event.keyCode === 39 || event.code === "ArrowRight") {
			// `NEXT` Key: Show the next slide
			event.preventDefault();
			next();
		}
	};

	/**
	 * Touchstart event handler
	 *
	 */
	const touchstartHandler = (event) => {
		// Prevent dragging / swiping on textareas inputs and selects
		if (isIgnoreElement(event.target)) {
			return;
		}

		event.stopPropagation();

		isDraggingX = false;
		isDraggingY = false;

		pointerDown = true;

		drag.startX = event.touches[0].pageX;
		drag.startY = event.touches[0].pageY;

		groups[activeGroup].slider.classList.add("tobii__slider--is-dragging");
	};

	/**
	 * Touchmove event handler
	 *
	 */
	const touchmoveHandler = (event) => {
		event.stopPropagation();

		if (pointerDown) {
			event.preventDefault();

			drag.endX = event.touches[0].pageX;
			drag.endY = event.touches[0].pageY;

			doSwipe();
		}
	};

	/**
	 * Touchend event handler
	 *
	 */
	const touchendHandler = (event) => {
		event.stopPropagation();

		pointerDown = false;

		groups[activeGroup].slider.classList.remove("tobii__slider--is-dragging");

		if (drag.endX) {
			updateAfterDrag();
		}

		clearDrag();
	};

	/**
	 * Mousedown event handler
	 *
	 */
	const mousedownHandler = (event) => {
		// Prevent dragging / swiping on textareas inputs and selects
		if (isIgnoreElement(event.target)) {
			return;
		}

		event.preventDefault();
		event.stopPropagation();

		isDraggingX = false;
		isDraggingY = false;

		pointerDown = true;

		drag.startX = event.pageX;
		drag.startY = event.pageY;

		groups[activeGroup].slider.classList.add("tobii__slider--is-dragging");
	};

	/**
	 * Mousemove event handler
	 *
	 */
	const mousemoveHandler = (event) => {
		event.preventDefault();

		if (pointerDown) {
			drag.endX = event.pageX;
			drag.endY = event.pageY;

			doSwipe();
		}
	};

	/**
	 * Mouseup event handler
	 *
	 */
	const mouseupHandler = (event) => {
		event.stopPropagation();

		pointerDown = false;

		groups[activeGroup].slider.classList.remove("tobii__slider--is-dragging");

		if (drag.endX) {
			updateAfterDrag();
		}

		clearDrag();
	};

	/**
	 * Contextmenu event handler
	 * This is a fix for chromium based browser on mac.
	 * The 'contextmenu' terminates a mouse event sequence.
	 * https://bugs.chromium.org/p/chromium/issues/detail?id=506801
	 *
	 */
	const contextmenuHandler = () => {
		pointerDown = false;
	};

	/**
	 * Decide whether to do horizontal of vertical swipe
	 *
	 */
	const doSwipe = () => {
		if (
			Math.abs(drag.startX - drag.endX) > 0 &&
			!isDraggingY &&
			groups[activeGroup].elementsLength > 1
		) {
			// Horizontal swipe
			groups[activeGroup].slider.style.transform = `translate3d(${
				offsetTmp - Math.round(drag.startX - drag.endX)
			}px, 0, 0)`;

			isDraggingX = true;
			isDraggingY = false;
		} else if (
			Math.abs(drag.startY - drag.endY) > 0 &&
			!isDraggingX &&
			config.swipeClose
		) {
			// Vertical swipe
			groups[
				activeGroup
			].slider.style.transform = `translate3d(${offsetTmp}px, -${Math.round(
				drag.startY - drag.endY
			)}px, 0)`;

			isDraggingX = false;
			isDraggingY = true;
		}
	};

	/**
	 * Bind events
	 *
	 */
	const bindEvents = () => {
		if (config.keyboard) {
			window.addEventListener("keydown", keydownHandler);
		}

		// Resize event
		window.addEventListener("resize", resizeHandler);

		// Popstate event
		window.addEventListener("popstate", close);

		// Click event
		lightbox.addEventListener("click", clickHandler);

		if (config.draggable) {
			if (isTouchDevice()) {
				// Touch events
				lightbox.addEventListener("touchstart", touchstartHandler);
				lightbox.addEventListener("touchmove", touchmoveHandler);
				lightbox.addEventListener("touchend", touchendHandler);
			}

			// Mouse events
			lightbox.addEventListener("mousedown", mousedownHandler);
			lightbox.addEventListener("mouseup", mouseupHandler);
			lightbox.addEventListener("mousemove", mousemoveHandler);
			lightbox.addEventListener("contextmenu", contextmenuHandler);
		}
	};

	/**
	 * Unbind events
	 *
	 */
	const unbindEvents = () => {
		if (config.keyboard) {
			window.removeEventListener("keydown", keydownHandler);
		}

		// Resize event
		window.removeEventListener("resize", resizeHandler);

		// Popstate event
		window.removeEventListener("popstate", close);

		// Click event
		lightbox.removeEventListener("click", clickHandler);

		if (config.draggable) {
			if (isTouchDevice()) {
				// Touch events
				lightbox.removeEventListener("touchstart", touchstartHandler);
				lightbox.removeEventListener("touchmove", touchmoveHandler);
				lightbox.removeEventListener("touchend", touchendHandler);
			}

			// Mouse events
			lightbox.removeEventListener("mousedown", mousedownHandler);
			lightbox.removeEventListener("mouseup", mouseupHandler);
			lightbox.removeEventListener("mousemove", mousemoveHandler);
			lightbox.removeEventListener("contextmenu", contextmenuHandler);
		}
	};

	/**
	 * Checks whether element has requested data-type value
	 *
	 */
	const checkType = (el, type) => {
		return el.getAttribute("data-type") === type;
	};

	/**
	 * Remove all `src` attributes
	 *
	 * @param {HTMLElement} el - Element to remove all `src` attributes
	 */
	const removeSources = (el) => {
		const SOURCES = el.querySelectorAll("src");

		if (SOURCES) {
			SOURCES.forEach((source) => {
				source.setAttribute("src", "");
			});
		}
	};

	/**
	 * Update Config
	 *
	 */
	const updateConfig = () => {
		if (
			(config.draggable &&
				config.swipeClose &&
				!groups[activeGroup].slider.classList.contains(
					"tobii__slider--is-draggable"
				)) ||
			(config.draggable &&
				groups[activeGroup].elementsLength > 1 &&
				!groups[activeGroup].slider.classList.contains(
					"tobii__slider--is-draggable"
				))
		) {
			groups[activeGroup].slider.classList.add("tobii__slider--is-draggable");
		}

		// Hide buttons if necessary
		if (
			!config.nav ||
			groups[activeGroup].elementsLength === 1 ||
			(config.nav === "auto" && isTouchDevice())
		) {
			prevButton.setAttribute("aria-hidden", "true");
			prevButton.disabled = true;
			nextButton.setAttribute("aria-hidden", "true");
			nextButton.disabled = true;
		} else {
			prevButton.setAttribute("aria-hidden", "false");
			prevButton.disabled = false;
			nextButton.setAttribute("aria-hidden", "false");
			nextButton.disabled = false;
		}

		// Hide counter if necessary
		if (!config.counter || groups[activeGroup].elementsLength === 1) {
			counter.setAttribute("aria-hidden", "true");
		} else {
			counter.setAttribute("aria-hidden", "false");
		}
	};

	/**
	 * Update lightbox
	 *
	 * @param {string} dir - Current slide direction
	 */
	const updateLightbox = (dir) => {
		updateOffset();
		updateCounter();
		updateFocus(dir);
	};

	/**
	 * Reset Tobii
	 *
	 */
	const reset = () => {
		if (isOpen()) {
			close();
		}

		// TODO Cleanup
		const GROUPS_ENTRIES = Object.entries(groups);

		GROUPS_ENTRIES.forEach((groupsEntrie) => {
			const SLIDE_ELS = groupsEntrie[1].gallery;

			// Remove slides
			SLIDE_ELS.forEach((slideEl) => {
				remove(slideEl);
			});
		});

		groups = {};
		newGroup = activeGroup = null;
		figcaptionId = 0;

		// TODO
	};

	/**
	 * Destroy Tobii
	 *
	 */
	const destroy = () => {
		reset();

		lightbox.parentNode.removeChild(lightbox);
	};

	/**
	 * Check if Tobii is open
	 *
	 */
	const isOpen = () => {
		return lightbox.getAttribute("aria-hidden") === "false";
	};

	/**
	 * Detect whether device is touch capable
	 *
	 */
	const isTouchDevice = () => {
		return "ontouchstart" in window;
	};

	/**
	 * Checks whether element's nodeName is part of array
	 *
	 */
	const isIgnoreElement = (el) => {
		return (
			["TEXTAREA", "OPTION", "INPUT", "SELECT"].indexOf(el.nodeName) !== -1 ||
			el === prevButton ||
			el === nextButton ||
			el === closeButton
		);
	};

	/**
	 * Return current index
	 *
	 */
	const slidesIndex = () => {
		return groups[activeGroup].currentIndex;
	};

	/**
	 * Return elements length
	 *
	 */
	const slidesCount = () => {
		return groups[activeGroup].elementsLength;
	};

	/**
	 * Return current group
	 *
	 */
	const currentGroup = () => {
		return activeGroup !== null ? activeGroup : newGroup;
	};

	/**
	 * Bind events
	 * @param {String} eventName
	 * @param {function} callback - callback to call
	 *
	 */
	const on = (eventName, callback) => {
		lightbox.addEventListener(eventName, callback);
	};

	/**
	 * Unbind events
	 * @param {String} eventName
	 * @param {function} callback - callback to call
	 *
	 */
	const off = (eventName, callback) => {
		lightbox.removeEventListener(eventName, callback);
	};

	init(userOptions);

	Tobii.open = open;
	Tobii.previous = previous;
	Tobii.next = next;
	Tobii.close = close;
	Tobii.add = checkDependencies;
	Tobii.remove = remove;
	Tobii.reset = reset;
	Tobii.destroy = destroy;
	Tobii.isOpen = isOpen;
	Tobii.slidesIndex = slidesIndex;
	Tobii.select = select;
	Tobii.slidesCount = slidesCount;
	Tobii.selectGroup = selectGroup;
	Tobii.currentGroup = currentGroup;
	Tobii.on = on;
	Tobii.off = off;

	return Tobii;
}
const tobii = new Tobii();

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.