import { mergeProps as _mergeProps, resolveDirective as _resolveDirective, createVNode as _createVNode } from "vue"; // Styles import "./VSnackbar.css"; // Components import { VDefaultsProvider } from "../VDefaultsProvider/index.mjs"; import { VOverlay } from "../VOverlay/index.mjs"; import { makeVOverlayProps } from "../VOverlay/VOverlay.mjs"; import { VProgressLinear } from "../VProgressLinear/index.mjs"; // Composables import { forwardRefs } from "../../composables/forwardRefs.mjs"; import { makeLocationProps, useLocation } from "../../composables/location.mjs"; import { makePositionProps, usePosition } from "../../composables/position.mjs"; import { useProxiedModel } from "../../composables/proxiedModel.mjs"; import { makeRoundedProps, useRounded } from "../../composables/rounded.mjs"; import { useScopeId } from "../../composables/scopeId.mjs"; import { makeThemeProps, provideTheme } from "../../composables/theme.mjs"; import { genOverlays, makeVariantProps, useVariant } from "../../composables/variant.mjs"; // Utilities import { mergeProps, nextTick, onMounted, onScopeDispose, ref, shallowRef, watch } from 'vue'; import { genericComponent, omit, propsFactory, refElement, useRender } from "../../util/index.mjs"; function useCountdown(milliseconds) { const time = shallowRef(milliseconds); let timer = -1; function clear() { clearInterval(timer); } function reset() { clear(); nextTick(() => time.value = milliseconds); } function start(el) { const style = el ? getComputedStyle(el) : { transitionDuration: 0.2 }; const interval = parseFloat(style.transitionDuration) * 1000 || 200; clear(); if (time.value <= 0) return; const startTime = performance.now(); timer = window.setInterval(() => { const elapsed = performance.now() - startTime + interval; time.value = Math.max(milliseconds - elapsed, 0); if (time.value <= 0) clear(); }, interval); } onScopeDispose(clear); return { clear, time, start, reset }; } export const makeVSnackbarProps = propsFactory({ multiLine: Boolean, text: String, timer: [Boolean, String], timeout: { type: [Number, String], default: 5000 }, vertical: Boolean, ...makeLocationProps({ location: 'bottom' }), ...makePositionProps(), ...makeRoundedProps(), ...makeVariantProps(), ...makeThemeProps(), ...omit(makeVOverlayProps({ transition: 'v-snackbar-transition' }), ['persistent', 'noClickAnimation', 'scrim', 'scrollStrategy']) }, 'VSnackbar'); export const VSnackbar = genericComponent()({ name: 'VSnackbar', props: makeVSnackbarProps(), emits: { 'update:modelValue': v => true }, setup(props, _ref) { let { slots } = _ref; const isActive = useProxiedModel(props, 'modelValue'); const { locationStyles } = useLocation(props); const { positionClasses } = usePosition(props); const { scopeId } = useScopeId(); const { themeClasses } = provideTheme(props); const { colorClasses, colorStyles, variantClasses } = useVariant(props); const { roundedClasses } = useRounded(props); const countdown = useCountdown(Number(props.timeout)); const overlay = ref(); const timerRef = ref(); const isHovering = shallowRef(false); watch(isActive, startTimeout); watch(() => props.timeout, startTimeout); onMounted(() => { if (isActive.value) startTimeout(); }); let activeTimeout = -1; function startTimeout() { countdown.reset(); window.clearTimeout(activeTimeout); const timeout = Number(props.timeout); if (!isActive.value || timeout === -1) return; const element = refElement(timerRef.value); countdown.start(element); activeTimeout = window.setTimeout(() => { isActive.value = false; }, timeout); } function clearTimeout() { countdown.reset(); window.clearTimeout(activeTimeout); } function onPointerenter() { isHovering.value = true; clearTimeout(); } function onPointerleave() { isHovering.value = false; startTimeout(); } useRender(() => { const overlayProps = VOverlay.filterProps(props); const hasContent = !!(slots.default || slots.text || props.text); return _createVNode(VOverlay, _mergeProps({ "ref": overlay, "class": ['v-snackbar', { 'v-snackbar--active': isActive.value, 'v-snackbar--multi-line': props.multiLine && !props.vertical, 'v-snackbar--timer': !!props.timer, 'v-snackbar--vertical': props.vertical }, positionClasses.value, props.class], "style": props.style }, overlayProps, { "modelValue": isActive.value, "onUpdate:modelValue": $event => isActive.value = $event, "contentProps": mergeProps({ class: ['v-snackbar__wrapper', themeClasses.value, colorClasses.value, roundedClasses.value, variantClasses.value], style: [locationStyles.value, colorStyles.value], onPointerenter, onPointerleave }, overlayProps.contentProps), "persistent": true, "noClickAnimation": true, "scrim": false, "scrollStrategy": "none", "_disableGlobalStack": true }, scopeId), { default: () => [genOverlays(false, 'v-snackbar'), props.timer && !isHovering.value && _createVNode("div", { "key": "timer", "class": "v-snackbar__timer" }, [_createVNode(VProgressLinear, { "ref": timerRef, "color": typeof props.timer === 'string' ? props.timer : 'info', "max": props.timeout, "model-value": countdown.time.value }, null)]), hasContent && _createVNode("div", { "key": "content", "class": "v-snackbar__content", "role": "status", "aria-live": "polite" }, [slots.text?.() ?? props.text, slots.default?.()]), slots.actions && _createVNode(VDefaultsProvider, { "defaults": { VBtn: { variant: 'text', ripple: false, slim: true } } }, { default: () => [_createVNode("div", { "class": "v-snackbar__actions" }, [slots.actions()])] })], activator: slots.activator }); }); return forwardRefs({}, overlay); } }); //# sourceMappingURL=VSnackbar.mjs.map