import { makeComponentProps } from '@/composables/component' import { computed, ref } from 'vue' import { makeRouterProps, useLink } from '@/composables/router' import { makeTagProps } from '@/composables/tag' import { UIcon } from '@/components/UIcon/UIcon' import { UBadge } from '@/components/UBadge/UBadge' import { genericComponent, propsFactory, useRender } from '@/utils' import { useEventListener } from '@vueuse/core' export const makeUListItemProps = propsFactory( { disabled: { type: Boolean, default: false, }, key: Number, badge: Number, itemId: { type: String, required: true, }, isActive: Boolean, prependIcon: String, type: { type: String, default: 'default', }, subTitle: String, nav: Boolean, ...makeComponentProps(), ...makeTagProps(), ...makeRouterProps(), }, 'UListItem' ) export type UListItemSlots = { default: never header: never } export const UListItem = genericComponent()({ name: 'UListItem', props: makeUListItemProps(), emits: { click: (e: MouseEvent) => true, currentItemId: (value: string) => true, 'keydown:enter': () => true, }, setup(props, { emit, slots, attrs }) { const link = useLink(props, attrs) const isHover = ref(false) const isFocused = ref(false) const navItemTextClasses = computed(() => ({ 'text-text-md font-semibold select-none whitespace-nowrap': true, ...(isHover.value === false && { 'text-gray-700': true, }), ...(isHover.value === true && !props.disabled && { 'text-gray-700': true, }), ...(props.isActive === true && !props.disabled && { 'text-gray-700': true, }), })) const listItemClasses = computed(() => ({ // eslint-disable-next-line max-len 'flex items-center shrink-0 text-text-md font-semibold select-none text-gray-700 py-3 w-full rounded-md overflow-hidden': true, ...(!props.disabled && { 'active:shadow-xs-btn active:shadow-gray-100 cursor-pointer': true, }), ...(props.disabled && { 'cursor-not-allowed': true, }), ...(props.prependIcon != '' && { 'px-3': true, }), ...(props.prependIcon === '' && { 'pr-3 pl-[48px]': true, }), ...(props.isActive === false && !props.disabled && { 'active:bg-transparent hover:bg-gray-50': true, }), ...(props.isActive === true && { 'bg-gray-200 hover:bg-gray-100 active:bg-gray-50': true, }), ...(props.type !== 'small' && { 'justify-between': true, }), ...(props.type === 'small' && { 'h-48 max-w-[48px] shrink-0 justify-center': true, }), })) const prependIconColor = () => { if ( (props.isActive === true || isHover.value === true) && !props.disabled ) { return 'gray-500' } return 'gray-500' } function onClick(e: MouseEvent) { if (props.disabled) return emit('click', e) link.navigate?.(e) } function changeCurrentIndex(id: string) { if (props.disabled) return emit('currentItemId', id) } const handleKeyDown = (event: KeyboardEvent) => { if (isFocused.value && event.key === 'Enter') { emit('keydown:enter') changeCurrentIndex(props.itemId) event.preventDefault() } } useEventListener('keydown', handleKeyDown) useRender(() => { const Tag = link.isLink.value ? 'a' : props.tag return ( { changeCurrentIndex(props.itemId) if (onClick && typeof onClick === 'function') { onClick(event) } }} onMouseover={() => (isHover.value = true)} onMouseleave={() => (isHover.value = false)} onFocus={() => (isFocused.value = true)} onBlur={() => (isFocused.value = false)} onKeydown={handleKeyDown} >
{props.prependIcon ? ( ) : null} {slots.default && props.type !== 'small' ? (
{slots.default?.()}
) : null}
{props.badge && props.type !== 'small' ? (
{props.badge}
) : null}
) }) return { changeCurrentIndex, isHover, } }, }) export type UListItem = InstanceType