vuetify
Version:
Vue Material Component Framework
307 lines (305 loc) • 11.1 kB
JavaScript
import { Fragment as _Fragment, createVNode as _createVNode, resolveDirective as _resolveDirective, mergeProps as _mergeProps, withDirectives as _withDirectives } from "vue";
// Styles
import "./VListItem.css";
// Components
import { VListItemSubtitle } from "./VListItemSubtitle.js";
import { VListItemTitle } from "./VListItemTitle.js";
import { VAvatar } from "../VAvatar/index.js";
import { VDefaultsProvider } from "../VDefaultsProvider/index.js";
import { VIcon } from "../VIcon/index.js"; // Composables
import { useList } from "./list.js";
import { makeBorderProps, useBorder } from "../../composables/border.js";
import { makeComponentProps } from "../../composables/component.js";
import { makeDensityProps, useDensity } from "../../composables/density.js";
import { makeDimensionProps, useDimension } from "../../composables/dimensions.js";
import { makeElevationProps, useElevation } from "../../composables/elevation.js";
import { IconValue } from "../../composables/icons.js";
import { useNestedItem } from "../../composables/nested/nested.js";
import { makeRoundedProps, useRounded } from "../../composables/rounded.js";
import { makeRouterProps, useLink } from "../../composables/router.js";
import { makeTagProps } from "../../composables/tag.js";
import { makeThemeProps, provideTheme } from "../../composables/theme.js";
import { genOverlays, makeVariantProps, useVariant } from "../../composables/variant.js"; // Directives
import { Ripple } from "../../directives/ripple/index.js"; // Utilities
import { computed, onBeforeMount, toDisplayString, toRef, watch } from 'vue';
import { deprecate, EventProp, genericComponent, propsFactory, useRender } from "../../util/index.js"; // Types
export const makeVListItemProps = propsFactory({
active: {
type: Boolean,
default: undefined
},
activeClass: String,
/* @deprecated */
activeColor: String,
appendAvatar: String,
appendIcon: IconValue,
baseColor: String,
disabled: Boolean,
lines: [Boolean, String],
link: {
type: Boolean,
default: undefined
},
nav: Boolean,
prependAvatar: String,
prependIcon: IconValue,
ripple: {
type: [Boolean, Object],
default: true
},
slim: Boolean,
subtitle: {
type: [String, Number, Boolean],
default: undefined
},
title: {
type: [String, Number, Boolean],
default: undefined
},
value: null,
onClick: EventProp(),
onClickOnce: EventProp(),
...makeBorderProps(),
...makeComponentProps(),
...makeDensityProps(),
...makeDimensionProps(),
...makeElevationProps(),
...makeRoundedProps(),
...makeRouterProps(),
...makeTagProps(),
...makeThemeProps(),
...makeVariantProps({
variant: 'text'
})
}, 'VListItem');
export const VListItem = genericComponent()({
name: 'VListItem',
directives: {
Ripple
},
props: makeVListItemProps(),
emits: {
click: e => true
},
setup(props, _ref) {
let {
attrs,
slots,
emit
} = _ref;
const link = useLink(props, attrs);
const id = computed(() => props.value === undefined ? link.href.value : props.value);
const {
activate,
isActivated,
select,
isOpen,
isSelected,
isIndeterminate,
isGroupActivator,
root,
parent,
openOnSelect,
id: uid
} = useNestedItem(id, false);
const list = useList();
const isActive = computed(() => props.active !== false && (props.active || link.isActive?.value || (root.activatable.value ? isActivated.value : isSelected.value)));
const isLink = toRef(() => props.link !== false && link.isLink.value);
const isSelectable = computed(() => !!list && (root.selectable.value || root.activatable.value || props.value != null));
const isClickable = computed(() => !props.disabled && props.link !== false && (props.link || link.isClickable.value || isSelectable.value));
const roundedProps = toRef(() => props.rounded || props.nav);
const color = toRef(() => props.color ?? props.activeColor);
const variantProps = toRef(() => ({
color: isActive.value ? color.value ?? props.baseColor : props.baseColor,
variant: props.variant
}));
// useNestedItem doesn't call register until beforeMount,
// so this can't be an immediate watcher as we don't know parent yet
watch(() => link.isActive?.value, val => {
if (!val) return;
handleActiveLink();
});
onBeforeMount(() => {
if (link.isActive?.value) handleActiveLink();
});
function handleActiveLink() {
if (parent.value != null) {
root.open(parent.value, true);
}
openOnSelect(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 = toRef(() => props.lines ? `v-list-item--${props.lines}-line` : undefined);
const slotProps = computed(() => ({
isActive: isActive.value,
select,
isOpen: isOpen.value,
isSelected: isSelected.value,
isIndeterminate: isIndeterminate.value
}));
function onClick(e) {
emit('click', e);
if (['INPUT', 'TEXTAREA'].includes(e.target?.tagName)) return;
if (!isClickable.value) return;
link.navigate?.(e);
if (isGroupActivator) return;
if (root.activatable.value) {
activate(!isActivated.value, e);
} else if (root.selectable.value) {
select(!isSelected.value, e);
} else if (props.value != null) {
select(!isSelected.value, e);
}
}
function onKeyDown(e) {
const target = e.target;
if (['INPUT', 'TEXTAREA'].includes(target.tagName)) return;
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
e.target.dispatchEvent(new MouseEvent('click', e));
}
}
useRender(() => {
const Tag = isLink.value ? 'a' : props.tag;
const hasTitle = slots.title || props.title != null;
const hasSubtitle = slots.subtitle || props.subtitle != null;
const hasAppendMedia = !!(props.appendAvatar || props.appendIcon);
const hasAppend = !!(hasAppendMedia || slots.append);
const hasPrependMedia = !!(props.prependAvatar || props.prependIcon);
const hasPrepend = !!(hasPrependMedia || slots.prepend);
list?.updateHasPrepend(hasPrepend);
if (props.activeColor) {
deprecate('active-color', ['color', 'base-color']);
}
return _withDirectives(_createVNode(Tag, _mergeProps({
"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,
'v-list-item--slim': props.slim,
[`${props.activeClass}`]: props.activeClass && isActive.value
}, themeClasses.value, borderClasses.value, colorClasses.value, densityClasses.value, elevationClasses.value, lineClasses.value, roundedClasses.value, variantClasses.value, props.class],
"style": [colorStyles.value, dimensionStyles.value, props.style],
"tabindex": isClickable.value ? list ? -2 : 0 : undefined,
"aria-selected": isSelectable.value ? root.activatable.value ? isActivated.value : root.selectable.value ? isSelected.value : isActive.value : undefined,
"onClick": onClick,
"onKeydown": isClickable.value && !isLink.value && onKeyDown
}, link.linkProps), {
default: () => [genOverlays(isClickable.value || isActive.value, 'v-list-item'), hasPrepend && _createVNode("div", {
"key": "prepend",
"class": "v-list-item__prepend"
}, [!slots.prepend ? _createVNode(_Fragment, null, [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)]) : _createVNode(VDefaultsProvider, {
"key": "prepend-defaults",
"disabled": !hasPrependMedia,
"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__spacer"
}, null)]), _createVNode("div", {
"class": "v-list-item__content",
"data-no-activator": ""
}, [hasTitle && _createVNode(VListItemTitle, {
"key": "title"
}, {
default: () => [slots.title?.({
title: props.title
}) ?? toDisplayString(props.title)]
}), hasSubtitle && _createVNode(VListItemSubtitle, {
"key": "subtitle"
}, {
default: () => [slots.subtitle?.({
subtitle: props.subtitle
}) ?? toDisplayString(props.subtitle)]
}), slots.default?.(slotProps.value)]), hasAppend && _createVNode("div", {
"key": "append",
"class": "v-list-item__append"
}, [!slots.append ? _createVNode(_Fragment, null, [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)]) : _createVNode(VDefaultsProvider, {
"key": "append-defaults",
"disabled": !hasAppendMedia,
"defaults": {
VAvatar: {
density: props.density,
image: props.appendAvatar
},
VIcon: {
density: props.density,
icon: props.appendIcon
},
VListItemAction: {
end: true
}
}
}, {
default: () => [slots.append?.(slotProps.value)]
}), _createVNode("div", {
"class": "v-list-item__spacer"
}, null)])]
}), [[_resolveDirective("ripple"), isClickable.value && props.ripple]]);
});
return {
activate,
isActivated,
isGroupActivator,
isSelected,
list,
select,
root,
id: uid,
link
};
}
});
//# sourceMappingURL=VListItem.js.map