UNPKG

@vue-ui-kit/ant

Version:

Vue3 UI Kit based on Ant Design

124 lines (110 loc) 4.02 kB
import type { PFormItemProps } from '#/antProxy'; import { defaultItemResponsive } from '@/utils/core'; import type { ColProps } from 'ant-design-vue'; import { computed, onBeforeUnmount, type Ref, ref, watch } from 'vue'; import { omit } from 'xe-utils'; const breakpointOrder = ['xxl', 'xl', 'lg', 'md', 'sm', 'xs'] as const; type Breakpoint = (typeof breakpointOrder)[number]; const breakpointMinWidth: Record<Breakpoint, number> = { xxl: 1600, xl: 1200, lg: 992, md: 768, sm: 576, xs: 0, }; function getActiveBreakpoint(width: number): Breakpoint { return breakpointOrder.find((breakpoint) => width >= breakpointMinWidth[breakpoint]) ?? 'xs'; } function resolveItemCol<F extends Recordable>( item: PFormItemProps<F>, breakpoint: Breakpoint, ): ColProps { if (!item.col) { return item.span ? { span: item.span } : { span: defaultItemResponsive[breakpoint] ?? 24 }; } const baseCol = omit(item.col, [...breakpointOrder]) as ColProps; const activeBreakpointIndex = breakpointOrder.indexOf(breakpoint); for (const responsiveBreakpoint of breakpointOrder.slice(activeBreakpointIndex)) { const responsive = item.col[responsiveBreakpoint]; if (typeof responsive === 'number') return { ...baseCol, span: responsive }; if (responsive && typeof responsive === 'object') return { ...baseCol, ...responsive }; } return baseCol; } function getItemSpan<F extends Recordable>(item: PFormItemProps<F>, breakpoint: Breakpoint) { const activeBreakpointIndex = breakpointOrder.indexOf(breakpoint); for (const responsiveBreakpoint of breakpointOrder.slice(activeBreakpointIndex)) { const responsive = item.col?.[responsiveBreakpoint]; if (typeof responsive === 'number') return responsive; if (responsive && typeof responsive === 'object' && typeof responsive.span === 'number') { return responsive.span; } } if (typeof item.col?.span === 'number') return item.col.span; if (typeof item.span === 'number') return item.span; return defaultItemResponsive[breakpoint] ?? 24; } function countRows(spans: number[]) { if (spans.length === 0) return 0; let rows = 1; let currentSpan = 0; for (const span of spans) { if (currentSpan + span > 24) { rows += 1; currentSpan = span; } else { currentSpan += span; } } return rows; } export function useFormRowLayout<F extends Recordable>( items: Ref<PFormItemProps<F>[]>, containerRef: Readonly<Ref<HTMLElement | null>>, ) { const containerWidth = ref(0); let resizeObserver: ResizeObserver | null = null; const disconnect = () => { resizeObserver?.disconnect(); resizeObserver = null; }; watch( containerRef, (container) => { disconnect(); if (!container) { containerWidth.value = 0; return; } const updateWidth = () => { containerWidth.value = container.getBoundingClientRect().width; }; updateWidth(); if (typeof ResizeObserver !== 'undefined') { resizeObserver = new ResizeObserver(updateWidth); resizeObserver.observe(container); } }, { flush: 'post' }, ); onBeforeUnmount(disconnect); const activeBreakpoint = computed<Breakpoint>(() => getActiveBreakpoint(containerWidth.value)); const resolvedItems = computed<PFormItemProps<F>[]>(() => { if (containerWidth.value <= 0) return items.value; return items.value.map((item) => ({ ...item, col: resolveItemCol(item, activeBreakpoint.value), })); }); const fieldRowCount = computed(() => { const spans = resolvedItems.value .filter((item) => item.itemRender || item.slots?.default) .map((item) => getItemSpan(item, activeBreakpoint.value)); return countRows(spans); }); return { resolvedItems, isSingleRow: computed(() => resolvedItems.value.length > 0 && fieldRowCount.value === 1), }; }