123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- 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 { useLayout } from "../../composables/index.mjs";
- import { forwardRefs } from "../../composables/forwardRefs.mjs";
- import { VuetifyLayoutKey } from "../../composables/layout.mjs";
- import { makeLocationProps } 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 { useToggleScope } from "../../composables/toggleScope.mjs";
- import { genOverlays, makeVariantProps, useVariant } from "../../composables/variant.mjs"; // Utilities
- import { computed, inject, mergeProps, nextTick, onMounted, onScopeDispose, ref, shallowRef, watch, watchEffect } from 'vue';
- import { genericComponent, omit, propsFactory, refElement, useRender } from "../../util/index.mjs"; // Types
- 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 {
- 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);
- const startY = shallowRef(0);
- const mainStyles = ref();
- const hasLayout = inject(VuetifyLayoutKey, undefined);
- useToggleScope(() => !!hasLayout, () => {
- const layout = useLayout();
- watchEffect(() => {
- mainStyles.value = layout.mainStyles.value;
- });
- });
- 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();
- }
- function onTouchstart(event) {
- startY.value = event.touches[0].clientY;
- }
- function onTouchend(event) {
- if (Math.abs(startY.value - event.changedTouches[0].clientY) > 50) {
- isActive.value = false;
- }
- }
- function onAfterLeave() {
- if (isHovering.value) onPointerleave();
- }
- const locationClasses = computed(() => {
- return props.location.split(' ').reduce((acc, loc) => {
- acc[`v-snackbar--${loc}`] = true;
- return acc;
- }, {});
- });
- 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
- }, locationClasses.value, positionClasses.value, props.class],
- "style": [mainStyles.value, 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: [colorStyles.value],
- onPointerenter,
- onPointerleave
- }, overlayProps.contentProps),
- "persistent": true,
- "noClickAnimation": true,
- "scrim": false,
- "scrollStrategy": "none",
- "_disableGlobalStack": true,
- "onTouchstartPassive": onTouchstart,
- "onTouchend": onTouchend,
- "onAfterLeave": onAfterLeave
- }, 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({
- isActive
- })])]
- })],
- activator: slots.activator
- });
- });
- return forwardRefs({}, overlay);
- }
- });
- //# sourceMappingURL=VSnackbar.mjs.map
|