vuetify
Version:
Vue Material Component Framework
251 lines (250 loc) • 8.88 kB
JavaScript
import { withDirectives as _withDirectives, resolveDirective as _resolveDirective, createVNode as _createVNode } from "vue";
// Styles
import "./VListItem.css";
// Components
import { VAvatar } from "../VAvatar/index.mjs";
import { VDefaultsProvider } from "../VDefaultsProvider/index.mjs";
import { VIcon } from "../VIcon/index.mjs";
import { VListItemSubtitle } from "./VListItemSubtitle.mjs";
import { VListItemTitle } from "./VListItemTitle.mjs"; // Directives
import { Ripple } from "../../directives/ripple/index.mjs"; // Composables
import { genOverlays, makeVariantProps, useVariant } from "../../composables/variant.mjs";
import { IconValue } from "../../composables/icons.mjs";
import { makeBorderProps, useBorder } from "../../composables/border.mjs";
import { makeDensityProps, useDensity } from "../../composables/density.mjs";
import { makeDimensionProps, useDimension } from "../../composables/dimensions.mjs";
import { makeElevationProps, useElevation } from "../../composables/elevation.mjs";
import { makeRoundedProps, useRounded } from "../../composables/rounded.mjs";
import { makeRouterProps, useLink } from "../../composables/router.mjs";
import { makeTagProps } from "../../composables/tag.mjs";
import { makeThemeProps, provideTheme } from "../../composables/theme.mjs";
import { useList } from "./list.mjs";
import { useNestedItem } from "../../composables/nested/nested.mjs"; // Utilities
import { computed, watch } from 'vue';
import { EventProp, genericComponent, useRender } from "../../util/index.mjs"; // Types
export const VListItem = genericComponent()({
name: 'VListItem',
directives: {
Ripple
},
props: {
active: {
type: Boolean,
default: undefined
},
activeClass: String,
activeColor: String,
appendAvatar: String,
appendIcon: IconValue,
disabled: Boolean,
lines: String,
link: {
type: Boolean,
default: undefined
},
nav: Boolean,
prependAvatar: String,
prependIcon: IconValue,
ripple: {
type: Boolean,
default: true
},
subtitle: [String, Number, Boolean],
title: [String, Number, Boolean],
value: null,
onClick: EventProp,
onClickOnce: EventProp,
...makeBorderProps(),
...makeDensityProps(),
...makeDimensionProps(),
...makeElevationProps(),
...makeRoundedProps(),
...makeRouterProps(),
...makeTagProps(),
...makeThemeProps(),
...makeVariantProps({
variant: 'text'
})
},
emits: {
click: e => true
},
setup(props, _ref) {
let {
attrs,
slots,
emit
} = _ref;
const link = useLink(props, attrs);
const id = computed(() => props.value ?? link.href.value);
const {
select,
isSelected,
isIndeterminate,
isGroupActivator,
root,
parent,
openOnSelect
} = useNestedItem(id, false);
const list = useList();
const isActive = computed(() => props.active !== false && (props.active || link.isActive?.value || isSelected.value));
const isLink = computed(() => props.link !== false && link.isLink.value);
const isClickable = computed(() => !props.disabled && props.link !== false && (props.link || link.isClickable.value || props.value != null && !!list));
const roundedProps = computed(() => props.rounded || props.nav);
const variantProps = computed(() => ({
color: isActive.value ? props.activeColor ?? props.color : props.color,
variant: props.variant
}));
watch(() => link.isActive?.value, val => {
if (val && parent.value != null) {
root.open(parent.value, true);
}
if (val) {
openOnSelect(val);
}
}, {
immediate: true
});
const {
themeClasses
} = provideTheme(props);
const {
borderClasses
} = useBorder(props);
const {
colorClasses,
colorStyles,
variantClasses
} = useVariant(variantProps);
const {
densityClasses
} = useDensity(props);
const {
dimensionStyles
} = useDimension(props);
const {
elevationClasses
} = useElevation(props);
const {
roundedClasses
} = useRounded(roundedProps);
const lineClasses = computed(() => props.lines ? `v-list-item--${props.lines}-line` : undefined);
const slotProps = computed(() => ({
isActive: isActive.value,
select,
isSelected: isSelected.value,
isIndeterminate: isIndeterminate.value
}));
function onClick(e) {
emit('click', e);
if (isGroupActivator || !isClickable.value) return;
link.navigate?.(e);
props.value != null && select(!isSelected.value, e);
}
function onKeyDown(e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
onClick(e);
}
}
useRender(() => {
const Tag = isLink.value ? 'a' : props.tag;
const hasColor = !list || isSelected.value || isActive.value;
const hasTitle = slots.title || props.title;
const hasSubtitle = slots.subtitle || props.subtitle;
const hasAppend = !!(slots.append || props.appendAvatar || props.appendIcon);
const hasPrepend = !!(slots.prepend || props.prependAvatar || props.prependIcon);
list?.updateHasPrepend(hasPrepend);
return _withDirectives(_createVNode(Tag, {
"class": ['v-list-item', {
'v-list-item--active': isActive.value,
'v-list-item--disabled': props.disabled,
'v-list-item--link': isClickable.value,
'v-list-item--nav': props.nav,
'v-list-item--prepend': !hasPrepend && list?.hasPrepend.value,
[`${props.activeClass}`]: props.activeClass && isActive.value
}, themeClasses.value, borderClasses.value, hasColor ? colorClasses.value : undefined, densityClasses.value, elevationClasses.value, lineClasses.value, roundedClasses.value, variantClasses.value],
"style": [hasColor ? colorStyles.value : undefined, dimensionStyles.value],
"href": link.href.value,
"tabindex": isClickable.value ? 0 : undefined,
"onClick": onClick,
"onKeydown": isClickable.value && !isLink.value && onKeyDown
}, {
default: () => [genOverlays(isClickable.value || isActive.value, 'v-list-item'), hasPrepend && _createVNode("div", {
"key": "prepend",
"class": "v-list-item__prepend"
}, [props.prependAvatar && _createVNode(VAvatar, {
"key": "prepend-avatar",
"density": props.density,
"image": props.prependAvatar
}, null), props.prependIcon && _createVNode(VIcon, {
"key": "prepend-icon",
"density": props.density,
"icon": props.prependIcon
}, null), slots.prepend && _createVNode(VDefaultsProvider, {
"key": "prepend",
"defaults": {
VAvatar: {
density: props.density,
image: props.prependAvatar
},
VIcon: {
density: props.density,
icon: props.prependIcon
},
VListItemAction: {
start: true
}
}
}, {
default: () => [slots.prepend(slotProps.value)]
})]), _createVNode("div", {
"class": "v-list-item__content",
"data-no-activator": ""
}, [hasTitle && _createVNode(VListItemTitle, {
"key": "title"
}, {
default: () => [slots.title?.({
title: props.title
}) ?? props.title]
}), hasSubtitle && _createVNode(VListItemSubtitle, {
"key": "subtitle"
}, {
default: () => [slots.subtitle?.({
subtitle: props.subtitle
}) ?? props.subtitle]
}), slots.default?.(slotProps.value)]), hasAppend && _createVNode("div", {
"key": "append",
"class": "v-list-item__append"
}, [slots.append && _createVNode(VDefaultsProvider, {
"key": "append",
"defaults": {
VAvatar: {
density: props.density,
image: props.appendAvatar
},
VIcon: {
density: props.density,
icon: props.appendIcon
},
VListItemAction: {
end: true
}
}
}, {
default: () => [slots.append(slotProps.value)]
}), props.appendIcon && _createVNode(VIcon, {
"key": "append-icon",
"density": props.density,
"icon": props.appendIcon
}, null), props.appendAvatar && _createVNode(VAvatar, {
"key": "append-avatar",
"density": props.density,
"image": props.appendAvatar
}, null)])]
}), [[_resolveDirective("ripple"), isClickable.value && props.ripple]]);
});
return {};
}
});
//# sourceMappingURL=VListItem.mjs.map