UNPKG

bootstrap-vue-next

Version:

Seamless integration of Vue 3, Bootstrap 5, and TypeScript for modern, type-safe UI development

506 lines (505 loc) 19.6 kB
import { h as modalManagerKey } from "./keys-CQKrwmvN.mjs"; import { P as tryOnScopeDispose, i as getSSRHandler, o as onKeyStroke, s as unrefElement } from "./dist-Dn5blevd.mjs"; import { i as getSafeDocument, o as isEmptySlot, r as getModalZIndex } from "./dom-AhkaSoh8.mjs"; import { t as useId$1 } from "./useId-CCwnEmGh.mjs"; import { t as useDefaults } from "./useDefaults-CCWS15M8.mjs"; import { t as useShowHide } from "./useShowHide-wBe7O9iE.mjs"; import { t as useColorVariantClasses } from "./useColorVariantClasses-GuDw8a_O.mjs"; import { t as BButton_default } from "./BButton-1yV1UiT7.mjs"; import { t as BCloseButton_default } from "./BCloseButton-DrD0tpan.mjs"; import { t as ConditionalTeleport_default } from "./ConditionalTeleport-B4KYZIM6.mjs"; import { t as getElement } from "./getElement-D5DvkPzw.mjs"; import { n as useActivatedFocusTrap, t as useSafeScrollLock } from "./useSafeScrollLock-PWxgzVSb.mjs"; import { Fragment, Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, getCurrentInstance, guardReactiveProps, inject, mergeModels, mergeProps, nextTick, normalizeClass, normalizeProps, normalizeStyle, onMounted, openBlock, ref, renderSlot, resolveDynamicComponent, toDisplayString, toValue, unref, useModel, useSlots, useTemplateRef, vShow, watch, withCtx, withDirectives, withModifiers } from "vue"; //#region src/composables/useModalManager.ts var modalOpenClassName = "modal-open"; var useSharedModalStack = () => { const modalManagerPlugin = inject(modalManagerKey, null); /** * Removes an item from both the stack and registry */ const dispose = (modal) => { modalManagerPlugin?.removeStack(modal); modalManagerPlugin?.removeRegistry(modal); }; const updateHTMLAttrs = getSSRHandler("updateHTMLAttrs", (selector, attribute, value) => { const el = typeof selector !== "string" ? unrefElement(selector) : selector ? getSafeDocument()?.querySelector(selector) : void 0; if (!el) return; if (attribute === "class") el.classList.toggle(modalOpenClassName, value === modalOpenClassName); else el.setAttribute(attribute, value); }); tryOnScopeDispose(() => { if (modalManagerPlugin?.countStack.value === 0) updateHTMLAttrs("body", "class", ""); }); watch(() => modalManagerPlugin?.countStack.value, (newValue) => { if (newValue === void 0) return; updateHTMLAttrs("body", "class", newValue > 0 ? modalOpenClassName : ""); }); return { ...modalManagerPlugin, dispose }; }; var useModalManager = (modalOpen, initialValue) => { const { pushRegistry, pushStack, removeStack, stack, dispose, countStack } = useSharedModalStack(); const currentModal = getCurrentInstance(); if (!currentModal || currentModal.type.__name !== "BModal") throw new Error("useModalManager must only use in BModal component"); pushRegistry?.(currentModal); tryOnScopeDispose(() => { dispose(currentModal); }); const setInStack = (newValue, oldValue) => { if (newValue) pushStack?.(currentModal); else if (oldValue && !newValue) removeStack?.(currentModal); }; setInStack(initialValue, initialValue); watch(modalOpen, setInStack); return { activePosition: computed(() => stack?.value.findIndex((el) => toValue(el.exposed?.id) === toValue(currentModal.exposed?.id))), activeModalCount: countStack, stackWithoutSelf: computed(() => stack?.value.filter((el) => toValue(el.exposed?.id) !== toValue(currentModal.exposed?.id)) ?? []) }; }; //#endregion //#region src/components/BModal/BModal.vue?vue&type=script&setup=true&lang.ts var _hoisted_1 = [ "id", "aria-labelledby", "aria-describedby" ]; var _hoisted_2 = ["id"]; var fallbackClassSelector = "modal-fallback-focus"; //#endregion //#region src/components/BModal/BModal.vue var BModal_default = /* @__PURE__ */ defineComponent({ inheritAttrs: false, __name: "BModal", props: /* @__PURE__ */ mergeModels({ focus: { type: [ String, Boolean, Object, null ], default: void 0 }, backdropFirst: { type: Boolean, default: false }, body: { default: void 0 }, bodyAttrs: { default: void 0 }, bodyBgVariant: { default: null }, bodyClass: { default: null }, bodyScrolling: { type: Boolean, default: false }, bodyTextVariant: { default: null }, bodyVariant: { default: null }, busy: { type: Boolean, default: false }, buttonSize: { default: "md" }, cancelClass: { default: void 0 }, cancelDisabled: { type: Boolean, default: false }, cancelTitle: { default: "Cancel" }, cancelVariant: { default: "secondary" }, centered: { type: Boolean, default: false }, contentClass: { default: void 0 }, dialogClass: { default: void 0 }, footerBgVariant: { default: null }, footerBorderVariant: { default: null }, footerClass: { default: void 0 }, footerTextVariant: { default: null }, footerVariant: { default: null }, fullscreen: { type: [Boolean, String], default: false }, headerAttrs: { default: void 0 }, headerBgVariant: { default: null }, headerBorderVariant: { default: null }, headerClass: { default: void 0 }, headerCloseClass: { default: void 0 }, headerCloseLabel: { default: "Close" }, headerCloseVariant: { default: "secondary" }, headerTextVariant: { default: null }, headerVariant: { default: null }, noBackdrop: { type: Boolean, default: false }, noFooter: { type: Boolean, default: false }, noHeader: { type: Boolean, default: false }, noHeaderClose: { type: Boolean, default: false }, id: { default: void 0 }, modalClass: { default: void 0 }, noCloseOnBackdrop: { type: Boolean, default: false }, noCloseOnEsc: { type: Boolean, default: false }, noTrap: { type: Boolean, default: false }, noStacking: { type: Boolean }, okClass: { default: void 0 }, okDisabled: { type: Boolean, default: false }, okOnly: { type: Boolean, default: false }, okTitle: { default: "OK" }, okVariant: { default: "primary" }, scrollable: { type: Boolean, default: false }, size: { default: "md" }, title: { default: void 0 }, titleClass: { default: void 0 }, titleVisuallyHidden: { type: Boolean, default: false }, titleTag: { default: "h5" }, teleportDisabled: { type: Boolean, default: false }, teleportTo: { default: "body" }, initialAnimation: { type: Boolean, default: false }, noAnimation: { type: Boolean }, noFade: { type: Boolean, default: false }, lazy: { type: Boolean, default: false }, unmountLazy: { type: Boolean, default: false }, show: { type: Boolean, default: false }, transProps: { default: void 0 }, visible: { type: Boolean, default: false } }, { "modelValue": { type: Boolean, default: false }, "modelModifiers": {} }), emits: /* @__PURE__ */ mergeModels([ "backdrop", "cancel", "close", "esc", "ok", "hide", "hide-prevented", "hidden", "show", "show-prevented", "shown", "toggle", "toggle-prevented" ], ["update:modelValue"]), setup(__props, { expose: __expose, emit: __emit }) { const props = useDefaults(__props, "BModal"); const emit = __emit; const slots = useSlots(); const computedId = useId$1(() => props.id, "modal"); const modelValue = useModel(__props, "modelValue"); const element = useTemplateRef("_element"); const fallbackFocusElement = useTemplateRef("_fallbackFocusElement"); const okButton = useTemplateRef("_okButton"); const cancelButton = useTemplateRef("_cancelButton"); const closeButton = useTemplateRef("_closeButton"); const pickFocusItem = () => { if (props.focus && typeof props.focus !== "boolean") { if (props.focus === "ok") return okButton; else if (props.focus === "close") return closeButton; else if (props.focus === "cancel") return cancelButton; return getElement(props.focus, element.value ?? void 0) ?? element.value; } return element; }; let activeElement = null; const onAfterEnter = () => { const doc = getSafeDocument(); if (props.noTrap && props.focus !== false && doc) { activeElement = doc.activeElement; if (activeElement === element.value) activeElement = null; const el = unrefElement(pickFocusItem()); if (!el) return; el?.focus(); if (el.tagName && el.tagName.toLowerCase() === "input" && typeof el.select === "function") el.select(); } }; const onAfterLeave = () => { if (props.noTrap && props.focus !== false && activeElement) { activeElement?.focus(); activeElement = null; } }; const { showRef, renderRef, renderBackdropRef, hide, show, toggle, computedNoAnimation, transitionProps, backdropTransitionProps, isLeaving, isVisible, trapActive, contentShowing, backdropReady, backdropVisible } = useShowHide(modelValue, props, emit, element, computedId, { transitionProps: { onAfterEnter, onAfterLeave } }); const { needsFallback } = useActivatedFocusTrap({ element, isActive: trapActive, noTrap: () => props.noTrap, fallbackFocus: { ref: fallbackFocusElement, classSelector: fallbackClassSelector }, focus: () => props.focus === false ? false : unrefElement(pickFocusItem()) ?? void 0 }); onKeyStroke("Escape", () => { hide("esc"); }, { target: element }); useSafeScrollLock(showRef, () => props.bodyScrolling); const hasHeaderCloseSlot = computed(() => !isEmptySlot(slots["header-close"])); const modalDialogClasses = computed(() => [props.dialogClass, { "modal-fullscreen": props.fullscreen === true, [`modal-fullscreen-${props.fullscreen}-down`]: typeof props.fullscreen === "string", [`modal-${props.size}`]: props.size !== "md", "modal-dialog-centered": props.centered, "modal-dialog-scrollable": props.scrollable }]); const bodyColorClasses = useColorVariantClasses(() => ({ bgVariant: props.bodyBgVariant, textVariant: props.bodyTextVariant, variant: props.bodyVariant })); const bodyClasses = computed(() => [props.bodyClass, bodyColorClasses.value]); const headerColorClasses = useColorVariantClasses(() => ({ bgVariant: props.headerBgVariant, textVariant: props.headerTextVariant, variant: props.headerVariant, borderVariant: props.headerBorderVariant })); const headerClasses = computed(() => [props.headerClass, headerColorClasses.value]); const headerCloseAttrs = computed(() => ({ variant: hasHeaderCloseSlot.value ? props.headerCloseVariant : void 0, class: props.headerCloseClass })); const footerColorClasses = useColorVariantClasses(() => ({ bgVariant: props.footerBgVariant, textVariant: props.footerTextVariant, variant: props.footerVariant, borderVariant: props.footerBorderVariant })); const footerClasses = computed(() => [props.footerClass, footerColorClasses.value]); const titleClasses = computed(() => [props.titleClass, { ["visually-hidden"]: props.titleVisuallyHidden }]); const disableCancel = computed(() => props.cancelDisabled || props.busy); const disableOk = computed(() => props.okDisabled || props.busy); const { activePosition, activeModalCount, stackWithoutSelf } = useModalManager(showRef, modelValue.value); const sharedClasses = computed(() => ({ [`stack-position-${activePosition?.value ?? 0}`]: true, [`stack-inverse-position-${(activeModalCount?.value ?? 1) - 1 - (activePosition?.value ?? 0)}`]: true })); watch(stackWithoutSelf, (newValue, oldValue) => { if (newValue.length > oldValue.length && showRef.value === true && props.noStacking) hide(); }); const defaultModalDialogZIndex = ref(getModalZIndex(element.value ?? getSafeDocument()?.body)); onMounted(() => { watch(renderRef, (v) => { if (!v) return; nextTick(() => { if (!element.value) return; defaultModalDialogZIndex.value = getModalZIndex(element.value); }); }, { immediate: true }); }); const computedZIndexNumber = computed(() => showRef.value || isLeaving.value ? defaultModalDialogZIndex.value - ((activeModalCount?.value ?? 0) * 2 - (activePosition?.value ?? 0) * 2) : defaultModalDialogZIndex.value); const computedZIndex = computed(() => ({ "z-index": computedZIndexNumber.value, "--b-position": activePosition?.value ?? 0, "--b-inverse-position": (activeModalCount?.value ?? 1) - 1 - (activePosition?.value ?? 0), "--b-count": activeModalCount?.value ?? 0 })); const computedZIndexBackdrop = computed(() => ({ "z-index": computedZIndexNumber.value - 1, "--b-position": activePosition?.value ?? 0, "--b-inverse-position": (activeModalCount?.value ?? 1) - 1 - (activePosition?.value ?? 0), "--b-count": activeModalCount?.value ?? 0 })); const sharedSlots = computed(() => ({ id: computedId.value, cancel: () => { hide("cancel"); }, close: () => { hide("close"); }, hide, show, toggle, ok: () => { hide("ok"); }, active: showRef.value, visible: showRef.value })); __expose({ hide, id: computedId, show, toggle, visible: showRef }); return (_ctx, _cache) => { return openBlock(), createBlock(ConditionalTeleport_default, { to: unref(props).teleportTo, disabled: unref(props).teleportDisabled }, { default: withCtx(() => [unref(renderRef) || unref(contentShowing) ? (openBlock(), createBlock(Transition, mergeProps({ key: 0 }, unref(transitionProps), { appear: modelValue.value || unref(props).visible }), { default: withCtx(() => [withDirectives(createElementVNode("div", mergeProps({ id: unref(computedId), ref: "_element", class: ["modal", [unref(props).modalClass, { fade: !unref(computedNoAnimation), show: unref(isVisible), ...sharedClasses.value }]], role: "dialog", "aria-labelledby": !unref(props).noHeader ? `${unref(computedId)}-label` : void 0, "aria-describedby": `${unref(computedId)}-body`, tabindex: "-1" }, _ctx.$attrs, { style: [computedZIndex.value, { "display": "block" }], onMousedown: _cache[4] || (_cache[4] = withModifiers(($event) => unref(hide)("backdrop"), ["left", "self"])) }), [createElementVNode("div", { class: normalizeClass(["modal-dialog", modalDialogClasses.value]) }, [unref(contentShowing) ? (openBlock(), createElementBlock("div", { key: 0, class: normalizeClass(["modal-content", unref(props).contentClass]) }, [ !unref(props).noHeader ? (openBlock(), createElementBlock("div", mergeProps({ key: 0, class: ["modal-header", headerClasses.value] }, unref(props).headerAttrs), [renderSlot(_ctx.$slots, "header", normalizeProps(guardReactiveProps(sharedSlots.value)), () => [(openBlock(), createBlock(resolveDynamicComponent(unref(props).titleTag), { id: `${unref(computedId)}-label`, class: normalizeClass(["modal-title", titleClasses.value]) }, { default: withCtx(() => [renderSlot(_ctx.$slots, "title", normalizeProps(guardReactiveProps(sharedSlots.value)), () => [createTextVNode(toDisplayString(unref(props).title), 1)])]), _: 3 }, 8, ["id", "class"])), !unref(props).noHeaderClose ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [hasHeaderCloseSlot.value ? (openBlock(), createBlock(BButton_default, mergeProps({ key: 0, ref: "_closeButton" }, headerCloseAttrs.value, { onClick: _cache[0] || (_cache[0] = ($event) => unref(hide)("close")) }), { default: withCtx(() => [renderSlot(_ctx.$slots, "header-close", normalizeProps(guardReactiveProps(sharedSlots.value)))]), _: 3 }, 16)) : (openBlock(), createBlock(BCloseButton_default, mergeProps({ key: 1, ref: "_closeButton", "aria-label": unref(props).headerCloseLabel }, headerCloseAttrs.value, { onClick: _cache[1] || (_cache[1] = ($event) => unref(hide)("close")) }), null, 16, ["aria-label"]))], 64)) : createCommentVNode("", true)])], 16)) : createCommentVNode("", true), createElementVNode("div", mergeProps({ id: `${unref(computedId)}-body`, class: ["modal-body", bodyClasses.value] }, unref(props).bodyAttrs), [renderSlot(_ctx.$slots, "default", normalizeProps(guardReactiveProps(sharedSlots.value)), () => [createTextVNode(toDisplayString(unref(props).body), 1)])], 16, _hoisted_2), !unref(props).noFooter ? (openBlock(), createElementBlock("div", { key: 1, class: normalizeClass(["modal-footer", footerClasses.value]) }, [renderSlot(_ctx.$slots, "footer", normalizeProps(guardReactiveProps(sharedSlots.value)), () => [renderSlot(_ctx.$slots, "cancel", normalizeProps(guardReactiveProps(sharedSlots.value)), () => [!unref(props).okOnly ? (openBlock(), createBlock(BButton_default, { key: 0, ref: "_cancelButton", disabled: disableCancel.value, size: unref(props).buttonSize, variant: unref(props).cancelVariant, class: normalizeClass(unref(props).cancelClass), onClick: _cache[2] || (_cache[2] = ($event) => unref(hide)("cancel")) }, { default: withCtx(() => [createTextVNode(toDisplayString(unref(props).cancelTitle), 1)]), _: 1 }, 8, [ "disabled", "size", "variant", "class" ])) : createCommentVNode("", true)]), renderSlot(_ctx.$slots, "ok", normalizeProps(guardReactiveProps(sharedSlots.value)), () => [createVNode(BButton_default, { ref: "_okButton", disabled: disableOk.value, size: unref(props).buttonSize, variant: unref(props).okVariant, class: normalizeClass(unref(props).okClass), onClick: _cache[3] || (_cache[3] = ($event) => unref(hide)("ok")) }, { default: withCtx(() => [createTextVNode(toDisplayString(unref(props).okTitle), 1)]), _: 1 }, 8, [ "disabled", "size", "variant", "class" ])])])], 2)) : createCommentVNode("", true) ], 2)) : createCommentVNode("", true)], 2), unref(needsFallback) ? (openBlock(), createElementBlock("div", { key: 0, ref: "_fallbackFocusElement", class: normalizeClass(fallbackClassSelector), tabindex: "0", style: { "width": "0", "height": "0", "overflow": "hidden" } }, null, 512)) : createCommentVNode("", true)], 16, _hoisted_1), [[vShow, unref(showRef) && (unref(backdropReady) && unref(props).backdropFirst || !unref(props).backdropFirst)]])]), _: 3 }, 16, ["appear"])) : createCommentVNode("", true), !unref(props).noBackdrop ? renderSlot(_ctx.$slots, "backdrop", normalizeProps(mergeProps({ key: 1 }, sharedSlots.value)), () => [unref(renderBackdropRef) ? (openBlock(), createBlock(Transition, normalizeProps(mergeProps({ key: 0 }, unref(backdropTransitionProps))), { default: withCtx(() => [withDirectives(createElementVNode("div", { class: normalizeClass(["modal-backdrop", { fade: !unref(computedNoAnimation), show: unref(backdropVisible) || unref(computedNoAnimation), ...sharedClasses.value }]), style: normalizeStyle(computedZIndexBackdrop.value), onClick: _cache[5] || (_cache[5] = ($event) => unref(hide)("backdrop")) }, null, 6), [[vShow, unref(showRef) || unref(isLeaving) && unref(props).backdropFirst && !unref(computedNoAnimation)]])]), _: 1 }, 16)) : createCommentVNode("", true)]) : createCommentVNode("", true)]), _: 3 }, 8, ["to", "disabled"]); }; } }); //#endregion export { useSharedModalStack as n, BModal_default as t }; //# sourceMappingURL=BModal-CJ2pBX28.mjs.map