VWindow.mjs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import { withDirectives as _withDirectives, resolveDirective as _resolveDirective, createVNode as _createVNode } from "vue";
  2. // Styles
  3. import "./VWindow.css";
  4. // Components
  5. import { VBtn } from "../VBtn/index.mjs"; // Composables
  6. import { makeComponentProps } from "../../composables/component.mjs";
  7. import { useGroup } from "../../composables/group.mjs";
  8. import { useLocale, useRtl } from "../../composables/locale.mjs";
  9. import { makeTagProps } from "../../composables/tag.mjs";
  10. import { makeThemeProps, provideTheme } from "../../composables/theme.mjs"; // Directives
  11. import { Touch } from "../../directives/touch/index.mjs"; // Utilities
  12. import { computed, provide, ref, shallowRef, watch } from 'vue';
  13. import { genericComponent, propsFactory, useRender } from "../../util/index.mjs"; // Types
  14. export const VWindowSymbol = Symbol.for('vuetify:v-window');
  15. export const VWindowGroupSymbol = Symbol.for('vuetify:v-window-group');
  16. export const makeVWindowProps = propsFactory({
  17. continuous: Boolean,
  18. nextIcon: {
  19. type: [Boolean, String, Function, Object],
  20. default: '$next'
  21. },
  22. prevIcon: {
  23. type: [Boolean, String, Function, Object],
  24. default: '$prev'
  25. },
  26. reverse: Boolean,
  27. showArrows: {
  28. type: [Boolean, String],
  29. validator: v => typeof v === 'boolean' || v === 'hover'
  30. },
  31. touch: {
  32. type: [Object, Boolean],
  33. default: undefined
  34. },
  35. direction: {
  36. type: String,
  37. default: 'horizontal'
  38. },
  39. modelValue: null,
  40. disabled: Boolean,
  41. selectedClass: {
  42. type: String,
  43. default: 'v-window-item--active'
  44. },
  45. // TODO: mandatory should probably not be exposed but do this for now
  46. mandatory: {
  47. type: [Boolean, String],
  48. default: 'force'
  49. },
  50. ...makeComponentProps(),
  51. ...makeTagProps(),
  52. ...makeThemeProps()
  53. }, 'VWindow');
  54. export const VWindow = genericComponent()({
  55. name: 'VWindow',
  56. directives: {
  57. Touch
  58. },
  59. props: makeVWindowProps(),
  60. emits: {
  61. 'update:modelValue': value => true
  62. },
  63. setup(props, _ref) {
  64. let {
  65. slots
  66. } = _ref;
  67. const {
  68. themeClasses
  69. } = provideTheme(props);
  70. const {
  71. isRtl
  72. } = useRtl();
  73. const {
  74. t
  75. } = useLocale();
  76. const group = useGroup(props, VWindowGroupSymbol);
  77. const rootRef = ref();
  78. const isRtlReverse = computed(() => isRtl.value ? !props.reverse : props.reverse);
  79. const isReversed = shallowRef(false);
  80. const transition = computed(() => {
  81. const axis = props.direction === 'vertical' ? 'y' : 'x';
  82. const reverse = isRtlReverse.value ? !isReversed.value : isReversed.value;
  83. const direction = reverse ? '-reverse' : '';
  84. return `v-window-${axis}${direction}-transition`;
  85. });
  86. const transitionCount = shallowRef(0);
  87. const transitionHeight = ref(undefined);
  88. const activeIndex = computed(() => {
  89. return group.items.value.findIndex(item => group.selected.value.includes(item.id));
  90. });
  91. watch(activeIndex, (newVal, oldVal) => {
  92. const itemsLength = group.items.value.length;
  93. const lastIndex = itemsLength - 1;
  94. if (itemsLength <= 2) {
  95. isReversed.value = newVal < oldVal;
  96. } else if (newVal === lastIndex && oldVal === 0) {
  97. isReversed.value = true;
  98. } else if (newVal === 0 && oldVal === lastIndex) {
  99. isReversed.value = false;
  100. } else {
  101. isReversed.value = newVal < oldVal;
  102. }
  103. });
  104. provide(VWindowSymbol, {
  105. transition,
  106. isReversed,
  107. transitionCount,
  108. transitionHeight,
  109. rootRef
  110. });
  111. const canMoveBack = computed(() => props.continuous || activeIndex.value !== 0);
  112. const canMoveForward = computed(() => props.continuous || activeIndex.value !== group.items.value.length - 1);
  113. function prev() {
  114. canMoveBack.value && group.prev();
  115. }
  116. function next() {
  117. canMoveForward.value && group.next();
  118. }
  119. const arrows = computed(() => {
  120. const arrows = [];
  121. const prevProps = {
  122. icon: isRtl.value ? props.nextIcon : props.prevIcon,
  123. class: `v-window__${isRtlReverse.value ? 'right' : 'left'}`,
  124. onClick: group.prev,
  125. 'aria-label': t('$vuetify.carousel.prev')
  126. };
  127. arrows.push(canMoveBack.value ? slots.prev ? slots.prev({
  128. props: prevProps
  129. }) : _createVNode(VBtn, prevProps, null) : _createVNode("div", null, null));
  130. const nextProps = {
  131. icon: isRtl.value ? props.prevIcon : props.nextIcon,
  132. class: `v-window__${isRtlReverse.value ? 'left' : 'right'}`,
  133. onClick: group.next,
  134. 'aria-label': t('$vuetify.carousel.next')
  135. };
  136. arrows.push(canMoveForward.value ? slots.next ? slots.next({
  137. props: nextProps
  138. }) : _createVNode(VBtn, nextProps, null) : _createVNode("div", null, null));
  139. return arrows;
  140. });
  141. const touchOptions = computed(() => {
  142. if (props.touch === false) return props.touch;
  143. const options = {
  144. left: () => {
  145. isRtlReverse.value ? prev() : next();
  146. },
  147. right: () => {
  148. isRtlReverse.value ? next() : prev();
  149. },
  150. start: _ref2 => {
  151. let {
  152. originalEvent
  153. } = _ref2;
  154. originalEvent.stopPropagation();
  155. }
  156. };
  157. return {
  158. ...options,
  159. ...(props.touch === true ? {} : props.touch)
  160. };
  161. });
  162. useRender(() => _withDirectives(_createVNode(props.tag, {
  163. "ref": rootRef,
  164. "class": ['v-window', {
  165. 'v-window--show-arrows-on-hover': props.showArrows === 'hover'
  166. }, themeClasses.value, props.class],
  167. "style": props.style
  168. }, {
  169. default: () => [_createVNode("div", {
  170. "class": "v-window__container",
  171. "style": {
  172. height: transitionHeight.value
  173. }
  174. }, [slots.default?.({
  175. group
  176. }), props.showArrows !== false && _createVNode("div", {
  177. "class": "v-window__controls"
  178. }, [arrows.value])]), slots.additional?.({
  179. group
  180. })]
  181. }), [[_resolveDirective("touch"), touchOptions.value]]));
  182. return {
  183. group
  184. };
  185. }
  186. });
  187. //# sourceMappingURL=VWindow.mjs.map