routie dev init since i didn't adhere to any proper guidance up until now
This commit is contained in:
+234
@@ -0,0 +1,234 @@
|
||||
import { Fragment as _Fragment, createVNode as _createVNode, mergeProps as _mergeProps, createElementVNode as _createElementVNode } from "vue";
|
||||
// Components
|
||||
import { VBtn } from "../VBtn/index.js";
|
||||
import { VDefaultsProvider } from "../VDefaultsProvider/index.js";
|
||||
import { makeVSnackbarProps, VSnackbar } from "../VSnackbar/VSnackbar.js"; // Composables
|
||||
import { useSnackbarQueue } from "./queue.js";
|
||||
import { useDelay } from "../../composables/delay.js";
|
||||
import { useDocumentVisibility } from "../../composables/documentVisibility.js";
|
||||
import { useLocale } from "../../composables/locale.js"; // Utilities
|
||||
import { computed, mergeProps, ref, shallowRef, toRef, triggerRef, watch } from 'vue';
|
||||
import { genericComponent, omit, propsFactory, useRender } from "../../util/index.js"; // Types
|
||||
export const makeVSnackbarQueueProps = propsFactory({
|
||||
// TODO: Port this to Snackbar on dev
|
||||
closable: [Boolean, String],
|
||||
closeText: {
|
||||
type: String,
|
||||
default: '$vuetify.dismiss'
|
||||
},
|
||||
collapsed: Boolean,
|
||||
displayStrategy: {
|
||||
type: String,
|
||||
default: 'hold'
|
||||
},
|
||||
modelValue: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
totalVisible: {
|
||||
type: [Number, String],
|
||||
default: 1
|
||||
},
|
||||
gap: {
|
||||
type: [Number, String],
|
||||
default: 8
|
||||
},
|
||||
...omit(makeVSnackbarProps(), ['modelValue', 'collapsed', 'queueIndex', 'queueGap'])
|
||||
}, 'VSnackbarQueue');
|
||||
export const VSnackbarQueue = genericComponent()({
|
||||
name: 'VSnackbarQueue',
|
||||
inheritAttrs: false,
|
||||
props: makeVSnackbarQueueProps(),
|
||||
emits: {
|
||||
'update:modelValue': val => true
|
||||
},
|
||||
setup(props, {
|
||||
attrs,
|
||||
emit,
|
||||
slots
|
||||
}) {
|
||||
const {
|
||||
t
|
||||
} = useLocale();
|
||||
const documentVisibility = useDocumentVisibility();
|
||||
const queue = useSnackbarQueue(props);
|
||||
const isHovered = shallowRef(false);
|
||||
const {
|
||||
runOpenDelay,
|
||||
runCloseDelay
|
||||
} = useDelay({
|
||||
openDelay: 0,
|
||||
closeDelay: 500
|
||||
}, val => {
|
||||
isHovered.value = val;
|
||||
updateDynamicProps();
|
||||
});
|
||||
let _lastId = 0;
|
||||
const visibleItems = ref([]);
|
||||
const limit = toRef(() => Number(props.totalVisible));
|
||||
watch(() => props.modelValue.length, showNext);
|
||||
function removeItem(id) {
|
||||
visibleItems.value = visibleItems.value.filter(x => x.id !== id);
|
||||
if (visibleItems.value.length === 0) {
|
||||
isHovered.value = false;
|
||||
}
|
||||
showNext();
|
||||
}
|
||||
function showNext() {
|
||||
if (!props.modelValue.length) return;
|
||||
const activeCount = visibleItems.value.filter(x => x.active).length;
|
||||
if (activeCount >= limit.value) {
|
||||
if (props.displayStrategy !== 'overflow') return;
|
||||
|
||||
// Dismiss oldest active items to make room
|
||||
visibleItems.value.filter(x => x.active).slice(limit.value - 1).forEach(item => {
|
||||
item.active = false;
|
||||
item.onDismiss?.('overflow');
|
||||
});
|
||||
}
|
||||
const [next, ...rest] = props.modelValue;
|
||||
emit('update:modelValue', rest);
|
||||
const item = typeof next === 'string' ? {
|
||||
text: next
|
||||
} : next;
|
||||
const {
|
||||
promise,
|
||||
success,
|
||||
error,
|
||||
onDismiss,
|
||||
...itemProps
|
||||
} = item;
|
||||
const newItem = {
|
||||
id: _lastId++,
|
||||
item: {
|
||||
...(promise ? {
|
||||
timeout: -1,
|
||||
loading: true
|
||||
} : {}),
|
||||
...itemProps
|
||||
},
|
||||
active: true,
|
||||
onDismiss
|
||||
};
|
||||
visibleItems.value.unshift(newItem);
|
||||
updateDynamicProps();
|
||||
promise?.then(data => {
|
||||
if (!newItem.active) return;
|
||||
newItem.item = success?.(data) ?? {
|
||||
...newItem.item,
|
||||
timeout: 1
|
||||
};
|
||||
updateDynamicProps();
|
||||
triggerRef(visibleItems);
|
||||
}, data => {
|
||||
if (!newItem.active) return;
|
||||
newItem.item = error?.(data) ?? {
|
||||
...newItem.item,
|
||||
timeout: 1
|
||||
};
|
||||
updateDynamicProps();
|
||||
triggerRef(visibleItems);
|
||||
});
|
||||
}
|
||||
function dismiss(id, reason) {
|
||||
const item = visibleItems.value.find(x => x.id === id);
|
||||
if (!item) return;
|
||||
item.active = false;
|
||||
item.onDismiss?.(reason);
|
||||
updateDynamicProps();
|
||||
}
|
||||
function clear() {
|
||||
emit('update:modelValue', []);
|
||||
visibleItems.value.toReversed().forEach((item, i) => setTimeout(() => {
|
||||
item.active = false;
|
||||
item.onDismiss?.('cleared');
|
||||
}, 100 * i));
|
||||
}
|
||||
const btnProps = computed(() => ({
|
||||
color: typeof props.closable === 'string' ? props.closable : undefined,
|
||||
text: t(props.closeText)
|
||||
}));
|
||||
function updateDynamicProps() {
|
||||
let activeIndex = 0;
|
||||
visibleItems.value.forEach(({
|
||||
item,
|
||||
active
|
||||
}) => {
|
||||
item.queueIndex = activeIndex;
|
||||
if (active) activeIndex++;
|
||||
});
|
||||
if (!props.collapsed || isHovered.value) {
|
||||
visibleItems.value.forEach(({
|
||||
item
|
||||
}) => item.collapsed = undefined);
|
||||
return;
|
||||
}
|
||||
for (const {
|
||||
item
|
||||
} of visibleItems.value) {
|
||||
item.collapsed = item.queueIndex > 0 ? {
|
||||
width: queue.lastItemSize.value.width,
|
||||
height: queue.lastItemSize.value.height
|
||||
} : undefined;
|
||||
}
|
||||
}
|
||||
watch(queue.lastItemSize, updateDynamicProps);
|
||||
watch(() => props.collapsed, updateDynamicProps);
|
||||
useRender(() => {
|
||||
const hasActions = !!(props.closable || slots.actions);
|
||||
const snackbarProps = omit(VSnackbar.filterProps(props), ['modelValue', 'collapsed']);
|
||||
const pauseAll = documentVisibility.value === 'hidden' || props.collapsed && isHovered.value;
|
||||
return _createElementVNode(_Fragment, null, [visibleItems.value.map(({
|
||||
id,
|
||||
item,
|
||||
active
|
||||
}) => slots.item ? _createVNode(VDefaultsProvider, {
|
||||
"defaults": {
|
||||
VSnackbar: item
|
||||
}
|
||||
}, {
|
||||
default: () => [slots.item({
|
||||
item
|
||||
})]
|
||||
}) : _createVNode(VSnackbar, _mergeProps({
|
||||
"key": id
|
||||
}, attrs, snackbarProps, item, pauseAll ? {
|
||||
timeout: -1
|
||||
} : {}, {
|
||||
"queueGap": Number(props.gap),
|
||||
"contentProps": mergeProps(snackbarProps.contentProps, {
|
||||
onMouseenter: runOpenDelay,
|
||||
onMouseleave: () => runCloseDelay()
|
||||
}),
|
||||
"modelValue": active,
|
||||
"onUpdate:modelValue": () => dismiss(id, 'auto'),
|
||||
"onAfterLeave": () => removeItem(id)
|
||||
}), {
|
||||
header: slots.header ? () => slots.header?.({
|
||||
item
|
||||
}) : undefined,
|
||||
text: slots.text ? () => slots.text?.({
|
||||
item
|
||||
}) : undefined,
|
||||
actions: hasActions ? () => _createElementVNode(_Fragment, null, [!slots.actions ? _createVNode(VBtn, _mergeProps(btnProps.value, {
|
||||
"onClick": () => dismiss(id, 'dismissed')
|
||||
}), null) : _createVNode(VDefaultsProvider, {
|
||||
"defaults": {
|
||||
VBtn: btnProps.value
|
||||
}
|
||||
}, {
|
||||
default: () => [slots.actions({
|
||||
item,
|
||||
props: {
|
||||
onClick: () => dismiss(id, 'dismissed')
|
||||
}
|
||||
})]
|
||||
})]) : undefined
|
||||
}))]);
|
||||
});
|
||||
return {
|
||||
clear
|
||||
};
|
||||
}
|
||||
});
|
||||
//# sourceMappingURL=VSnackbarQueue.js.map
|
||||
Reference in New Issue
Block a user