routie dev init since i didn't adhere to any proper guidance up until now
This commit is contained in:
+259
@@ -0,0 +1,259 @@
|
||||
import { createVNode as _createVNode, createElementVNode as _createElementVNode, normalizeClass as _normalizeClass, normalizeStyle as _normalizeStyle, withDirectives as _withDirectives } from "vue";
|
||||
// Styles
|
||||
import "./VWindow.css";
|
||||
|
||||
// Components
|
||||
import { VBtn } from "../VBtn/index.js"; // Composables
|
||||
import { makeComponentProps } from "../../composables/component.js";
|
||||
import { useGroup } from "../../composables/group.js";
|
||||
import { useLocale, useRtl } from "../../composables/locale.js";
|
||||
import { makeTagProps } from "../../composables/tag.js";
|
||||
import { makeThemeProps, provideTheme } from "../../composables/theme.js"; // Directives
|
||||
import vTouch from "../../directives/touch/index.js"; // Utilities
|
||||
import { computed, nextTick, provide, ref, shallowRef, toRef, watch } from 'vue';
|
||||
import { convertToUnit, genericComponent, IN_BROWSER, PREFERS_REDUCED_MOTION, propsFactory, useRender } from "../../util/index.js";
|
||||
import { getScrollParent } from "../../util/getScrollParent.js"; // Types
|
||||
export const VWindowSymbol = Symbol.for('vuetify:v-window');
|
||||
export const VWindowGroupSymbol = Symbol.for('vuetify:v-window-group');
|
||||
export const makeVWindowProps = propsFactory({
|
||||
continuous: Boolean,
|
||||
nextIcon: {
|
||||
type: [Boolean, String, Function, Object],
|
||||
default: '$next'
|
||||
},
|
||||
prevIcon: {
|
||||
type: [Boolean, String, Function, Object],
|
||||
default: '$prev'
|
||||
},
|
||||
reverse: Boolean,
|
||||
showArrows: {
|
||||
type: [Boolean, String],
|
||||
validator: v => typeof v === 'boolean' || v === 'hover'
|
||||
},
|
||||
verticalArrows: [Boolean, String],
|
||||
touch: {
|
||||
type: [Object, Boolean],
|
||||
default: undefined
|
||||
},
|
||||
direction: {
|
||||
type: String,
|
||||
default: 'horizontal'
|
||||
},
|
||||
modelValue: null,
|
||||
disabled: Boolean,
|
||||
selectedClass: {
|
||||
type: String,
|
||||
default: 'v-window-item--active'
|
||||
},
|
||||
// TODO: mandatory should probably not be exposed but do this for now
|
||||
mandatory: {
|
||||
type: [Boolean, String],
|
||||
default: 'force'
|
||||
},
|
||||
crossfade: Boolean,
|
||||
transitionDuration: Number,
|
||||
...makeComponentProps(),
|
||||
...makeTagProps(),
|
||||
...makeThemeProps()
|
||||
}, 'VWindow');
|
||||
export const VWindow = genericComponent()({
|
||||
name: 'VWindow',
|
||||
directives: {
|
||||
vTouch
|
||||
},
|
||||
props: makeVWindowProps(),
|
||||
emits: {
|
||||
'update:modelValue': value => true
|
||||
},
|
||||
setup(props, {
|
||||
slots
|
||||
}) {
|
||||
const {
|
||||
themeClasses
|
||||
} = provideTheme(props);
|
||||
const {
|
||||
isRtl
|
||||
} = useRtl();
|
||||
const {
|
||||
t
|
||||
} = useLocale();
|
||||
const group = useGroup(props, VWindowGroupSymbol);
|
||||
const rootRef = ref();
|
||||
const isRtlReverse = computed(() => isRtl.value ? !props.reverse : props.reverse);
|
||||
const isReversed = shallowRef(false);
|
||||
const transition = computed(() => {
|
||||
if (props.crossfade) {
|
||||
return 'v-window-crossfade-transition';
|
||||
}
|
||||
const axis = props.direction === 'vertical' ? 'y' : 'x';
|
||||
const reverse = isRtlReverse.value ? !isReversed.value : isReversed.value;
|
||||
const direction = reverse ? '-reverse' : '';
|
||||
return `v-window-${axis}${direction}-transition`;
|
||||
});
|
||||
const transitionCount = shallowRef(0);
|
||||
const transitionHeight = ref(undefined);
|
||||
const activeIndex = computed(() => {
|
||||
return group.items.value.findIndex(item => group.selected.value.includes(item.id));
|
||||
});
|
||||
|
||||
// Fix for https://github.com/vuetifyjs/vuetify/issues/18447
|
||||
watch(activeIndex, (newVal, oldVal) => {
|
||||
let scrollableParent;
|
||||
const savedScrollPosition = {
|
||||
left: 0,
|
||||
top: 0
|
||||
};
|
||||
if (IN_BROWSER && oldVal >= 0) {
|
||||
scrollableParent = getScrollParent(rootRef.value);
|
||||
savedScrollPosition.left = scrollableParent?.scrollLeft;
|
||||
savedScrollPosition.top = scrollableParent?.scrollTop;
|
||||
}
|
||||
const itemsLength = group.items.value.length;
|
||||
const lastIndex = itemsLength - 1;
|
||||
if (itemsLength <= 2) {
|
||||
isReversed.value = newVal < oldVal;
|
||||
} else if (newVal === lastIndex && oldVal === 0) {
|
||||
isReversed.value = false;
|
||||
} else if (newVal === 0 && oldVal === lastIndex) {
|
||||
isReversed.value = true;
|
||||
} else {
|
||||
isReversed.value = newVal < oldVal;
|
||||
}
|
||||
nextTick(() => {
|
||||
if (!IN_BROWSER || !scrollableParent) return;
|
||||
const currentScrollY = scrollableParent.scrollTop;
|
||||
if (currentScrollY !== savedScrollPosition.top) {
|
||||
scrollableParent.scrollTo({
|
||||
...savedScrollPosition,
|
||||
behavior: 'instant'
|
||||
});
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
if (!scrollableParent) return;
|
||||
const rafScrollY = scrollableParent.scrollTop;
|
||||
if (rafScrollY !== savedScrollPosition.top) {
|
||||
scrollableParent.scrollTo({
|
||||
...savedScrollPosition,
|
||||
behavior: 'instant'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}, {
|
||||
flush: 'sync'
|
||||
}); // Run synchronously before DOM updates
|
||||
|
||||
provide(VWindowSymbol, {
|
||||
transition,
|
||||
isReversed,
|
||||
transitionCount,
|
||||
transitionHeight,
|
||||
rootRef
|
||||
});
|
||||
const canMoveBack = toRef(() => props.continuous || activeIndex.value !== 0);
|
||||
const canMoveForward = toRef(() => props.continuous || activeIndex.value !== group.items.value.length - 1);
|
||||
function prev() {
|
||||
canMoveBack.value && group.prev();
|
||||
}
|
||||
function next() {
|
||||
canMoveForward.value && group.next();
|
||||
}
|
||||
const arrows = computed(() => {
|
||||
const arrows = [];
|
||||
const prevProps = {
|
||||
icon: isRtl.value ? props.nextIcon : props.prevIcon,
|
||||
class: `v-window__${isRtlReverse.value ? 'right' : 'left'}`,
|
||||
onClick: group.prev,
|
||||
'aria-label': t('$vuetify.carousel.prev')
|
||||
};
|
||||
arrows.push(canMoveBack.value ? slots.prev ? slots.prev({
|
||||
props: prevProps
|
||||
}) : _createVNode(VBtn, prevProps, null) : _createElementVNode("div", null, null));
|
||||
const nextProps = {
|
||||
icon: isRtl.value ? props.prevIcon : props.nextIcon,
|
||||
class: `v-window__${isRtlReverse.value ? 'left' : 'right'}`,
|
||||
onClick: group.next,
|
||||
'aria-label': t('$vuetify.carousel.next')
|
||||
};
|
||||
arrows.push(canMoveForward.value ? slots.next ? slots.next({
|
||||
props: nextProps
|
||||
}) : _createVNode(VBtn, nextProps, null) : _createElementVNode("div", null, null));
|
||||
return arrows;
|
||||
});
|
||||
const touchOptions = computed(() => {
|
||||
if (props.touch === false) return props.touch;
|
||||
const options = {
|
||||
left: () => {
|
||||
isRtlReverse.value ? prev() : next();
|
||||
},
|
||||
right: () => {
|
||||
isRtlReverse.value ? next() : prev();
|
||||
},
|
||||
start: ({
|
||||
originalEvent
|
||||
}) => {
|
||||
originalEvent.stopPropagation();
|
||||
}
|
||||
};
|
||||
return {
|
||||
...options,
|
||||
...(props.touch === true ? {} : props.touch)
|
||||
};
|
||||
});
|
||||
function onKeyDown(e) {
|
||||
if (props.direction === 'horizontal' && e.key === 'ArrowLeft' || props.direction === 'vertical' && e.key === 'ArrowUp') {
|
||||
e.preventDefault();
|
||||
prev();
|
||||
nextTick(() => {
|
||||
canMoveBack.value ? focusArrow(0) : focusArrow(1);
|
||||
});
|
||||
}
|
||||
if (props.direction === 'horizontal' && e.key === 'ArrowRight' || props.direction === 'vertical' && e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
next();
|
||||
nextTick(() => {
|
||||
canMoveForward.value ? focusArrow(1) : focusArrow(0);
|
||||
});
|
||||
}
|
||||
}
|
||||
function focusArrow(index) {
|
||||
const arrow = arrows.value[index];
|
||||
if (!arrow) return;
|
||||
const arrowEl = Array.isArray(arrow) ? arrow[0] : arrow;
|
||||
arrowEl.el?.focus();
|
||||
}
|
||||
useRender(() => _withDirectives(_createVNode(props.tag, {
|
||||
"ref": rootRef,
|
||||
"class": _normalizeClass(['v-window', {
|
||||
'v-window--show-arrows-on-hover': props.showArrows === 'hover',
|
||||
'v-window--vertical-arrows': !!props.verticalArrows,
|
||||
'v-window--crossfade': !!props.crossfade
|
||||
}, themeClasses.value, props.class]),
|
||||
"style": _normalizeStyle([props.style, {
|
||||
'--v-window-transition-duration': !PREFERS_REDUCED_MOTION() ? convertToUnit(props.transitionDuration, 'ms') : null
|
||||
}])
|
||||
}, {
|
||||
default: () => [_createElementVNode("div", {
|
||||
"class": "v-window__container",
|
||||
"style": {
|
||||
height: transitionHeight.value
|
||||
}
|
||||
}, [slots.default?.({
|
||||
group
|
||||
}), props.showArrows !== false && _createElementVNode("div", {
|
||||
"class": _normalizeClass(['v-window__controls', {
|
||||
'v-window__controls--left': props.verticalArrows === 'left' || props.verticalArrows === true
|
||||
}, {
|
||||
'v-window__controls--right': props.verticalArrows === 'right'
|
||||
}]),
|
||||
"onKeydown": onKeyDown
|
||||
}, [arrows.value])]), slots.additional?.({
|
||||
group
|
||||
})]
|
||||
}), [[vTouch, touchOptions.value]]));
|
||||
return {
|
||||
group
|
||||
};
|
||||
}
|
||||
});
|
||||
//# sourceMappingURL=VWindow.js.map
|
||||
Reference in New Issue
Block a user