import { makeComponentProps } from '@/composables/component' import { makeTagProps } from '@/composables/tag' import { genericComponent, propsFactory } from '@/utils' import { ref, computed, onMounted, nextTick, ExtractPropTypes, PropType, } from 'vue' import { UCheckbox, UBadge } from '@/components' import Sizes from '@/types/sizes' import BaseCheckboxVariant from '@/types/baseCheckboxVariants' export const makeUTableCellProps = propsFactory( { isChecked: { type: [Boolean, undefined] as PropType, default: undefined, required: false, }, checkboxType: { type: String, default: 'default', required: false, }, disabled: { type: Boolean, default: false, required: false, }, badges: { type: [Array, String] as PropType< Array<{ text: string; color: string; size: string }> | string >, default: 'default', required: false, }, width: { type: String, required: false, }, height: { type: String, default: '72', required: false, }, ...makeComponentProps(), ...makeTagProps(), }, 'UTableCell' ) export type UTableCellProps = ExtractPropTypes export type UTableCellSlots = { default: never } export const UTableCell = genericComponent()({ name: 'UTableCell', props: makeUTableCellProps(), emits: { change: (value: boolean | undefined) => true, 'update:isChecked': (value: boolean | undefined) => true, }, setup(props, { emit, slots }) { const BadgesContainer = ref(null) const BadgesContainerPaddings = ref(0) const CountBadgeWidth = 50 const badgesContainerWidth = ref(0) const BadgesElements = ref([]) const badgesElementWidth = ref([]) // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const slotContent = ref(slots.default && slots.default()[0].type.name) const slotClasses = computed(() => { let classes = '' if (slotContent.value === 'UTableCellText') { classes = 'flex flex-col justify-center items-start' } else if (slotContent.value === 'UButton') { classes = 'overflow-visible flex gap-1 justify-center items-start' } return classes }) onMounted(async () => { await nextTick() const container = BadgesContainer.value if (container) { const { width } = container.getBoundingClientRect() badgesContainerWidth.value = width const computedStyle = getComputedStyle(BadgesContainer.value as Element) BadgesContainerPaddings.value = parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight) } await nextTick() const badges: Element[] = [] badges.push( ...(container?.querySelectorAll( '.badgesElements > *' ) as unknown as Element[]) ) badges.forEach((badge) => { const width = (badge as HTMLElement).clientWidth badgesElementWidth.value.push(width) }) }) const isWidthReady = computed(() => badgesElementWidth.value.length > 0) const getVisibleBadges = computed(() => { const padding = BadgesContainerPaddings.value const containerWidth = badgesContainerWidth.value - padding const badgesWidth = badgesElementWidth.value const visibleBadges = [] let sumWidth = CountBadgeWidth for (let i = 0; i < badgesWidth.length; i++) { sumWidth += badgesWidth[i] + 4 if (sumWidth < containerWidth) { visibleBadges.push(props.badges[i]) } else { break } } const hiddenCount = props.badges.length - visibleBadges.length if (hiddenCount > 0) { const dynamicBadge = { text: `+${hiddenCount}`, color: 'indigo', size: 'sm', } visibleBadges.push(dynamicBadge) } return visibleBadges }) const bgClasses = computed(() => { return props.disabled ? 'bg-gray-25' : `bg-transparent` }) const switchCheckbox = (isChecked: boolean | undefined) => { emit('change', isChecked) emit('update:isChecked', isChecked) } return () => (
{props.isChecked !== undefined ? ( switchCheckbox(props.isChecked)} > ) : null}
{slots.default?.()}
{isWidthReady.value ? getVisibleBadges.value.map((badge, index) => { if (typeof badge === 'string') { return badge } return ( {badge.text} ) }) : Array.isArray(props.badges) ? props.badges.map((badge, index) => { if (typeof badge === 'string') { return badge } return ( {badge.text} ) }) : null}
) }, }) export type UTableCell = InstanceType