UNPKG

maz-ui

Version:

A standalone components library for Vue.Js 3 & Nuxt.Js 3

287 lines (272 loc) 11.2 kB
const style = ` .maz-zoom-img { position: fixed; top: 0; bottom: 0; left: 0; right: 0; padding: 1rem; z-index: 1050; background-color: hsla(238, 15%, 40%, 0.7); display: flex; align-items: center; justify-content: center; flex-direction: column; } .maz-zoom-img, .maz-zoom-img * { box-sizing: border-box; } .maz-zoom-img .maz-zoom-img__wrapper { position: relative; display: flex; justify-content: center; align-items: center; min-width: 0; min-height: 0; max-width: 100%; max-height: 100%; transition: all 300ms ease-in-out; opacity: 0; transform: scale(0.5); } .maz-zoom-img.maz-animate .maz-zoom-img__wrapper { opacity: 1; transform: scale(1); } .maz-zoom-img.maz-animate .maz-zoom-img__loader { position: absolute; top: 0; bottom: 0; left: 0; right: 0; display: flex; align-items: center; justify-content: center; background-color: hsla(238, 15%, 40%, 0.7); border-radius: 1rem; z-index: 2; min-width: 60px; min-height: 60px; } .maz-zoom-img.maz-animate .maz-zoom-img__loader[hidden] { display: none; } @-webkit-keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .maz-zoom-img.maz-animate .maz-zoom-img__loader__svg { animation: spin .6s linear infinite; } .maz-zoom-img img { max-width: 100%; max-height: 100%; min-width: 0; border-radius: 1rem; } .maz-zoom-img .maz-zoom-btn { margin: 0 auto; border: none; background-color: hsla(0, 0%, 7%, 0.5); box-shadow: 0 0 0.5rem 0 hsla(0, 0%, 0%, 0.2); height: 2.2rem; min-height: 2.2rem; width: 2.2rem; min-width: 2.2rem; display: flex; align-items: center; justify-content: center; border-radius: 2.2rem; cursor: pointer; flex: 0 0 auto; outline: none; } .maz-zoom-img .maz-zoom-btn svg { fill: white; } .maz-zoom-img .maz-zoom-btn.maz-zoom-btn--close { position: absolute; top: 0.5rem; right: 0.5rem; z-index: 1; } .maz-zoom-img .maz-zoom-btn.maz-zoom-btn--previous { position: absolute; left: 0.5rem; z-index: 1; } .maz-zoom-img .maz-zoom-btn.maz-zoom-btn--next { position: absolute; right: 0.5rem; z-index: 1; } .maz-zoom-img .maz-zoom-btn:hover { background-color: hsl(0, 0%, 0%); }`, svgs = { close: '<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>', next: '<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>', previous: '<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>', spinner: '<svg width="40px" height="40px" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="currentColor" x="0px" y="0px" viewBox="0 0 50 50" xml:space="preserve" class="maz-zoom-img__loader__svg" data-v-6d1cb50c=""><path d="M43.935,25.145c0-10.318-8.364-18.683-18.683-18.683c-10.318,0-18.683,8.365-18.683,18.683h4.068c0-8.071,6.543-14.615,14.615-14.615c8.072,0,14.615,6.543,14.615,14.615H43.935z"></path></svg>' }; class ZoomImgHandler { options; loader; wrapper; img; keydownHandler; onImgLoadedCallback; buttonsAdded; defaultOptions = { scale: !0, blur: !0, disabled: !1 }; mouseEnterListener = void 0; mouseLeaveListener = void 0; renderPreviewListener = void 0; constructor(binding) { if (!binding.value) throw new Error( '[MazUI](zoom-img) Image path must be defined. Ex: `v-zoom-img="<PATH_TO_IMAGE>"`' ); if (typeof binding.value == "object" && !binding.value.src) throw new Error("[maz-ui](zoom-img) src of image must be provided"); this.buttonsAdded = !1, this.options = this.buildOptions(binding), this.keydownHandler = this.keydownLister.bind(this), this.loader = this.getLoader(), this.wrapper = document.createElement("div"), this.wrapper.classList.add("maz-zoom-img__wrapper"), this.wrapper.prepend(this.loader), this.img = document.createElement("img"), this.onImgLoadedCallback = this.onImgLoaded.bind(this), this.imgEventHandler(!0); } buildOptions(binding) { return { ...this.defaultOptions, ...typeof binding.value == "object" ? binding.value : { src: binding.value } }; } get allInstances() { return [...document.querySelectorAll(".maz-zoom-img-instance")]; } create(el) { this.options.disabled || (el.style.cursor = "pointer", setTimeout(() => el.classList.add("maz-zoom-img-instance")), el.setAttribute("data-zoom-src", this.options.src), this.options.alt && el.setAttribute("data-zoom-alt", this.options.alt), el.style.transition = "all 300ms ease-in-out", this.mouseEnterListener = () => this.mouseEnter(el), this.mouseLeaveListener = () => this.mouseLeave(el), this.renderPreviewListener = () => this.renderPreview(el, this.options), el.addEventListener("mouseenter", this.mouseEnterListener), el.addEventListener("mouseleave", this.mouseLeaveListener), el.addEventListener("click", this.renderPreviewListener)); } update(binding) { this.options = this.buildOptions(binding); } remove(el) { this.imgEventHandler(!1), this.mouseEnterListener && el.removeEventListener("mouseenter", this.mouseEnterListener), this.mouseLeaveListener && el.removeEventListener("mouseleave", this.mouseLeaveListener), this.renderPreviewListener && el.removeEventListener("click", this.renderPreviewListener), this.mouseEnterListener = void 0, this.mouseLeaveListener = void 0, this.renderPreviewListener = void 0, el.classList.remove("maz-zoom-img-instance"), el.removeAttribute("data-zoom-src"), el.removeAttribute("data-zoom-alt"), el.style.cursor = ""; } renderPreview(el, options) { el.classList.add( "maz-is-open" /* OPEN */ ), this.addStyle(style); const container = document.createElement("div"); container.classList.add("maz-zoom-img"), container.setAttribute("id", "MazImgPreviewFullsize"), container.addEventListener("click", (e) => { container.isEqualNode(e.target) && this.closePreview(); }), typeof options == "object" && (this.img.setAttribute("src", options.src), options.alt && this.img.setAttribute("alt", options.alt), this.img.id = "MazImgElement"), this.wrapper.append(this.img), container.append(this.wrapper), document.body.append(container), this.keyboardEventHandler(!0), setTimeout(() => { container && container.classList.add("maz-animate"); }, 100); } onImgLoaded() { this.wrapper.style.width = `${this.img.width}px`, this.wrapper.style.minWidth = "200px", this.loader.hidden = !0; const closeButton = this.getButton(), buttons = [], hasMultipleInstance = this.allInstances.length > 1; if (!this.buttonsAdded) { if (this.buttonsAdded = !0, hasMultipleInstance) { const previousButton = this.getButton("previous"), nextButton = this.getButton("next"); buttons.push(previousButton, nextButton); } this.wrapper.append(closeButton), hasMultipleInstance && (this.wrapper.prepend(buttons[0]), this.wrapper.append(buttons[1])); } } getLoader() { const loader = document.createElement("div"); return loader.classList.add("maz-zoom-img__loader"), loader.innerHTML = svgs.spinner, loader; } mouseLeave(el) { this.options.scale && (el.style.transform = ""), this.options.blur && (el.style.filter = ""), el.style.zIndex = ""; } mouseEnter(el) { el.style.zIndex = "1", this.options.scale && (el.style.transform = "scale(1.1)"), this.options.blur && (el.style.filter = "blur(2px)"); } keydownLister(e) { e.preventDefault(), (e.key === "Escape" || e.key === " ") && this.closePreview(), (e.key === "ArrowLeft" || e.key === "ArrowRight") && this.nextPreviousImage(e.key === "ArrowRight"); } getButton(iconName = "close") { const button = document.createElement("button"); button.innerHTML = svgs[iconName]; const getAction = () => iconName === "close" ? this.closePreview() : this.allInstances ? this.nextPreviousImage(iconName === "next") : null; return button.addEventListener("click", () => { getAction(); }), button.classList.add("maz-zoom-btn"), button.classList.add(`maz-zoom-btn--${iconName}`), button; } closePreview() { const container = document.querySelector("#MazImgPreviewFullsize"), style2 = document.querySelector("#MazPreviewStyle"), instance2 = document.querySelector( ".maz-zoom-img-instance.maz-is-open" ); instance2 && instance2.classList.remove( "maz-is-open" /* OPEN */ ), container && container.classList.remove("maz-animate"), this.keyboardEventHandler(!1), setTimeout(() => { container && container.remove(), style2 && style2.remove(); }, 300); } getNewInstanceIndex(newInstanceIndex) { let nextIndex = newInstanceIndex; return nextIndex < 0 ? nextIndex = this.allInstances.length - 1 : nextIndex >= this.allInstances.length && (nextIndex = 0), nextIndex; } nextPreviousImage(isNext) { const selectNextInstance = isNext, currentInstance = document.querySelector( ".maz-zoom-img-instance.maz-is-open" ); if (currentInstance) { const currentInstanceIndex = this.allInstances.indexOf(currentInstance), newInstanceIndex = selectNextInstance ? currentInstanceIndex + 1 : currentInstanceIndex - 1, nextInstance = this.allInstances[this.getNewInstanceIndex(newInstanceIndex)]; nextInstance && this.useNextInstance(currentInstance, nextInstance); } } useNextInstance(currentInstance, nextInstance) { currentInstance.classList.remove( "maz-is-open" /* OPEN */ ), nextInstance.classList.add( "maz-is-open" /* OPEN */ ); const src = nextInstance.getAttribute("data-zoom-src"), alt = nextInstance.getAttribute("data-zoom-alt"); this.wrapper.style.width = "", this.loader.hidden = !1, src && this.img.setAttribute("src", src), alt && this.img.setAttribute("alt", alt); } addStyle(styleString) { const style2 = document.createElement("style"); style2.id = "MazPreviewStyle", style2.textContent = styleString, document.head.append(style2); } keyboardEventHandler(add) { if (add) return document.addEventListener("keydown", this.keydownHandler); document.removeEventListener("keydown", this.keydownHandler); } imgEventHandler(add) { if (add) return this.img.addEventListener("load", this.onImgLoadedCallback); this.img.removeEventListener("load", this.onImgLoadedCallback); } } let instance; const vZoomImg = { created(el, binding) { instance = new ZoomImgHandler(binding), instance.create(el); }, updated(_el, binding) { instance.update(binding); }, unmounted(el) { instance.remove(el); } }, plugin = { install(app) { app.directive("zoom-img", vZoomImg); } }; export { vZoomImg, plugin as vZoomImgInstall };