VListItem.mjs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. import { withDirectives as _withDirectives, resolveDirective as _resolveDirective, createVNode as _createVNode, Fragment as _Fragment } from "vue";
  2. // Styles
  3. import "./VListItem.css";
  4. // Components
  5. import { VListItemSubtitle } from "./VListItemSubtitle.mjs";
  6. import { VListItemTitle } from "./VListItemTitle.mjs";
  7. import { VAvatar } from "../VAvatar/index.mjs";
  8. import { VDefaultsProvider } from "../VDefaultsProvider/index.mjs";
  9. import { VIcon } from "../VIcon/index.mjs"; // Composables
  10. import { useList } from "./list.mjs";
  11. import { makeBorderProps, useBorder } from "../../composables/border.mjs";
  12. import { makeComponentProps } from "../../composables/component.mjs";
  13. import { makeDensityProps, useDensity } from "../../composables/density.mjs";
  14. import { makeDimensionProps, useDimension } from "../../composables/dimensions.mjs";
  15. import { makeElevationProps, useElevation } from "../../composables/elevation.mjs";
  16. import { IconValue } from "../../composables/icons.mjs";
  17. import { useNestedItem } from "../../composables/nested/nested.mjs";
  18. import { makeRoundedProps, useRounded } from "../../composables/rounded.mjs";
  19. import { makeRouterProps, useLink } from "../../composables/router.mjs";
  20. import { makeTagProps } from "../../composables/tag.mjs";
  21. import { makeThemeProps, provideTheme } from "../../composables/theme.mjs";
  22. import { genOverlays, makeVariantProps, useVariant } from "../../composables/variant.mjs"; // Directives
  23. import { Ripple } from "../../directives/ripple/index.mjs"; // Utilities
  24. import { computed, watch } from 'vue';
  25. import { deprecate, EventProp, genericComponent, propsFactory, useRender } from "../../util/index.mjs"; // Types
  26. export const makeVListItemProps = propsFactory({
  27. active: {
  28. type: Boolean,
  29. default: undefined
  30. },
  31. activeClass: String,
  32. /* @deprecated */
  33. activeColor: String,
  34. appendAvatar: String,
  35. appendIcon: IconValue,
  36. baseColor: String,
  37. disabled: Boolean,
  38. lines: String,
  39. link: {
  40. type: Boolean,
  41. default: undefined
  42. },
  43. nav: Boolean,
  44. prependAvatar: String,
  45. prependIcon: IconValue,
  46. ripple: {
  47. type: [Boolean, Object],
  48. default: true
  49. },
  50. subtitle: [String, Number, Boolean],
  51. title: [String, Number, Boolean],
  52. value: null,
  53. onClick: EventProp(),
  54. onClickOnce: EventProp(),
  55. ...makeBorderProps(),
  56. ...makeComponentProps(),
  57. ...makeDensityProps(),
  58. ...makeDimensionProps(),
  59. ...makeElevationProps(),
  60. ...makeRoundedProps(),
  61. ...makeRouterProps(),
  62. ...makeTagProps(),
  63. ...makeThemeProps(),
  64. ...makeVariantProps({
  65. variant: 'text'
  66. })
  67. }, 'VListItem');
  68. export const VListItem = genericComponent()({
  69. name: 'VListItem',
  70. directives: {
  71. Ripple
  72. },
  73. props: makeVListItemProps(),
  74. emits: {
  75. click: e => true
  76. },
  77. setup(props, _ref) {
  78. let {
  79. attrs,
  80. slots,
  81. emit
  82. } = _ref;
  83. const link = useLink(props, attrs);
  84. const id = computed(() => props.value === undefined ? link.href.value : props.value);
  85. const {
  86. select,
  87. isSelected,
  88. isIndeterminate,
  89. isGroupActivator,
  90. root,
  91. parent,
  92. openOnSelect
  93. } = useNestedItem(id, false);
  94. const list = useList();
  95. const isActive = computed(() => props.active !== false && (props.active || link.isActive?.value || isSelected.value));
  96. const isLink = computed(() => props.link !== false && link.isLink.value);
  97. const isClickable = computed(() => !props.disabled && props.link !== false && (props.link || link.isClickable.value || props.value != null && !!list));
  98. const roundedProps = computed(() => props.rounded || props.nav);
  99. const color = computed(() => props.color ?? props.activeColor);
  100. const variantProps = computed(() => ({
  101. color: isActive.value ? color.value ?? props.baseColor : props.baseColor,
  102. variant: props.variant
  103. }));
  104. watch(() => link.isActive?.value, val => {
  105. if (val && parent.value != null) {
  106. root.open(parent.value, true);
  107. }
  108. if (val) {
  109. openOnSelect(val);
  110. }
  111. }, {
  112. immediate: true
  113. });
  114. const {
  115. themeClasses
  116. } = provideTheme(props);
  117. const {
  118. borderClasses
  119. } = useBorder(props);
  120. const {
  121. colorClasses,
  122. colorStyles,
  123. variantClasses
  124. } = useVariant(variantProps);
  125. const {
  126. densityClasses
  127. } = useDensity(props);
  128. const {
  129. dimensionStyles
  130. } = useDimension(props);
  131. const {
  132. elevationClasses
  133. } = useElevation(props);
  134. const {
  135. roundedClasses
  136. } = useRounded(roundedProps);
  137. const lineClasses = computed(() => props.lines ? `v-list-item--${props.lines}-line` : undefined);
  138. const slotProps = computed(() => ({
  139. isActive: isActive.value,
  140. select,
  141. isSelected: isSelected.value,
  142. isIndeterminate: isIndeterminate.value
  143. }));
  144. function onClick(e) {
  145. emit('click', e);
  146. if (isGroupActivator || !isClickable.value) return;
  147. link.navigate?.(e);
  148. props.value != null && select(!isSelected.value, e);
  149. }
  150. function onKeyDown(e) {
  151. if (e.key === 'Enter' || e.key === ' ') {
  152. e.preventDefault();
  153. onClick(e);
  154. }
  155. }
  156. useRender(() => {
  157. const Tag = isLink.value ? 'a' : props.tag;
  158. const hasTitle = slots.title || props.title;
  159. const hasSubtitle = slots.subtitle || props.subtitle;
  160. const hasAppendMedia = !!(props.appendAvatar || props.appendIcon);
  161. const hasAppend = !!(hasAppendMedia || slots.append);
  162. const hasPrependMedia = !!(props.prependAvatar || props.prependIcon);
  163. const hasPrepend = !!(hasPrependMedia || slots.prepend);
  164. list?.updateHasPrepend(hasPrepend);
  165. if (props.activeColor) {
  166. deprecate('active-color', ['color', 'base-color']);
  167. }
  168. return _withDirectives(_createVNode(Tag, {
  169. "class": ['v-list-item', {
  170. 'v-list-item--active': isActive.value,
  171. 'v-list-item--disabled': props.disabled,
  172. 'v-list-item--link': isClickable.value,
  173. 'v-list-item--nav': props.nav,
  174. 'v-list-item--prepend': !hasPrepend && list?.hasPrepend.value,
  175. [`${props.activeClass}`]: props.activeClass && isActive.value
  176. }, themeClasses.value, borderClasses.value, colorClasses.value, densityClasses.value, elevationClasses.value, lineClasses.value, roundedClasses.value, variantClasses.value, props.class],
  177. "style": [colorStyles.value, dimensionStyles.value, props.style],
  178. "href": link.href.value,
  179. "tabindex": isClickable.value ? list ? -2 : 0 : undefined,
  180. "onClick": onClick,
  181. "onKeydown": isClickable.value && !isLink.value && onKeyDown
  182. }, {
  183. default: () => [genOverlays(isClickable.value || isActive.value, 'v-list-item'), hasPrepend && _createVNode("div", {
  184. "key": "prepend",
  185. "class": "v-list-item__prepend"
  186. }, [!slots.prepend ? _createVNode(_Fragment, null, [props.prependAvatar && _createVNode(VAvatar, {
  187. "key": "prepend-avatar",
  188. "density": props.density,
  189. "image": props.prependAvatar
  190. }, null), props.prependIcon && _createVNode(VIcon, {
  191. "key": "prepend-icon",
  192. "density": props.density,
  193. "icon": props.prependIcon
  194. }, null)]) : _createVNode(VDefaultsProvider, {
  195. "key": "prepend-defaults",
  196. "disabled": !hasPrependMedia,
  197. "defaults": {
  198. VAvatar: {
  199. density: props.density,
  200. image: props.prependAvatar
  201. },
  202. VIcon: {
  203. density: props.density,
  204. icon: props.prependIcon
  205. },
  206. VListItemAction: {
  207. start: true
  208. }
  209. }
  210. }, {
  211. default: () => [slots.prepend?.(slotProps.value)]
  212. })]), _createVNode("div", {
  213. "class": "v-list-item__content",
  214. "data-no-activator": ""
  215. }, [hasTitle && _createVNode(VListItemTitle, {
  216. "key": "title"
  217. }, {
  218. default: () => [slots.title?.({
  219. title: props.title
  220. }) ?? props.title]
  221. }), hasSubtitle && _createVNode(VListItemSubtitle, {
  222. "key": "subtitle"
  223. }, {
  224. default: () => [slots.subtitle?.({
  225. subtitle: props.subtitle
  226. }) ?? props.subtitle]
  227. }), slots.default?.(slotProps.value)]), hasAppend && _createVNode("div", {
  228. "key": "append",
  229. "class": "v-list-item__append"
  230. }, [!slots.append ? _createVNode(_Fragment, null, [props.appendIcon && _createVNode(VIcon, {
  231. "key": "append-icon",
  232. "density": props.density,
  233. "icon": props.appendIcon
  234. }, null), props.appendAvatar && _createVNode(VAvatar, {
  235. "key": "append-avatar",
  236. "density": props.density,
  237. "image": props.appendAvatar
  238. }, null)]) : _createVNode(VDefaultsProvider, {
  239. "key": "append-defaults",
  240. "disabled": !hasAppendMedia,
  241. "defaults": {
  242. VAvatar: {
  243. density: props.density,
  244. image: props.appendAvatar
  245. },
  246. VIcon: {
  247. density: props.density,
  248. icon: props.appendIcon
  249. },
  250. VListItemAction: {
  251. end: true
  252. }
  253. }
  254. }, {
  255. default: () => [slots.append?.(slotProps.value)]
  256. })])]
  257. }), [[_resolveDirective("ripple"), isClickable.value && props.ripple]]);
  258. });
  259. return {};
  260. }
  261. });
  262. //# sourceMappingURL=VListItem.mjs.map