VNavigationDrawer.mjs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. import { mergeProps as _mergeProps, resolveDirective as _resolveDirective, createVNode as _createVNode, Fragment as _Fragment } from "vue";
  2. // Styles
  3. import "./VNavigationDrawer.css";
  4. // Components
  5. import { VDefaultsProvider } from "../VDefaultsProvider/index.mjs";
  6. import { VImg } from "../VImg/index.mjs"; // Composables
  7. import { useSticky } from "./sticky.mjs";
  8. import { useTouch } from "./touch.mjs";
  9. import { useRtl } from "../../composables/index.mjs";
  10. import { makeBorderProps, useBorder } from "../../composables/border.mjs";
  11. import { useBackgroundColor } from "../../composables/color.mjs";
  12. import { makeComponentProps } from "../../composables/component.mjs";
  13. import { provideDefaults } from "../../composables/defaults.mjs";
  14. import { makeDelayProps, useDelay } from "../../composables/delay.mjs";
  15. import { makeDisplayProps, useDisplay } from "../../composables/display.mjs";
  16. import { makeElevationProps, useElevation } from "../../composables/elevation.mjs";
  17. import { makeLayoutItemProps, useLayoutItem } from "../../composables/layout.mjs";
  18. import { useProxiedModel } from "../../composables/proxiedModel.mjs";
  19. import { makeRoundedProps, useRounded } from "../../composables/rounded.mjs";
  20. import { useRouter } from "../../composables/router.mjs";
  21. import { useScopeId } from "../../composables/scopeId.mjs";
  22. import { useSsrBoot } from "../../composables/ssrBoot.mjs";
  23. import { makeTagProps } from "../../composables/tag.mjs";
  24. import { makeThemeProps, provideTheme } from "../../composables/theme.mjs";
  25. import { useToggleScope } from "../../composables/toggleScope.mjs"; // Utilities
  26. import { computed, nextTick, ref, shallowRef, toRef, Transition, watch } from 'vue';
  27. import { genericComponent, propsFactory, toPhysical, useRender } from "../../util/index.mjs"; // Types
  28. const locations = ['start', 'end', 'left', 'right', 'top', 'bottom'];
  29. export const makeVNavigationDrawerProps = propsFactory({
  30. color: String,
  31. disableResizeWatcher: Boolean,
  32. disableRouteWatcher: Boolean,
  33. expandOnHover: Boolean,
  34. floating: Boolean,
  35. modelValue: {
  36. type: Boolean,
  37. default: null
  38. },
  39. permanent: Boolean,
  40. rail: {
  41. type: Boolean,
  42. default: null
  43. },
  44. railWidth: {
  45. type: [Number, String],
  46. default: 56
  47. },
  48. scrim: {
  49. type: [Boolean, String],
  50. default: true
  51. },
  52. image: String,
  53. temporary: Boolean,
  54. persistent: Boolean,
  55. touchless: Boolean,
  56. width: {
  57. type: [Number, String],
  58. default: 256
  59. },
  60. location: {
  61. type: String,
  62. default: 'start',
  63. validator: value => locations.includes(value)
  64. },
  65. sticky: Boolean,
  66. ...makeBorderProps(),
  67. ...makeComponentProps(),
  68. ...makeDelayProps(),
  69. ...makeDisplayProps({
  70. mobile: null
  71. }),
  72. ...makeElevationProps(),
  73. ...makeLayoutItemProps(),
  74. ...makeRoundedProps(),
  75. ...makeTagProps({
  76. tag: 'nav'
  77. }),
  78. ...makeThemeProps()
  79. }, 'VNavigationDrawer');
  80. export const VNavigationDrawer = genericComponent()({
  81. name: 'VNavigationDrawer',
  82. props: makeVNavigationDrawerProps(),
  83. emits: {
  84. 'update:modelValue': val => true,
  85. 'update:rail': val => true
  86. },
  87. setup(props, _ref) {
  88. let {
  89. attrs,
  90. emit,
  91. slots
  92. } = _ref;
  93. const {
  94. isRtl
  95. } = useRtl();
  96. const {
  97. themeClasses
  98. } = provideTheme(props);
  99. const {
  100. borderClasses
  101. } = useBorder(props);
  102. const {
  103. backgroundColorClasses,
  104. backgroundColorStyles
  105. } = useBackgroundColor(toRef(props, 'color'));
  106. const {
  107. elevationClasses
  108. } = useElevation(props);
  109. const {
  110. displayClasses,
  111. mobile
  112. } = useDisplay(props);
  113. const {
  114. roundedClasses
  115. } = useRounded(props);
  116. const router = useRouter();
  117. const isActive = useProxiedModel(props, 'modelValue', null, v => !!v);
  118. const {
  119. ssrBootStyles
  120. } = useSsrBoot();
  121. const {
  122. scopeId
  123. } = useScopeId();
  124. const rootEl = ref();
  125. const isHovering = shallowRef(false);
  126. const {
  127. runOpenDelay,
  128. runCloseDelay
  129. } = useDelay(props, value => {
  130. isHovering.value = value;
  131. });
  132. const width = computed(() => {
  133. return props.rail && props.expandOnHover && isHovering.value ? Number(props.width) : Number(props.rail ? props.railWidth : props.width);
  134. });
  135. const location = computed(() => {
  136. return toPhysical(props.location, isRtl.value);
  137. });
  138. const isPersistent = computed(() => props.persistent);
  139. const isTemporary = computed(() => !props.permanent && (mobile.value || props.temporary));
  140. const isSticky = computed(() => props.sticky && !isTemporary.value && location.value !== 'bottom');
  141. useToggleScope(() => props.expandOnHover && props.rail != null, () => {
  142. watch(isHovering, val => emit('update:rail', !val));
  143. });
  144. useToggleScope(() => !props.disableResizeWatcher, () => {
  145. watch(isTemporary, val => !props.permanent && nextTick(() => isActive.value = !val));
  146. });
  147. useToggleScope(() => !props.disableRouteWatcher && !!router, () => {
  148. watch(router.currentRoute, () => isTemporary.value && (isActive.value = false));
  149. });
  150. watch(() => props.permanent, val => {
  151. if (val) isActive.value = true;
  152. });
  153. if (props.modelValue == null && !isTemporary.value) {
  154. isActive.value = props.permanent || !mobile.value;
  155. }
  156. const {
  157. isDragging,
  158. dragProgress
  159. } = useTouch({
  160. el: rootEl,
  161. isActive,
  162. isTemporary,
  163. width,
  164. touchless: toRef(props, 'touchless'),
  165. position: location
  166. });
  167. const layoutSize = computed(() => {
  168. const size = isTemporary.value ? 0 : props.rail && props.expandOnHover ? Number(props.railWidth) : width.value;
  169. return isDragging.value ? size * dragProgress.value : size;
  170. });
  171. const elementSize = computed(() => ['top', 'bottom'].includes(props.location) ? 0 : width.value);
  172. const {
  173. layoutItemStyles,
  174. layoutItemScrimStyles
  175. } = useLayoutItem({
  176. id: props.name,
  177. order: computed(() => parseInt(props.order, 10)),
  178. position: location,
  179. layoutSize,
  180. elementSize,
  181. active: computed(() => isActive.value || isDragging.value),
  182. disableTransitions: computed(() => isDragging.value),
  183. absolute: computed(() =>
  184. // eslint-disable-next-line @typescript-eslint/no-use-before-define
  185. props.absolute || isSticky.value && typeof isStuck.value !== 'string')
  186. });
  187. const {
  188. isStuck,
  189. stickyStyles
  190. } = useSticky({
  191. rootEl,
  192. isSticky,
  193. layoutItemStyles
  194. });
  195. const scrimColor = useBackgroundColor(computed(() => {
  196. return typeof props.scrim === 'string' ? props.scrim : null;
  197. }));
  198. const scrimStyles = computed(() => ({
  199. ...(isDragging.value ? {
  200. opacity: dragProgress.value * 0.2,
  201. transition: 'none'
  202. } : undefined),
  203. ...layoutItemScrimStyles.value
  204. }));
  205. provideDefaults({
  206. VList: {
  207. bgColor: 'transparent'
  208. }
  209. });
  210. useRender(() => {
  211. const hasImage = slots.image || props.image;
  212. return _createVNode(_Fragment, null, [_createVNode(props.tag, _mergeProps({
  213. "ref": rootEl,
  214. "onMouseenter": runOpenDelay,
  215. "onMouseleave": runCloseDelay,
  216. "class": ['v-navigation-drawer', `v-navigation-drawer--${location.value}`, {
  217. 'v-navigation-drawer--expand-on-hover': props.expandOnHover,
  218. 'v-navigation-drawer--floating': props.floating,
  219. 'v-navigation-drawer--is-hovering': isHovering.value,
  220. 'v-navigation-drawer--rail': props.rail,
  221. 'v-navigation-drawer--temporary': isTemporary.value,
  222. 'v-navigation-drawer--persistent': isPersistent.value,
  223. 'v-navigation-drawer--active': isActive.value,
  224. 'v-navigation-drawer--sticky': isSticky.value
  225. }, themeClasses.value, backgroundColorClasses.value, borderClasses.value, displayClasses.value, elevationClasses.value, roundedClasses.value, props.class],
  226. "style": [backgroundColorStyles.value, layoutItemStyles.value, ssrBootStyles.value, stickyStyles.value, props.style, ['top', 'bottom'].includes(location.value) ? {
  227. height: 'auto'
  228. } : {}]
  229. }, scopeId, attrs), {
  230. default: () => [hasImage && _createVNode("div", {
  231. "key": "image",
  232. "class": "v-navigation-drawer__img"
  233. }, [!slots.image ? _createVNode(VImg, {
  234. "key": "image-img",
  235. "alt": "",
  236. "cover": true,
  237. "height": "inherit",
  238. "src": props.image
  239. }, null) : _createVNode(VDefaultsProvider, {
  240. "key": "image-defaults",
  241. "disabled": !props.image,
  242. "defaults": {
  243. VImg: {
  244. alt: '',
  245. cover: true,
  246. height: 'inherit',
  247. src: props.image
  248. }
  249. }
  250. }, slots.image)]), slots.prepend && _createVNode("div", {
  251. "class": "v-navigation-drawer__prepend"
  252. }, [slots.prepend?.()]), _createVNode("div", {
  253. "class": "v-navigation-drawer__content"
  254. }, [slots.default?.()]), slots.append && _createVNode("div", {
  255. "class": "v-navigation-drawer__append"
  256. }, [slots.append?.()])]
  257. }), _createVNode(Transition, {
  258. "name": "fade-transition"
  259. }, {
  260. default: () => [isTemporary.value && (isDragging.value || isActive.value) && !!props.scrim && _createVNode("div", _mergeProps({
  261. "class": ['v-navigation-drawer__scrim', scrimColor.backgroundColorClasses.value],
  262. "style": [scrimStyles.value, scrimColor.backgroundColorStyles.value],
  263. "onClick": () => {
  264. if (isPersistent.value) return;
  265. isActive.value = false;
  266. }
  267. }, scopeId), null)]
  268. })]);
  269. });
  270. return {
  271. isStuck
  272. };
  273. }
  274. });
  275. //# sourceMappingURL=VNavigationDrawer.mjs.map