817 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Vue
		
	
	
			
		
		
	
	
			817 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Vue
		
	
	
import Header from './Header/Header';
 | 
						|
import type {
 | 
						|
  GetRowKey,
 | 
						|
  ColumnsType,
 | 
						|
  TableComponents,
 | 
						|
  Key,
 | 
						|
  TriggerEventHandler,
 | 
						|
  GetComponentProps,
 | 
						|
  PanelRender,
 | 
						|
  TableLayout,
 | 
						|
  RowClassName,
 | 
						|
  CustomizeComponent,
 | 
						|
  ColumnType,
 | 
						|
  CustomizeScrollBody,
 | 
						|
  TableSticky,
 | 
						|
  ExpandedRowRender,
 | 
						|
  RenderExpandIcon,
 | 
						|
  TransformCellText,
 | 
						|
  DefaultRecordType,
 | 
						|
} from './interface';
 | 
						|
import Body from './Body';
 | 
						|
import useColumns from './hooks/useColumns';
 | 
						|
import { useLayoutState, useTimeoutLock } from './hooks/useFrame';
 | 
						|
import { getPathValue, mergeObject, validateValue, getColumnsKey } from './utils/valueUtil';
 | 
						|
import useStickyOffsets from './hooks/useStickyOffsets';
 | 
						|
import ColGroup from './ColGroup';
 | 
						|
import Panel from './Panel';
 | 
						|
import Footer from './Footer';
 | 
						|
import { findAllChildrenKeys, renderExpandIcon } from './utils/expandUtil';
 | 
						|
import { getCellFixedInfo } from './utils/fixUtil';
 | 
						|
import StickyScrollBar from './stickyScrollBar';
 | 
						|
import useSticky from './hooks/useSticky';
 | 
						|
import FixedHolder from './FixedHolder';
 | 
						|
import type { CSSProperties } from 'vue';
 | 
						|
import {
 | 
						|
  computed,
 | 
						|
  defineComponent,
 | 
						|
  nextTick,
 | 
						|
  onMounted,
 | 
						|
  reactive,
 | 
						|
  ref,
 | 
						|
  shallowRef,
 | 
						|
  toRef,
 | 
						|
  toRefs,
 | 
						|
  watch,
 | 
						|
  watchEffect,
 | 
						|
} from 'vue';
 | 
						|
import { warning } from '../vc-util/warning';
 | 
						|
import { reactivePick } from '../_util/reactivePick';
 | 
						|
import useState from '../_util/hooks/useState';
 | 
						|
import { toPx } from '../_util/util';
 | 
						|
import isVisible from '../vc-util/Dom/isVisible';
 | 
						|
import { getTargetScrollBarSize } from '../_util/getScrollBarSize';
 | 
						|
import classNames from '../_util/classNames';
 | 
						|
import type { EventHandler } from '../_util/EventInterface';
 | 
						|
import VCResizeObserver from '../vc-resize-observer';
 | 
						|
import { useProvideTable } from './context/TableContext';
 | 
						|
import { useProvideBody } from './context/BodyContext';
 | 
						|
import { useProvideResize } from './context/ResizeContext';
 | 
						|
import { getDataAndAriaProps } from './utils/legacyUtil';
 | 
						|
 | 
						|
// Used for conditions cache
 | 
						|
const EMPTY_DATA = [];
 | 
						|
 | 
						|
// Used for customize scroll
 | 
						|
const EMPTY_SCROLL_TARGET = {};
 | 
						|
 | 
						|
export const INTERNAL_HOOKS = 'rc-table-internal-hook';
 | 
						|
 | 
						|
export interface TableProps<RecordType = DefaultRecordType> {
 | 
						|
  prefixCls?: string;
 | 
						|
  data?: RecordType[];
 | 
						|
  columns?: ColumnsType<RecordType>;
 | 
						|
  rowKey?: string | GetRowKey<RecordType>;
 | 
						|
  tableLayout?: TableLayout;
 | 
						|
 | 
						|
  // Fixed Columns
 | 
						|
  scroll?: { x?: number | true | string; y?: number | string };
 | 
						|
 | 
						|
  rowClassName?: string | RowClassName<RecordType>;
 | 
						|
 | 
						|
  // Additional Part
 | 
						|
  title?: PanelRender<RecordType>;
 | 
						|
  footer?: PanelRender<RecordType>;
 | 
						|
  // summary?: (data: readonly RecordType[]) => any;
 | 
						|
 | 
						|
  // Customize
 | 
						|
  id?: string;
 | 
						|
  showHeader?: boolean;
 | 
						|
  components?: TableComponents<RecordType>;
 | 
						|
  customRow?: GetComponentProps<RecordType>;
 | 
						|
  customHeaderRow?: GetComponentProps<ColumnType<RecordType>[]>;
 | 
						|
  // emptyText?: any;
 | 
						|
 | 
						|
  direction?: 'ltr' | 'rtl';
 | 
						|
 | 
						|
  // Expandable
 | 
						|
  expandFixed?: boolean;
 | 
						|
  expandColumnWidth?: number;
 | 
						|
  expandedRowKeys?: Key[];
 | 
						|
  defaultExpandedRowKeys?: Key[];
 | 
						|
  expandedRowRender?: ExpandedRowRender<RecordType>;
 | 
						|
  expandRowByClick?: boolean;
 | 
						|
  expandIcon?: RenderExpandIcon<RecordType>;
 | 
						|
  onExpand?: (expanded: boolean, record: RecordType) => void;
 | 
						|
  onExpandedRowsChange?: (expandedKeys: Key[]) => void;
 | 
						|
  defaultExpandAllRows?: boolean;
 | 
						|
  indentSize?: number;
 | 
						|
  expandIconColumnIndex?: number;
 | 
						|
  expandedRowClassName?: RowClassName<RecordType>;
 | 
						|
  childrenColumnName?: string;
 | 
						|
  rowExpandable?: (record: RecordType) => boolean;
 | 
						|
 | 
						|
  // =================================== Internal ===================================
 | 
						|
  /**
 | 
						|
   * @private Internal usage, may remove by refactor. Should always use `columns` instead.
 | 
						|
   *
 | 
						|
   * !!! DO NOT USE IN PRODUCTION ENVIRONMENT !!!
 | 
						|
   */
 | 
						|
  internalHooks?: string;
 | 
						|
 | 
						|
  /**
 | 
						|
   * @private Internal usage, may remove by refactor. Should always use `columns` instead.
 | 
						|
   *
 | 
						|
   * !!! DO NOT USE IN PRODUCTION ENVIRONMENT !!!
 | 
						|
   */
 | 
						|
  // Used for antd table transform column with additional column
 | 
						|
  transformColumns?: (columns: ColumnsType<RecordType>) => ColumnsType<RecordType>;
 | 
						|
 | 
						|
  /**
 | 
						|
   * @private Internal usage, may remove by refactor.
 | 
						|
   *
 | 
						|
   * !!! DO NOT USE IN PRODUCTION ENVIRONMENT !!!
 | 
						|
   */
 | 
						|
  internalRefs?: {
 | 
						|
    body: HTMLDivElement;
 | 
						|
  };
 | 
						|
 | 
						|
  sticky?: boolean | TableSticky;
 | 
						|
 | 
						|
  canExpandable?: boolean;
 | 
						|
 | 
						|
  onUpdateInternalRefs?: (refs: Record<string, any>) => void;
 | 
						|
 | 
						|
  transformCellText?: TransformCellText<RecordType>;
 | 
						|
}
 | 
						|
 | 
						|
export default defineComponent<TableProps<DefaultRecordType>>({
 | 
						|
  name: 'Table',
 | 
						|
  inheritAttrs: false,
 | 
						|
  props: [
 | 
						|
    'prefixCls',
 | 
						|
    'data',
 | 
						|
    'columns',
 | 
						|
    'rowKey',
 | 
						|
    'tableLayout',
 | 
						|
    'scroll',
 | 
						|
    'rowClassName',
 | 
						|
    'title',
 | 
						|
    'footer',
 | 
						|
    'id',
 | 
						|
    'showHeader',
 | 
						|
    'components',
 | 
						|
    'customRow',
 | 
						|
    'customHeaderRow',
 | 
						|
    'direction',
 | 
						|
    'expandFixed',
 | 
						|
    'expandColumnWidth',
 | 
						|
    'expandedRowKeys',
 | 
						|
    'defaultExpandedRowKeys',
 | 
						|
    'expandedRowRender',
 | 
						|
    'expandRowByClick',
 | 
						|
    'expandIcon',
 | 
						|
    'onExpand',
 | 
						|
    'onExpandedRowsChange',
 | 
						|
    'defaultExpandAllRows',
 | 
						|
    'indentSize',
 | 
						|
    'expandIconColumnIndex',
 | 
						|
    'expandedRowClassName',
 | 
						|
    'childrenColumnName',
 | 
						|
    'rowExpandable',
 | 
						|
    'sticky',
 | 
						|
    'transformColumns',
 | 
						|
    'internalHooks',
 | 
						|
    'internalRefs',
 | 
						|
    'canExpandable',
 | 
						|
    'onUpdateInternalRefs',
 | 
						|
    'transformCellText',
 | 
						|
  ] as any,
 | 
						|
  slots: ['title', 'footer', 'summary', 'emptyText'],
 | 
						|
  emits: ['expand', 'expandedRowsChange', 'updateInternalRefs'],
 | 
						|
  setup(props, { attrs, slots, emit }) {
 | 
						|
    const mergedData = computed(() => props.data || EMPTY_DATA);
 | 
						|
    const hasData = computed(() => !!mergedData.value.length);
 | 
						|
    // ==================== Customize =====================
 | 
						|
    const mergedComponents = computed(() =>
 | 
						|
      mergeObject<TableComponents<any>>(props.components, {}),
 | 
						|
    );
 | 
						|
 | 
						|
    const getComponent = (path, defaultComponent?: string) =>
 | 
						|
      getPathValue<CustomizeComponent, TableComponents<any>>(mergedComponents.value, path) ||
 | 
						|
      defaultComponent;
 | 
						|
 | 
						|
    const getRowKey = computed(() => {
 | 
						|
      const rowKey = props.rowKey;
 | 
						|
      if (typeof rowKey === 'function') {
 | 
						|
        return rowKey;
 | 
						|
      }
 | 
						|
      return record => {
 | 
						|
        const key = record && record[rowKey];
 | 
						|
 | 
						|
        if (process.env.NODE_ENV !== 'production') {
 | 
						|
          warning(
 | 
						|
            key !== undefined,
 | 
						|
            'Each record in table should have a unique `key` prop, or set `rowKey` to an unique primary key.',
 | 
						|
          );
 | 
						|
        }
 | 
						|
 | 
						|
        return key;
 | 
						|
      };
 | 
						|
    });
 | 
						|
 | 
						|
    // ====================== Expand ======================
 | 
						|
 | 
						|
    const mergedExpandIcon = computed(() => props.expandIcon || renderExpandIcon);
 | 
						|
 | 
						|
    const mergedChildrenColumnName = computed(() => props.childrenColumnName || 'children');
 | 
						|
 | 
						|
    const expandableType = computed(() => {
 | 
						|
      if (props.expandedRowRender) {
 | 
						|
        return 'row';
 | 
						|
      }
 | 
						|
      /* eslint-disable no-underscore-dangle */
 | 
						|
      /**
 | 
						|
       * Fix https://github.com/ant-design/ant-design/issues/21154
 | 
						|
       * This is a workaround to not to break current behavior.
 | 
						|
       * We can remove follow code after final release.
 | 
						|
       *
 | 
						|
       * To other developer:
 | 
						|
       *  Do not use `__PARENT_RENDER_ICON__` in prod since we will remove this when refactor
 | 
						|
       */
 | 
						|
      if (
 | 
						|
        props.canExpandable ||
 | 
						|
        mergedData.value.some(
 | 
						|
          record => record && typeof record === 'object' && record[mergedChildrenColumnName.value],
 | 
						|
        )
 | 
						|
      ) {
 | 
						|
        return 'nest';
 | 
						|
      }
 | 
						|
      /* eslint-enable */
 | 
						|
      return false;
 | 
						|
    });
 | 
						|
 | 
						|
    const innerExpandedKeys = shallowRef([]);
 | 
						|
    const stop = watchEffect(() => {
 | 
						|
      if (props.defaultExpandedRowKeys) {
 | 
						|
        innerExpandedKeys.value = props.defaultExpandedRowKeys;
 | 
						|
      }
 | 
						|
      if (props.defaultExpandAllRows) {
 | 
						|
        innerExpandedKeys.value = findAllChildrenKeys(
 | 
						|
          mergedData.value,
 | 
						|
          getRowKey.value,
 | 
						|
          mergedChildrenColumnName.value,
 | 
						|
        );
 | 
						|
      }
 | 
						|
    });
 | 
						|
    // defalutXxxx äģ
äģ
įŦŦ䏿ŦĄįæ
 | 
						|
    stop();
 | 
						|
 | 
						|
    const mergedExpandedKeys = computed(
 | 
						|
      () => new Set(props.expandedRowKeys || innerExpandedKeys.value || []),
 | 
						|
    );
 | 
						|
 | 
						|
    const onTriggerExpand: TriggerEventHandler<any> = record => {
 | 
						|
      const key = getRowKey.value(record, mergedData.value.indexOf(record));
 | 
						|
 | 
						|
      let newExpandedKeys: Key[];
 | 
						|
      const hasKey = mergedExpandedKeys.value.has(key);
 | 
						|
      if (hasKey) {
 | 
						|
        mergedExpandedKeys.value.delete(key);
 | 
						|
        newExpandedKeys = [...mergedExpandedKeys.value];
 | 
						|
      } else {
 | 
						|
        newExpandedKeys = [...mergedExpandedKeys.value, key];
 | 
						|
      }
 | 
						|
      innerExpandedKeys.value = newExpandedKeys;
 | 
						|
 | 
						|
      emit('expand', !hasKey, record);
 | 
						|
      emit('expandedRowsChange', newExpandedKeys);
 | 
						|
    };
 | 
						|
 | 
						|
    const componentWidth = ref(0);
 | 
						|
 | 
						|
    const [columns, flattenColumns] = useColumns(
 | 
						|
      {
 | 
						|
        ...toRefs(props),
 | 
						|
 | 
						|
        // children,
 | 
						|
        expandable: computed(() => !!props.expandedRowRender),
 | 
						|
        expandedKeys: mergedExpandedKeys,
 | 
						|
        getRowKey,
 | 
						|
        onTriggerExpand,
 | 
						|
        expandIcon: mergedExpandIcon,
 | 
						|
      },
 | 
						|
      computed(() => (props.internalHooks === INTERNAL_HOOKS ? props.transformColumns : null)),
 | 
						|
    );
 | 
						|
 | 
						|
    const columnContext = computed(() => ({
 | 
						|
      columns: columns.value,
 | 
						|
      flattenColumns: flattenColumns.value,
 | 
						|
    }));
 | 
						|
 | 
						|
    // ====================== Scroll ======================
 | 
						|
    const fullTableRef = ref<HTMLDivElement>();
 | 
						|
    const scrollHeaderRef = ref<HTMLDivElement>();
 | 
						|
    const scrollBodyRef = ref<HTMLDivElement>();
 | 
						|
    const scrollSummaryRef = ref<HTMLDivElement>();
 | 
						|
    const [pingedLeft, setPingedLeft] = useState(false);
 | 
						|
    const [pingedRight, setPingedRight] = useState(false);
 | 
						|
    const [colsWidths, updateColsWidths] = useLayoutState(new Map<Key, number>());
 | 
						|
 | 
						|
    // Convert map to number width
 | 
						|
    const colsKeys = computed(() => getColumnsKey(flattenColumns.value));
 | 
						|
    const colWidths = computed(() =>
 | 
						|
      colsKeys.value.map(columnKey => colsWidths.value.get(columnKey)),
 | 
						|
    );
 | 
						|
    const columnCount = computed(() => flattenColumns.value.length);
 | 
						|
    const stickyOffsets = useStickyOffsets(colWidths, columnCount, toRef(props, 'direction'));
 | 
						|
    const fixHeader = computed(() => props.scroll && validateValue(props.scroll.y));
 | 
						|
    const horizonScroll = computed(
 | 
						|
      () => (props.scroll && validateValue(props.scroll.x)) || Boolean(props.expandFixed),
 | 
						|
    );
 | 
						|
    const fixColumn = computed(
 | 
						|
      () => horizonScroll.value && flattenColumns.value.some(({ fixed }) => fixed),
 | 
						|
    );
 | 
						|
 | 
						|
    // Sticky
 | 
						|
    const stickyRef = ref<{ setScrollLeft: (left: number) => void }>();
 | 
						|
    const stickyState = useSticky(toRef(props, 'sticky'), toRef(props, 'prefixCls'));
 | 
						|
 | 
						|
    const summaryFixedInfos = reactive<Record<string, boolean | string>>({});
 | 
						|
    const fixFooter = computed(() => {
 | 
						|
      const info = Object.values(summaryFixedInfos)[0];
 | 
						|
      return (fixHeader.value || stickyState.value.isSticky) && info;
 | 
						|
    });
 | 
						|
 | 
						|
    const summaryCollect = (uniKey: string, fixed: boolean | string) => {
 | 
						|
      if (fixed) {
 | 
						|
        summaryFixedInfos[uniKey] = fixed;
 | 
						|
      } else {
 | 
						|
        delete summaryFixedInfos[uniKey];
 | 
						|
      }
 | 
						|
    };
 | 
						|
 | 
						|
    // Scroll
 | 
						|
    const scrollXStyle = ref<CSSProperties>({});
 | 
						|
    const scrollYStyle = ref<CSSProperties>({});
 | 
						|
    const scrollTableStyle = ref<CSSProperties>({});
 | 
						|
 | 
						|
    watchEffect(() => {
 | 
						|
      if (fixHeader.value) {
 | 
						|
        scrollYStyle.value = {
 | 
						|
          overflowY: 'scroll',
 | 
						|
          maxHeight: toPx(props.scroll.y),
 | 
						|
        };
 | 
						|
      }
 | 
						|
 | 
						|
      if (horizonScroll.value) {
 | 
						|
        scrollXStyle.value = { overflowX: 'auto' };
 | 
						|
        // When no vertical scrollbar, should hide it
 | 
						|
        // https://github.com/ant-design/ant-design/pull/20705
 | 
						|
        // https://github.com/ant-design/ant-design/issues/21879
 | 
						|
        if (!fixHeader.value) {
 | 
						|
          scrollYStyle.value = { overflowY: 'hidden' };
 | 
						|
        }
 | 
						|
        scrollTableStyle.value = {
 | 
						|
          width: props.scroll.x === true ? 'auto' : toPx(props.scroll.x),
 | 
						|
          minWidth: '100%',
 | 
						|
        };
 | 
						|
      }
 | 
						|
    });
 | 
						|
 | 
						|
    const onColumnResize = (columnKey: Key, width: number) => {
 | 
						|
      if (isVisible(fullTableRef.value)) {
 | 
						|
        updateColsWidths(widths => {
 | 
						|
          if (widths.get(columnKey) !== width) {
 | 
						|
            const newWidths = new Map(widths);
 | 
						|
            newWidths.set(columnKey, width);
 | 
						|
            return newWidths;
 | 
						|
          }
 | 
						|
          return widths;
 | 
						|
        });
 | 
						|
      }
 | 
						|
    };
 | 
						|
 | 
						|
    const [setScrollTarget, getScrollTarget] = useTimeoutLock(null);
 | 
						|
 | 
						|
    function forceScroll(scrollLeft: number, target: HTMLDivElement | ((left: number) => void)) {
 | 
						|
      if (!target) {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      if (typeof target === 'function') {
 | 
						|
        target(scrollLeft);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      const domTarget = (target as any).$el || target;
 | 
						|
      if (domTarget.scrollLeft !== scrollLeft) {
 | 
						|
        // eslint-disable-next-line no-param-reassign
 | 
						|
        domTarget.scrollLeft = scrollLeft;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    const onScroll: EventHandler = ({
 | 
						|
      currentTarget,
 | 
						|
      scrollLeft,
 | 
						|
    }: {
 | 
						|
      currentTarget: HTMLElement;
 | 
						|
      scrollLeft?: number;
 | 
						|
    }) => {
 | 
						|
      const isRTL = props.direction === 'rtl';
 | 
						|
      const mergedScrollLeft =
 | 
						|
        typeof scrollLeft === 'number' ? scrollLeft : currentTarget.scrollLeft;
 | 
						|
 | 
						|
      const compareTarget = currentTarget || EMPTY_SCROLL_TARGET;
 | 
						|
      if (!getScrollTarget() || getScrollTarget() === compareTarget) {
 | 
						|
        setScrollTarget(compareTarget);
 | 
						|
 | 
						|
        forceScroll(mergedScrollLeft, scrollHeaderRef.value);
 | 
						|
        forceScroll(mergedScrollLeft, scrollBodyRef.value);
 | 
						|
        forceScroll(mergedScrollLeft, scrollSummaryRef.value);
 | 
						|
        forceScroll(mergedScrollLeft, stickyRef.value?.setScrollLeft);
 | 
						|
      }
 | 
						|
 | 
						|
      if (currentTarget) {
 | 
						|
        const { scrollWidth, clientWidth } = currentTarget;
 | 
						|
        if (isRTL) {
 | 
						|
          setPingedLeft(-mergedScrollLeft < scrollWidth - clientWidth);
 | 
						|
          setPingedRight(-mergedScrollLeft > 0);
 | 
						|
        } else {
 | 
						|
          setPingedLeft(mergedScrollLeft > 0);
 | 
						|
          setPingedRight(mergedScrollLeft < scrollWidth - clientWidth);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    };
 | 
						|
 | 
						|
    const triggerOnScroll = () => {
 | 
						|
      if (scrollBodyRef.value) {
 | 
						|
        onScroll({ currentTarget: scrollBodyRef.value });
 | 
						|
      }
 | 
						|
    };
 | 
						|
    let timtout;
 | 
						|
    const updateWidth = (width: number) => {
 | 
						|
      if (width !== componentWidth.value) {
 | 
						|
        triggerOnScroll();
 | 
						|
        componentWidth.value = fullTableRef.value ? fullTableRef.value.offsetWidth : width;
 | 
						|
      }
 | 
						|
    };
 | 
						|
    const onFullTableResize = ({ width }) => {
 | 
						|
      clearTimeout(timtout);
 | 
						|
      if (componentWidth.value === 0) {
 | 
						|
        updateWidth(width);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      timtout = setTimeout(() => {
 | 
						|
        updateWidth(width);
 | 
						|
      }, 100);
 | 
						|
    };
 | 
						|
 | 
						|
    watch([horizonScroll, () => props.data, () => props.columns], () => {
 | 
						|
      if (horizonScroll.value) {
 | 
						|
        triggerOnScroll();
 | 
						|
      }
 | 
						|
    });
 | 
						|
 | 
						|
    const [scrollbarSize, setScrollbarSize] = useState(0);
 | 
						|
 | 
						|
    onMounted(() => {
 | 
						|
      nextTick(() => {
 | 
						|
        triggerOnScroll();
 | 
						|
        setScrollbarSize(getTargetScrollBarSize(scrollBodyRef.value).width);
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    watchEffect(
 | 
						|
      () => {
 | 
						|
        if (props.internalHooks === INTERNAL_HOOKS && props.internalRefs) {
 | 
						|
          props.onUpdateInternalRefs({
 | 
						|
            body: scrollBodyRef.value
 | 
						|
              ? (scrollBodyRef.value as any).$el || scrollBodyRef.value
 | 
						|
              : null,
 | 
						|
          });
 | 
						|
        }
 | 
						|
      },
 | 
						|
      { flush: 'post' },
 | 
						|
    );
 | 
						|
 | 
						|
    // Table layout
 | 
						|
    const mergedTableLayout = computed(() => {
 | 
						|
      if (props.tableLayout) {
 | 
						|
        return props.tableLayout;
 | 
						|
      }
 | 
						|
      // https://github.com/ant-design/ant-design/issues/25227
 | 
						|
      // When scroll.x is max-content, no need to fix table layout
 | 
						|
      // it's width should stretch out to fit content
 | 
						|
      if (fixColumn.value) {
 | 
						|
        return props.scroll.x === 'max-content' ? 'auto' : 'fixed';
 | 
						|
      }
 | 
						|
      if (
 | 
						|
        fixHeader.value ||
 | 
						|
        stickyState.value.isSticky ||
 | 
						|
        flattenColumns.value.some(({ ellipsis }) => ellipsis)
 | 
						|
      ) {
 | 
						|
        return 'fixed';
 | 
						|
      }
 | 
						|
      return 'auto';
 | 
						|
    });
 | 
						|
 | 
						|
    const emptyNode = () => {
 | 
						|
      return hasData.value ? null : slots.emptyText?.() || 'No Data';
 | 
						|
    };
 | 
						|
    useProvideTable(
 | 
						|
      reactive({
 | 
						|
        ...toRefs(reactivePick(props, 'prefixCls', 'direction', 'transformCellText')),
 | 
						|
        getComponent,
 | 
						|
        scrollbarSize,
 | 
						|
        fixedInfoList: computed(() =>
 | 
						|
          flattenColumns.value.map((_, colIndex) =>
 | 
						|
            getCellFixedInfo(
 | 
						|
              colIndex,
 | 
						|
              colIndex,
 | 
						|
              flattenColumns.value,
 | 
						|
              stickyOffsets.value,
 | 
						|
              props.direction,
 | 
						|
            ),
 | 
						|
          ),
 | 
						|
        ),
 | 
						|
        isSticky: computed(() => stickyState.value.isSticky),
 | 
						|
        summaryCollect,
 | 
						|
      }),
 | 
						|
    );
 | 
						|
    useProvideBody(
 | 
						|
      reactive({
 | 
						|
        ...toRefs(
 | 
						|
          reactivePick(
 | 
						|
            props,
 | 
						|
            'rowClassName',
 | 
						|
            'expandedRowClassName',
 | 
						|
            'expandRowByClick',
 | 
						|
            'expandedRowRender',
 | 
						|
            'expandIconColumnIndex',
 | 
						|
            'indentSize',
 | 
						|
          ),
 | 
						|
        ),
 | 
						|
        columns,
 | 
						|
        flattenColumns,
 | 
						|
        tableLayout: mergedTableLayout,
 | 
						|
        componentWidth,
 | 
						|
        fixHeader,
 | 
						|
        fixColumn,
 | 
						|
        horizonScroll,
 | 
						|
        expandIcon: mergedExpandIcon,
 | 
						|
        expandableType,
 | 
						|
        onTriggerExpand,
 | 
						|
      }),
 | 
						|
    );
 | 
						|
 | 
						|
    useProvideResize({
 | 
						|
      onColumnResize,
 | 
						|
    });
 | 
						|
 | 
						|
    // Body
 | 
						|
    const bodyTable = () => (
 | 
						|
      <Body
 | 
						|
        data={mergedData.value}
 | 
						|
        measureColumnWidth={fixHeader.value || horizonScroll.value || stickyState.value.isSticky}
 | 
						|
        expandedKeys={mergedExpandedKeys.value}
 | 
						|
        rowExpandable={props.rowExpandable}
 | 
						|
        getRowKey={getRowKey.value}
 | 
						|
        customRow={props.customRow}
 | 
						|
        childrenColumnName={mergedChildrenColumnName.value}
 | 
						|
        v-slots={{ emptyNode }}
 | 
						|
      />
 | 
						|
    );
 | 
						|
 | 
						|
    const bodyColGroup = () => (
 | 
						|
      <ColGroup
 | 
						|
        colWidths={flattenColumns.value.map(({ width }) => width)}
 | 
						|
        columns={flattenColumns.value}
 | 
						|
      />
 | 
						|
    );
 | 
						|
    return () => {
 | 
						|
      const {
 | 
						|
        prefixCls,
 | 
						|
        scroll,
 | 
						|
        tableLayout,
 | 
						|
        direction,
 | 
						|
 | 
						|
        // Additional Part
 | 
						|
        title = slots.title,
 | 
						|
        footer = slots.footer,
 | 
						|
 | 
						|
        // Customize
 | 
						|
        id,
 | 
						|
        showHeader,
 | 
						|
        customHeaderRow,
 | 
						|
      } = props;
 | 
						|
      const { isSticky, offsetHeader, offsetSummary, offsetScroll, stickyClassName, container } =
 | 
						|
        stickyState.value;
 | 
						|
      const TableComponent = getComponent(['table'], 'table');
 | 
						|
      const customizeScrollBody = getComponent(['body']) as unknown as CustomizeScrollBody<any>;
 | 
						|
      const summaryNode = slots.summary?.({ pageData: mergedData.value });
 | 
						|
 | 
						|
      let groupTableNode = () => null;
 | 
						|
 | 
						|
      // Header props
 | 
						|
      const headerProps = {
 | 
						|
        colWidths: colWidths.value,
 | 
						|
        columCount: flattenColumns.value.length,
 | 
						|
        stickyOffsets: stickyOffsets.value,
 | 
						|
        customHeaderRow,
 | 
						|
        fixHeader: fixHeader.value,
 | 
						|
        scroll,
 | 
						|
      };
 | 
						|
 | 
						|
      if (
 | 
						|
        process.env.NODE_ENV !== 'production' &&
 | 
						|
        typeof customizeScrollBody === 'function' &&
 | 
						|
        hasData.value &&
 | 
						|
        !fixHeader.value
 | 
						|
      ) {
 | 
						|
        warning(false, '`components.body` with render props is only work on `scroll.y`.');
 | 
						|
      }
 | 
						|
      if (fixHeader.value || isSticky) {
 | 
						|
        // >>>>>> Fixed Header
 | 
						|
        let bodyContent = () => null;
 | 
						|
 | 
						|
        if (typeof customizeScrollBody === 'function') {
 | 
						|
          bodyContent = () =>
 | 
						|
            customizeScrollBody(mergedData.value, {
 | 
						|
              scrollbarSize: scrollbarSize.value,
 | 
						|
              ref: scrollBodyRef,
 | 
						|
              onScroll,
 | 
						|
            });
 | 
						|
 | 
						|
          headerProps.colWidths = flattenColumns.value.map(({ width }, index) => {
 | 
						|
            const colWidth =
 | 
						|
              index === columns.value.length - 1 ? (width as number) - scrollbarSize.value : width;
 | 
						|
            if (typeof colWidth === 'number' && !Number.isNaN(colWidth)) {
 | 
						|
              return colWidth;
 | 
						|
            }
 | 
						|
            warning(
 | 
						|
              false,
 | 
						|
              'When use `components.body` with render props. Each column should have a fixed `width` value.',
 | 
						|
            );
 | 
						|
 | 
						|
            return 0;
 | 
						|
          }) as number[];
 | 
						|
        } else {
 | 
						|
          bodyContent = () => (
 | 
						|
            <div
 | 
						|
              style={{
 | 
						|
                ...scrollXStyle.value,
 | 
						|
                ...scrollYStyle.value,
 | 
						|
              }}
 | 
						|
              onScroll={onScroll}
 | 
						|
              ref={scrollBodyRef}
 | 
						|
              class={classNames(`${prefixCls}-body`)}
 | 
						|
            >
 | 
						|
              <TableComponent
 | 
						|
                style={{
 | 
						|
                  ...scrollTableStyle.value,
 | 
						|
                  tableLayout: mergedTableLayout.value,
 | 
						|
                }}
 | 
						|
              >
 | 
						|
                {bodyColGroup()}
 | 
						|
                {bodyTable()}
 | 
						|
                {!fixFooter.value && summaryNode && (
 | 
						|
                  <Footer stickyOffsets={stickyOffsets.value} flattenColumns={flattenColumns.value}>
 | 
						|
                    {summaryNode}
 | 
						|
                  </Footer>
 | 
						|
                )}
 | 
						|
              </TableComponent>
 | 
						|
            </div>
 | 
						|
          );
 | 
						|
        }
 | 
						|
 | 
						|
        // Fixed holder share the props
 | 
						|
        const fixedHolderProps = {
 | 
						|
          noData: !mergedData.value.length,
 | 
						|
          maxContentScroll: horizonScroll.value && scroll.x === 'max-content',
 | 
						|
          ...headerProps,
 | 
						|
          ...columnContext.value,
 | 
						|
          direction,
 | 
						|
          stickyClassName,
 | 
						|
          onScroll,
 | 
						|
        };
 | 
						|
 | 
						|
        groupTableNode = () => (
 | 
						|
          <>
 | 
						|
            {/* Header Table */}
 | 
						|
            {showHeader !== false && (
 | 
						|
              <FixedHolder
 | 
						|
                {...fixedHolderProps}
 | 
						|
                stickyTopOffset={offsetHeader}
 | 
						|
                class={`${prefixCls}-header`}
 | 
						|
                ref={scrollHeaderRef}
 | 
						|
                v-slots={{
 | 
						|
                  default: fixedHolderPassProps => (
 | 
						|
                    <>
 | 
						|
                      <Header {...fixedHolderPassProps} />
 | 
						|
                      {fixFooter.value === 'top' && (
 | 
						|
                        <Footer {...fixedHolderPassProps}>{summaryNode}</Footer>
 | 
						|
                      )}
 | 
						|
                    </>
 | 
						|
                  ),
 | 
						|
                }}
 | 
						|
              ></FixedHolder>
 | 
						|
            )}
 | 
						|
 | 
						|
            {/* Body Table */}
 | 
						|
            {bodyContent()}
 | 
						|
 | 
						|
            {/* Summary Table */}
 | 
						|
            {fixFooter.value && fixFooter.value !== 'top' && (
 | 
						|
              <FixedHolder
 | 
						|
                {...fixedHolderProps}
 | 
						|
                stickyBottomOffset={offsetSummary}
 | 
						|
                class={`${prefixCls}-summary`}
 | 
						|
                ref={scrollSummaryRef}
 | 
						|
                v-slots={{
 | 
						|
                  default: fixedHolderPassProps => (
 | 
						|
                    <Footer {...fixedHolderPassProps}>{summaryNode}</Footer>
 | 
						|
                  ),
 | 
						|
                }}
 | 
						|
              ></FixedHolder>
 | 
						|
            )}
 | 
						|
 | 
						|
            {isSticky && scrollBodyRef.value && (
 | 
						|
              <StickyScrollBar
 | 
						|
                ref={stickyRef}
 | 
						|
                offsetScroll={offsetScroll}
 | 
						|
                scrollBodyRef={scrollBodyRef}
 | 
						|
                onScroll={onScroll}
 | 
						|
                container={container}
 | 
						|
              />
 | 
						|
            )}
 | 
						|
          </>
 | 
						|
        );
 | 
						|
      } else {
 | 
						|
        // >>>>>> Unique table
 | 
						|
        groupTableNode = () => (
 | 
						|
          <div
 | 
						|
            style={{
 | 
						|
              ...scrollXStyle.value,
 | 
						|
              ...scrollYStyle.value,
 | 
						|
            }}
 | 
						|
            class={classNames(`${prefixCls}-content`)}
 | 
						|
            onScroll={onScroll}
 | 
						|
            ref={scrollBodyRef}
 | 
						|
          >
 | 
						|
            <TableComponent
 | 
						|
              style={{ ...scrollTableStyle.value, tableLayout: mergedTableLayout.value }}
 | 
						|
            >
 | 
						|
              {bodyColGroup()}
 | 
						|
              {showHeader !== false && <Header {...headerProps} {...columnContext.value} />}
 | 
						|
              {bodyTable()}
 | 
						|
              {summaryNode && (
 | 
						|
                <Footer stickyOffsets={stickyOffsets.value} flattenColumns={flattenColumns.value}>
 | 
						|
                  {summaryNode}
 | 
						|
                </Footer>
 | 
						|
              )}
 | 
						|
            </TableComponent>
 | 
						|
          </div>
 | 
						|
        );
 | 
						|
      }
 | 
						|
      const ariaProps = getDataAndAriaProps(attrs);
 | 
						|
      const fullTable = () => (
 | 
						|
        <div
 | 
						|
          {...ariaProps}
 | 
						|
          class={classNames(prefixCls, {
 | 
						|
            [`${prefixCls}-rtl`]: direction === 'rtl',
 | 
						|
            [`${prefixCls}-ping-left`]: pingedLeft.value,
 | 
						|
            [`${prefixCls}-ping-right`]: pingedRight.value,
 | 
						|
            [`${prefixCls}-layout-fixed`]: tableLayout === 'fixed',
 | 
						|
            [`${prefixCls}-fixed-header`]: fixHeader.value,
 | 
						|
            /** No used but for compatible */
 | 
						|
            [`${prefixCls}-fixed-column`]: fixColumn.value,
 | 
						|
            [`${prefixCls}-scroll-horizontal`]: horizonScroll.value,
 | 
						|
            [`${prefixCls}-has-fix-left`]: flattenColumns.value[0] && flattenColumns.value[0].fixed,
 | 
						|
            [`${prefixCls}-has-fix-right`]:
 | 
						|
              flattenColumns.value[columnCount.value - 1] &&
 | 
						|
              flattenColumns.value[columnCount.value - 1].fixed === 'right',
 | 
						|
            [attrs.class as string]: attrs.class,
 | 
						|
          })}
 | 
						|
          style={attrs.style}
 | 
						|
          id={id}
 | 
						|
          ref={fullTableRef}
 | 
						|
        >
 | 
						|
          {title && <Panel class={`${prefixCls}-title`}>{title(mergedData.value)}</Panel>}
 | 
						|
          <div class={`${prefixCls}-container`}>{groupTableNode()}</div>
 | 
						|
          {footer && <Panel class={`${prefixCls}-footer`}>{footer(mergedData.value)}</Panel>}
 | 
						|
        </div>
 | 
						|
      );
 | 
						|
 | 
						|
      if (horizonScroll.value) {
 | 
						|
        return (
 | 
						|
          <VCResizeObserver
 | 
						|
            onResize={onFullTableResize}
 | 
						|
            v-slots={{ default: fullTable }}
 | 
						|
          ></VCResizeObserver>
 | 
						|
        );
 | 
						|
      }
 | 
						|
      return fullTable();
 | 
						|
    };
 | 
						|
  },
 | 
						|
});
 |