UNPKG

@nextcloud/vue

Version:
423 lines (422 loc) 16.9 kB
import '../assets/NcModal-DLWvQ8EA.css'; import { getCurrentInstance, warn, defineComponent, mergeModels, useCssVars, computed, useModel, useTemplateRef, onMounted, onUnmounted, watch, toRef, ref, watchEffect, nextTick, createBlock, openBlock, Teleport, createVNode, Transition, withCtx, withDirectives, createElementVNode, mergeProps, unref, createElementBlock, createCommentVNode, toDisplayString, normalizeClass, renderSlot, withModifiers, vShow } from "vue"; import { C as mdiPause, D as mdiPlay, b as mdiClose, x as mdiChevronLeft, c as mdiChevronRight } from "./mdi-XFJRiRqJ.mjs"; import { useIntervalFn, useSwipe } from "@vueuse/core"; import { createFocusTrap } from "focus-trap"; import { N as NcActions } from "./NcActions-DWmvh7-Y.mjs"; import { N as NcButton } from "./NcButton-Dc8V4Urj.mjs"; import { N as NcIconSvgWrapper } from "./NcIconSvgWrapper-BvLanNaW.mjs"; import "../composables/useFormatDateTime/index.mjs"; import { useHotKey } from "../composables/useHotKey/index.mjs"; import "../composables/useIsDarkTheme/index.mjs"; import "../composables/useIsFullscreen/index.mjs"; import "../composables/useIsMobile/index.mjs"; import { r as register, a as t } from "./_l10n-DrTiip5c.mjs"; import { c as createElementId } from "./createElementId-DhjFt1I9.mjs"; import { g as getTrapStack } from "./focusTrap-HJQ4pqHV.mjs"; import { i as isRtl } from "./rtl-v0UOPAM7.mjs"; import { _ as _export_sfc } from "./_plugin-vue_export-helper-1tPrXgE0.mjs"; /*! * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ function getSameNodeParent(instance) { if (!instance.parent) { return null; } if ("vapor" in instance || "vapor" in instance.parent) { warn("Vapor instances are not supported in useScopeIdAttrs :("); return null; } if (instance.parent.subTree !== instance.vnode) { return null; } return instance.parent; } function getSameNodeAncestors(instance) { const ancestors = [instance]; let parent = getSameNodeParent(instance); while (parent) { ancestors.push(parent); parent = getSameNodeParent(parent); } return ancestors; } function useScopeIdAttrs() { const instance = getCurrentInstance(); if (!instance) { throw new Error("useScopeId must be called within a setup context"); } const sameNodeAncestors = getSameNodeAncestors(instance); const scopeIds = sameNodeAncestors.map((instance2) => instance2.vnode.scopeId).filter(Boolean); const scopeIdAttrs = Object.fromEntries(scopeIds.map((scopeId) => [scopeId, ""])); return scopeIdAttrs; } register(); const _hoisted_1 = ["aria-labelledby", "aria-describedby"]; const _hoisted_2 = ["data-theme-light", "data-theme-dark"]; const _hoisted_3 = ["id"]; const _hoisted_4 = { class: "icons-menu" }; const _hoisted_5 = ["title"]; const _hoisted_6 = ["id"]; const _hoisted_7 = { class: "modal-container__content" }; const _sfc_main = /* @__PURE__ */ defineComponent({ ...{ inheritAttrs: false }, __name: "NcModal", props: /* @__PURE__ */ mergeModels({ name: { default: "" }, hasPrevious: { type: Boolean }, hasNext: { type: Boolean }, outTransition: { type: Boolean }, enableSlideshow: { type: Boolean }, slideshowDelay: { default: 5e3 }, slideshowPaused: { type: Boolean }, disableSwipe: { type: Boolean }, spreadNavigation: { type: Boolean }, size: { default: "normal" }, noClose: { type: Boolean }, closeOnClickOutside: { type: Boolean }, dark: { type: Boolean }, lightBackdrop: { type: Boolean }, container: { default: "body" }, closeButtonOutside: { type: Boolean }, additionalTrapElements: { default: () => [] }, inlineActions: { default: 0 }, labelId: { default: "" }, setReturnFocus: { default: void 0 } }, { "show": { type: Boolean, ...{ default: true } }, "showModifiers": {} }), emits: /* @__PURE__ */ mergeModels(["next", "previous", "close", "update:show"], ["update:show"]), setup(__props, { emit: __emit }) { useCssVars((_ctx) => ({ "3caa6a4b": cssSlideshowDelay.value })); const showModal = useModel(__props, "show"); const props = __props; const emit = __emit; const scopeIdAttrs = useScopeIdAttrs(); const modalId = createElementId(); const maskElement = useTemplateRef("mask"); let focusTrap; onMounted(() => useFocusTrap()); onUnmounted(() => clearFocusTrap()); watch(() => props.additionalTrapElements, (elements) => { if (focusTrap) { focusTrap.updateContainerElements([maskElement.value, ...elements]); } }); const { isActive: isPlaying, pause: stopSlideshow, resume: startSlideshow } = useIntervalFn(nextSlide, toRef(() => props.slideshowDelay), { immediate: false }); const animationKey = ref(0); const runSlideshow = ref(false); watchEffect(() => { if (runSlideshow.value && !props.slideshowPaused) { startSlideshow(); } else if (isPlaying.value) { stopSlideshow(); } }); const cssSlideshowDelay = computed(() => `${props.slideshowDelay}ms`); const { stop: stopSwipe } = useSwipe(maskElement, { onSwipeEnd: handleSwipe }); onUnmounted(stopSwipe); useHotKey("Escape", () => { const trapStack = getTrapStack(); if (trapStack.at(-1) === focusTrap) { close(); } }, { allowInModal: true }); useHotKey(["ArrowLeft", "ArrowRight"], (event) => { if (document.activeElement && !maskElement.value.contains(document.activeElement)) { return; } if (event.key === "ArrowLeft" !== isRtl) { previousSlide(); } else { nextSlide(); } }, { allowInModal: true }); onMounted(() => { if (!props.name && !props.labelId) { warn("[NcModal] You need either set the name or set a `labelId` for accessibility."); } }); function nextSlide(event) { if (!props.hasNext) { runSlideshow.value = false; return; } if (event && isPlaying.value) { restartSlideshow(); } emit("next", event); } function previousSlide(event) { if (!props.hasPrevious) { return; } if (event && isPlaying.value) { restartSlideshow(); } emit("previous", event); } function handleSwipe(e, direction) { if (!props.disableSwipe) { if (direction !== "left" && direction !== "right") { return; } if (direction === "left" !== isRtl) { nextSlide(e); } else { previousSlide(e); } } } function restartSlideshow() { stopSlideshow(); startSlideshow(); animationKey.value++; } function close(event) { if (props.noClose) { return; } showModal.value = false; setTimeout(() => { emit("close", event); }, 300); } function handleClickModalWrapper(event) { if (props.closeOnClickOutside) { close(event); } } async function useFocusTrap() { if (!showModal.value || focusTrap) { return; } await nextTick(); const options = { allowOutsideClick: true, fallbackFocus: maskElement.value, trapStack: getTrapStack(), // Esc can be used without stop in content or additionalTrapElements where it should not deactivate modal's focus trap. // Focus trap is deactivated on modal close anyway. escapeDeactivates: false, setReturnFocus: props.setReturnFocus }; focusTrap = createFocusTrap([maskElement.value, ...props.additionalTrapElements], options); focusTrap.activate(); } function clearFocusTrap() { if (!focusTrap) { return; } focusTrap?.deactivate(); focusTrap = void 0; } return (_ctx, _cache) => { return openBlock(), createBlock(Teleport, { disabled: _ctx.container === null, to: _ctx.container }, [ createVNode(Transition, { name: "fade", appear: "", onAfterEnter: useFocusTrap, onBeforeLeave: clearFocusTrap }, { default: withCtx(() => [ withDirectives(createElementVNode("div", mergeProps({ ..._ctx.$attrs, ...unref(scopeIdAttrs) }, { ref: "mask", class: ["modal-mask", { "modal-mask--opaque": _ctx.dark || _ctx.closeButtonOutside || _ctx.hasPrevious || _ctx.hasNext, "modal-mask--light": _ctx.lightBackdrop }], role: "dialog", "aria-modal": "true", "aria-labelledby": _ctx.labelId || `modal-name-${unref(modalId)}`, "aria-describedby": "modal-description-" + unref(modalId), tabindex: "-1" }), [ createVNode(Transition, { name: "fade-visibility", appear: "" }, { default: withCtx(() => [ createElementVNode("div", { class: "modal-header", "data-theme-light": _ctx.lightBackdrop, "data-theme-dark": !_ctx.lightBackdrop }, [ _ctx.name.trim() !== "" ? (openBlock(), createElementBlock("h2", { key: 0, id: "modal-name-" + unref(modalId), class: "modal-header__name" }, toDisplayString(_ctx.name), 9, _hoisted_3)) : createCommentVNode("", true), createElementVNode("div", _hoisted_4, [ _ctx.hasNext && _ctx.enableSlideshow ? (openBlock(), createElementBlock("button", { key: 0, class: normalizeClass(["play-pause-icons", { "play-pause-icons--paused": _ctx.slideshowPaused }]), title: unref(isPlaying) ? unref(t)("Pause slideshow") : unref(t)("Start slideshow"), type: "button", onClick: _cache[0] || (_cache[0] = ($event) => runSlideshow.value = !runSlideshow.value) }, [ createVNode(NcIconSvgWrapper, { class: "play-pause-icons__icon", inline: "", name: unref(isPlaying) ? unref(t)("Pause slideshow") : unref(t)("Start slideshow"), path: unref(isPlaying) ? unref(mdiPause) : unref(mdiPlay) }, null, 8, ["name", "path"]), unref(isPlaying) ? (openBlock(), createElementBlock("svg", { key: `${unref(modalId)}-animation-${animationKey.value}`, class: "progress-ring", height: "50", width: "50" }, [..._cache[1] || (_cache[1] = [ createElementVNode("circle", { class: "progress-ring__circle", stroke: "white", "stroke-width": "2", fill: "transparent", r: "15", cx: "25", cy: "25" }, null, -1) ])])) : createCommentVNode("", true) ], 10, _hoisted_5)) : createCommentVNode("", true), createVNode(NcActions, { class: "header-actions", inline: _ctx.inlineActions }, { default: withCtx(() => [ renderSlot(_ctx.$slots, "actions", {}, void 0, true) ]), _: 3 }, 8, ["inline"]), !_ctx.noClose && _ctx.closeButtonOutside ? (openBlock(), createBlock(NcButton, { key: 1, "aria-label": unref(t)("Close"), class: "header-close", variant: "tertiary", onClick: close }, { icon: withCtx(() => [ createVNode(NcIconSvgWrapper, { path: unref(mdiClose) }, null, 8, ["path"]) ]), _: 1 }, 8, ["aria-label"])) : createCommentVNode("", true) ]) ], 8, _hoisted_2) ]), _: 3 }), createVNode(Transition, { name: `modal-${_ctx.outTransition ? "out" : "in"}`, appear: "" }, { default: withCtx(() => [ withDirectives(createElementVNode("div", { class: normalizeClass(["modal-wrapper", [ `modal-wrapper--${_ctx.size}`, { "modal-wrapper--spread-navigation": _ctx.spreadNavigation } ]]), onMousedown: withModifiers(handleClickModalWrapper, ["self"]) }, [ createVNode(Transition, { name: "fade-visibility", appear: "" }, { default: withCtx(() => [ withDirectives(createVNode(NcButton, { "aria-label": unref(t)("Previous"), class: "prev", variant: "tertiary-no-background", onClick: previousSlide }, { icon: withCtx(() => [ createVNode(NcIconSvgWrapper, { directional: "", path: unref(mdiChevronLeft), size: 40 }, null, 8, ["path"]) ]), _: 1 }, 8, ["aria-label"]), [ [vShow, _ctx.hasPrevious] ]) ]), _: 1 }), createElementVNode("div", { id: "modal-description-" + unref(modalId), class: "modal-container" }, [ createElementVNode("div", _hoisted_7, [ renderSlot(_ctx.$slots, "default", {}, void 0, true) ]), !_ctx.noClose && !_ctx.closeButtonOutside ? (openBlock(), createBlock(NcButton, { key: 0, "aria-label": unref(t)("Close"), class: "modal-container__close", variant: "tertiary", onClick: close }, { icon: withCtx(() => [ createVNode(NcIconSvgWrapper, { path: unref(mdiClose) }, null, 8, ["path"]) ]), _: 1 }, 8, ["aria-label"])) : createCommentVNode("", true) ], 8, _hoisted_6), createVNode(Transition, { name: "fade-visibility", appear: "" }, { default: withCtx(() => [ withDirectives(createVNode(NcButton, { "aria-label": unref(t)("Next"), class: "next", variant: "tertiary-no-background", onClick: nextSlide }, { icon: withCtx(() => [ createVNode(NcIconSvgWrapper, { directional: "", path: unref(mdiChevronRight), size: 40 }, null, 8, ["path"]) ]), _: 1 }, 8, ["aria-label"]), [ [vShow, _ctx.hasNext] ]) ]), _: 1 }) ], 34), [ [vShow, showModal.value] ]) ]), _: 3 }, 8, ["name"]) ], 16, _hoisted_1), [ [vShow, showModal.value] ]) ]), _: 3 }) ], 8, ["disabled", "to"]); }; } }); const NcModal = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-1639aad0"]]); export { NcModal as N }; //# sourceMappingURL=NcModal-MC_HktJd.mjs.map