Merge branches 'next' and 'next' of https://github.com/vueComponent/ant-design-vue into next
						commit
						948727a2ef
					
				| 
						 | 
				
			
			@ -0,0 +1,55 @@
 | 
			
		|||
import { VNodeTypes, HTMLAttributes, FunctionalComponent } from 'vue';
 | 
			
		||||
 | 
			
		||||
function notEmpty(val: any) {
 | 
			
		||||
  return val !== undefined && val !== null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface CellProps extends HTMLAttributes {
 | 
			
		||||
  itemPrefixCls: string;
 | 
			
		||||
  span: number;
 | 
			
		||||
  component: string;
 | 
			
		||||
  bordered?: boolean;
 | 
			
		||||
  label?: VNodeTypes;
 | 
			
		||||
  content?: VNodeTypes;
 | 
			
		||||
  colon?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Cell: FunctionalComponent<CellProps> = props => {
 | 
			
		||||
  const { itemPrefixCls, component, span, bordered, label, content, colon } = props;
 | 
			
		||||
  const Component = component as any;
 | 
			
		||||
  if (bordered) {
 | 
			
		||||
    return (
 | 
			
		||||
      <Component
 | 
			
		||||
        class={[
 | 
			
		||||
          {
 | 
			
		||||
            [`${itemPrefixCls}-item-label`]: notEmpty(label),
 | 
			
		||||
            [`${itemPrefixCls}-item-content`]: notEmpty(content),
 | 
			
		||||
          },
 | 
			
		||||
        ]}
 | 
			
		||||
        colSpan={span}
 | 
			
		||||
      >
 | 
			
		||||
        {notEmpty(label) ? label : content}
 | 
			
		||||
      </Component>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Component class={[`${itemPrefixCls}-item`]} colSpan={span}>
 | 
			
		||||
      {label && (
 | 
			
		||||
        <span
 | 
			
		||||
          class={[
 | 
			
		||||
            `${itemPrefixCls}-item-label`,
 | 
			
		||||
            {
 | 
			
		||||
              [`${itemPrefixCls}-item-no-colon`]: !colon,
 | 
			
		||||
            },
 | 
			
		||||
          ]}
 | 
			
		||||
        >
 | 
			
		||||
          {label}
 | 
			
		||||
        </span>
 | 
			
		||||
      )}
 | 
			
		||||
      {content && <span class={`${itemPrefixCls}-item-content`}>{content}</span>}
 | 
			
		||||
    </Component>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default Cell;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,82 +0,0 @@
 | 
			
		|||
import { SetupContext, VNode } from 'vue';
 | 
			
		||||
import { getOptionProps } from '../_util/props-util';
 | 
			
		||||
 | 
			
		||||
interface ColProps {
 | 
			
		||||
  child: VNode;
 | 
			
		||||
  bordered: boolean;
 | 
			
		||||
  colon: boolean;
 | 
			
		||||
  type?: 'label' | 'content';
 | 
			
		||||
  layout?: 'horizontal' | 'vertical';
 | 
			
		||||
  colKey?: string;
 | 
			
		||||
}
 | 
			
		||||
const Col = (_props: ColProps, { attrs }: SetupContext) => {
 | 
			
		||||
  const {
 | 
			
		||||
    child = {} as VNode,
 | 
			
		||||
    bordered,
 | 
			
		||||
    colon,
 | 
			
		||||
    type,
 | 
			
		||||
    layout,
 | 
			
		||||
    colKey: key,
 | 
			
		||||
  } = (attrs as unknown) as ColProps;
 | 
			
		||||
  const { prefixCls, span = 1 } = getOptionProps(child);
 | 
			
		||||
  const { children = {} as any, props = {} } = child;
 | 
			
		||||
  const label = props.label || (children.label && children.label());
 | 
			
		||||
  const defaultSlot = children.default && children.default();
 | 
			
		||||
 | 
			
		||||
  const labelProps: any = {
 | 
			
		||||
    class: [
 | 
			
		||||
      `${prefixCls}-item-label`,
 | 
			
		||||
      {
 | 
			
		||||
        [`${prefixCls}-item-colon`]: colon,
 | 
			
		||||
        [`${prefixCls}-item-no-label`]: !label,
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    key: `${key}-label`,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  if (layout === 'vertical') {
 | 
			
		||||
    labelProps.colspan = span * 2 - 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (bordered) {
 | 
			
		||||
    if (type === 'label') {
 | 
			
		||||
      return <th {...labelProps}>{label}</th>;
 | 
			
		||||
    }
 | 
			
		||||
    return (
 | 
			
		||||
      <td class={`${prefixCls}-item-content`} key={`${key}-content`} colspan={span * 2 - 1}>
 | 
			
		||||
        {defaultSlot}
 | 
			
		||||
      </td>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  if (layout === 'vertical') {
 | 
			
		||||
    if (type === 'content') {
 | 
			
		||||
      return (
 | 
			
		||||
        <td colspan={span} class={`${prefixCls}-item`}>
 | 
			
		||||
          <span class={`${prefixCls}-item-content`} key={`${key}-content`}>
 | 
			
		||||
            {defaultSlot}
 | 
			
		||||
          </span>
 | 
			
		||||
        </td>
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return (
 | 
			
		||||
      <td colspan={span} class={`${prefixCls}-item`}>
 | 
			
		||||
        <span
 | 
			
		||||
          class={[`${prefixCls}-item-label`, { [`${prefixCls}-item-colon`]: colon }]}
 | 
			
		||||
          key={`${key}-label`}
 | 
			
		||||
        >
 | 
			
		||||
          {label}
 | 
			
		||||
        </span>
 | 
			
		||||
      </td>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  return (
 | 
			
		||||
    <td colspan={span} class={`${prefixCls}-item`}>
 | 
			
		||||
      <span {...labelProps}>{label}</span>
 | 
			
		||||
      <span class={`${prefixCls}-item-content`} key={`${key}-content`}>
 | 
			
		||||
        {defaultSlot}
 | 
			
		||||
      </span>
 | 
			
		||||
    </td>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default Col;
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,109 @@
 | 
			
		|||
import Cell from './Cell';
 | 
			
		||||
import { getOptionProps, getSlot, getClass, getStyle, getComponent } from '../_util/props-util';
 | 
			
		||||
import { FunctionalComponent } from 'vue';
 | 
			
		||||
 | 
			
		||||
interface CellConfig {
 | 
			
		||||
  component: string | [string, string];
 | 
			
		||||
  type: string;
 | 
			
		||||
  showLabel?: boolean;
 | 
			
		||||
  showContent?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface RowProps {
 | 
			
		||||
  prefixCls: string;
 | 
			
		||||
  vertical: boolean;
 | 
			
		||||
  row: any[];
 | 
			
		||||
  bordered: boolean;
 | 
			
		||||
  colon: boolean;
 | 
			
		||||
  index: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Row: FunctionalComponent<RowProps> = props => {
 | 
			
		||||
  const renderCells = (
 | 
			
		||||
    items,
 | 
			
		||||
    { colon, prefixCls, bordered },
 | 
			
		||||
    { component, type, showLabel, showContent }: CellConfig,
 | 
			
		||||
  ) => {
 | 
			
		||||
    return items.map((item, index) => {
 | 
			
		||||
      const { prefixCls: itemPrefixCls = prefixCls, span = 1 } = getOptionProps(item);
 | 
			
		||||
      const label = getComponent(item, 'label');
 | 
			
		||||
 | 
			
		||||
      const children = getSlot(item);
 | 
			
		||||
      const className = getClass(item);
 | 
			
		||||
      const style = getStyle(item);
 | 
			
		||||
      const { key } = item;
 | 
			
		||||
 | 
			
		||||
      if (typeof component === 'string') {
 | 
			
		||||
        return (
 | 
			
		||||
          <Cell
 | 
			
		||||
            key={`${type}-${key || index}`}
 | 
			
		||||
            class={className}
 | 
			
		||||
            style={style}
 | 
			
		||||
            span={span}
 | 
			
		||||
            colon={colon}
 | 
			
		||||
            component={component}
 | 
			
		||||
            itemPrefixCls={itemPrefixCls}
 | 
			
		||||
            bordered={bordered}
 | 
			
		||||
            label={showLabel ? label : null}
 | 
			
		||||
            content={showContent ? children : null}
 | 
			
		||||
          />
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return [
 | 
			
		||||
        <Cell
 | 
			
		||||
          key={`label-${key || index}`}
 | 
			
		||||
          class={className}
 | 
			
		||||
          style={style}
 | 
			
		||||
          span={1}
 | 
			
		||||
          colon={colon}
 | 
			
		||||
          component={component[0]}
 | 
			
		||||
          itemPrefixCls={itemPrefixCls}
 | 
			
		||||
          bordered={bordered}
 | 
			
		||||
          label={label}
 | 
			
		||||
        />,
 | 
			
		||||
        <Cell
 | 
			
		||||
          key={`content-${key || index}`}
 | 
			
		||||
          class={className}
 | 
			
		||||
          style={style}
 | 
			
		||||
          span={span * 2 - 1}
 | 
			
		||||
          component={component[1]}
 | 
			
		||||
          itemPrefixCls={itemPrefixCls}
 | 
			
		||||
          bordered={bordered}
 | 
			
		||||
          content={children}
 | 
			
		||||
        />,
 | 
			
		||||
      ];
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const { prefixCls, vertical, row, index, bordered } = props;
 | 
			
		||||
  if (vertical) {
 | 
			
		||||
    return (
 | 
			
		||||
      <>
 | 
			
		||||
        <tr key={`label-${index}`} class={`${prefixCls}-row`}>
 | 
			
		||||
          {renderCells(row, props, { component: 'th', type: 'label', showLabel: true })}
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr key={`content-${index}`} class={`${prefixCls}-row`}>
 | 
			
		||||
          {renderCells(row, props, {
 | 
			
		||||
            component: 'td',
 | 
			
		||||
            type: 'content',
 | 
			
		||||
            showContent: true,
 | 
			
		||||
          })}
 | 
			
		||||
        </tr>
 | 
			
		||||
      </>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <tr key={index} class={`${prefixCls}-row`}>
 | 
			
		||||
      {renderCells(row, props, {
 | 
			
		||||
        component: bordered ? ['th', 'td'] : 'td',
 | 
			
		||||
        type: 'item',
 | 
			
		||||
        showLabel: true,
 | 
			
		||||
        showContent: true,
 | 
			
		||||
      })}
 | 
			
		||||
    </tr>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default Row;
 | 
			
		||||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ exports[`Descriptions Descriptions support colon 1`] = `
 | 
			
		|||
    <table>
 | 
			
		||||
      <tbody>
 | 
			
		||||
        <tr class="ant-descriptions-row">
 | 
			
		||||
          <td colspan="3" class="ant-descriptions-item"><span class="ant-descriptions-item-label">Product</span><span class="ant-descriptions-item-content">Cloud Database</span></td>
 | 
			
		||||
          <td class="ant-descriptions-item" colspan="3"><span class="ant-descriptions-item-label ant-descriptions-item-no-colon">Product</span><span class="ant-descriptions-item-content">Cloud Database</span></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,9 @@ exports[`Descriptions Descriptions support style 1`] = `
 | 
			
		|||
    <table>
 | 
			
		||||
      <tbody>
 | 
			
		||||
        <tr class="ant-descriptions-row">
 | 
			
		||||
          <td colspan="3" class="ant-descriptions-item"><span class="ant-descriptions-item-label ant-descriptions-item-colon ant-descriptions-item-no-label"><!----></span><span class="ant-descriptions-item-content">Cloud Database</span></td>
 | 
			
		||||
          <td class="ant-descriptions-item" colspan="3">
 | 
			
		||||
            <!----><span class="ant-descriptions-item-content">Cloud Database</span>
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
| 
						 | 
				
			
			@ -37,7 +39,7 @@ exports[`Descriptions Descriptions.Item support className 1`] = `
 | 
			
		|||
    <table>
 | 
			
		||||
      <tbody>
 | 
			
		||||
        <tr class="ant-descriptions-row">
 | 
			
		||||
          <td colspan="3" class="ant-descriptions-item"><span class="ant-descriptions-item-label ant-descriptions-item-colon">Product</span><span class="ant-descriptions-item-content">Cloud Database</span></td>
 | 
			
		||||
          <td class="ant-descriptions-item my-class" colspan="3"><span class="ant-descriptions-item-label">Product</span><span class="ant-descriptions-item-content">Cloud Database</span></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
| 
						 | 
				
			
			@ -52,12 +54,12 @@ exports[`Descriptions column is number 1`] = `
 | 
			
		|||
    <table>
 | 
			
		||||
      <tbody>
 | 
			
		||||
        <tr class="ant-descriptions-row">
 | 
			
		||||
          <td colspan="1" class="ant-descriptions-item"><span class="ant-descriptions-item-label ant-descriptions-item-colon">Product</span><span class="ant-descriptions-item-content">Cloud Database</span></td>
 | 
			
		||||
          <td colspan="1" class="ant-descriptions-item"><span class="ant-descriptions-item-label ant-descriptions-item-colon">Billing</span><span class="ant-descriptions-item-content">Prepaid</span></td>
 | 
			
		||||
          <td colspan="1" class="ant-descriptions-item"><span class="ant-descriptions-item-label ant-descriptions-item-colon">time</span><span class="ant-descriptions-item-content">18:00:00</span></td>
 | 
			
		||||
          <td class="ant-descriptions-item" colspan="1"><span class="ant-descriptions-item-label">Product</span><span class="ant-descriptions-item-content">Cloud Database</span></td>
 | 
			
		||||
          <td class="ant-descriptions-item" colspan="1"><span class="ant-descriptions-item-label">Billing</span><span class="ant-descriptions-item-content">Prepaid</span></td>
 | 
			
		||||
          <td class="ant-descriptions-item" colspan="1"><span class="ant-descriptions-item-label">time</span><span class="ant-descriptions-item-content">18:00:00</span></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr class="ant-descriptions-row">
 | 
			
		||||
          <td colspan="3" class="ant-descriptions-item"><span class="ant-descriptions-item-label ant-descriptions-item-colon">Amount</span><span class="ant-descriptions-item-content">$80.00</span></td>
 | 
			
		||||
          <td class="ant-descriptions-item" colspan="3"><span class="ant-descriptions-item-label">Amount</span><span class="ant-descriptions-item-content">$80.00</span></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
| 
						 | 
				
			
			@ -72,20 +74,36 @@ exports[`Descriptions vertical layout 1`] = `
 | 
			
		|||
    <table>
 | 
			
		||||
      <tbody>
 | 
			
		||||
        <tr class="ant-descriptions-row">
 | 
			
		||||
          <td colspan="1" class="ant-descriptions-item"><span class="ant-descriptions-item-label ant-descriptions-item-colon">Product</span></td>
 | 
			
		||||
          <td colspan="1" class="ant-descriptions-item"><span class="ant-descriptions-item-label ant-descriptions-item-colon">Billing</span></td>
 | 
			
		||||
          <td colspan="1" class="ant-descriptions-item"><span class="ant-descriptions-item-label ant-descriptions-item-colon">time</span></td>
 | 
			
		||||
          <th class="ant-descriptions-item" colspan="1"><span class="ant-descriptions-item-label">Product</span>
 | 
			
		||||
            <!---->
 | 
			
		||||
          </th>
 | 
			
		||||
          <th class="ant-descriptions-item" colspan="1"><span class="ant-descriptions-item-label">Billing</span>
 | 
			
		||||
            <!---->
 | 
			
		||||
          </th>
 | 
			
		||||
          <th class="ant-descriptions-item" colspan="1"><span class="ant-descriptions-item-label">time</span>
 | 
			
		||||
            <!---->
 | 
			
		||||
          </th>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr class="ant-descriptions-row">
 | 
			
		||||
          <td colspan="1" class="ant-descriptions-item"><span class="ant-descriptions-item-content">Cloud Database</span></td>
 | 
			
		||||
          <td colspan="1" class="ant-descriptions-item"><span class="ant-descriptions-item-content">Prepaid</span></td>
 | 
			
		||||
          <td colspan="1" class="ant-descriptions-item"><span class="ant-descriptions-item-content">18:00:00</span></td>
 | 
			
		||||
          <td class="ant-descriptions-item" colspan="1">
 | 
			
		||||
            <!----><span class="ant-descriptions-item-content">Cloud Database</span>
 | 
			
		||||
          </td>
 | 
			
		||||
          <td class="ant-descriptions-item" colspan="1">
 | 
			
		||||
            <!----><span class="ant-descriptions-item-content">Prepaid</span>
 | 
			
		||||
          </td>
 | 
			
		||||
          <td class="ant-descriptions-item" colspan="1">
 | 
			
		||||
            <!----><span class="ant-descriptions-item-content">18:00:00</span>
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr class="ant-descriptions-row">
 | 
			
		||||
          <td colspan="3" class="ant-descriptions-item"><span class="ant-descriptions-item-label ant-descriptions-item-colon">Amount</span></td>
 | 
			
		||||
          <th class="ant-descriptions-item" colspan="3"><span class="ant-descriptions-item-label">Amount</span>
 | 
			
		||||
            <!---->
 | 
			
		||||
          </th>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr class="ant-descriptions-row">
 | 
			
		||||
          <td colspan="3" class="ant-descriptions-item"><span class="ant-descriptions-item-content">$80.00</span></td>
 | 
			
		||||
          <td class="ant-descriptions-item" colspan="3">
 | 
			
		||||
            <!----><span class="ant-descriptions-item-content">$80.00</span>
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
| 
						 | 
				
			
			@ -100,12 +118,12 @@ exports[`Descriptions when item is rendered conditionally 1`] = `
 | 
			
		|||
    <table>
 | 
			
		||||
      <tbody>
 | 
			
		||||
        <tr class="ant-descriptions-row">
 | 
			
		||||
          <td colspan="1" class="ant-descriptions-item"><span class="ant-descriptions-item-label ant-descriptions-item-colon">Product</span><span class="ant-descriptions-item-content">Cloud Database</span></td>
 | 
			
		||||
          <td colspan="1" class="ant-descriptions-item"><span class="ant-descriptions-item-label ant-descriptions-item-colon">Billing</span><span class="ant-descriptions-item-content">Prepaid</span></td>
 | 
			
		||||
          <td colspan="1" class="ant-descriptions-item"><span class="ant-descriptions-item-label ant-descriptions-item-colon">time</span><span class="ant-descriptions-item-content">18:00:00</span></td>
 | 
			
		||||
          <td class="ant-descriptions-item" colspan="1"><span class="ant-descriptions-item-label">Product</span><span class="ant-descriptions-item-content">Cloud Database</span></td>
 | 
			
		||||
          <td class="ant-descriptions-item" colspan="1"><span class="ant-descriptions-item-label">Billing</span><span class="ant-descriptions-item-content">Prepaid</span></td>
 | 
			
		||||
          <td class="ant-descriptions-item" colspan="1"><span class="ant-descriptions-item-label">time</span><span class="ant-descriptions-item-content">18:00:00</span></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr class="ant-descriptions-row">
 | 
			
		||||
          <td colspan="3" class="ant-descriptions-item"><span class="ant-descriptions-item-label ant-descriptions-item-colon">Amount</span><span class="ant-descriptions-item-content">$80.00</span></td>
 | 
			
		||||
          <td class="ant-descriptions-item" colspan="3"><span class="ant-descriptions-item-label">Amount</span><span class="ant-descriptions-item-content">$80.00</span></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,7 +33,9 @@ describe('Descriptions', () => {
 | 
			
		|||
      { sync: false, attachTo: 'body' },
 | 
			
		||||
    );
 | 
			
		||||
    await asyncExpect(() => {
 | 
			
		||||
      expect(wrapper.vm.$refs.descriptions.getColumn()).toBe(8);
 | 
			
		||||
      expect(
 | 
			
		||||
        wrapper.findAll('td').reduce((total, td) => total + parseInt(td.attributes().colspan), 0),
 | 
			
		||||
      ).toBe(8);
 | 
			
		||||
    }, 100);
 | 
			
		||||
    wrapper.unmount();
 | 
			
		||||
  });
 | 
			
		||||
| 
						 | 
				
			
			@ -74,7 +76,7 @@ describe('Descriptions', () => {
 | 
			
		|||
      },
 | 
			
		||||
    });
 | 
			
		||||
    expect(errorSpy).toHaveBeenCalledWith(
 | 
			
		||||
      'Warning: [antdv: Descriptions] Sum of column `span` in a line exceeds `column` of Descriptions.',
 | 
			
		||||
      'Warning: [antdv: Descriptions] Sum of column `span` in a line not match `column` of Descriptions.',
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -120,7 +122,7 @@ describe('Descriptions', () => {
 | 
			
		|||
      render() {
 | 
			
		||||
        return (
 | 
			
		||||
          <Descriptions>
 | 
			
		||||
            <Descriptions.Item label="Product" className="my-class">
 | 
			
		||||
            <Descriptions.Item label="Product" class="my-class">
 | 
			
		||||
              Cloud Database
 | 
			
		||||
            </Descriptions.Item>
 | 
			
		||||
          </Descriptions>
 | 
			
		||||
| 
						 | 
				
			
			@ -176,7 +178,7 @@ describe('Descriptions', () => {
 | 
			
		|||
    );
 | 
			
		||||
    await asyncExpect(() => {
 | 
			
		||||
      expect(wrapper.findAll('tr')).toHaveLength(5);
 | 
			
		||||
      expect(wrapper.findAll('.ant-descriptions-item-no-label')).toHaveLength(1);
 | 
			
		||||
      expect(wrapper.findAll('.ant-descriptions-item-label')).toHaveLength(4);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    wrapper.unmount();
 | 
			
		||||
| 
						 | 
				
			
			@ -198,8 +200,86 @@ describe('Descriptions', () => {
 | 
			
		|||
      },
 | 
			
		||||
      { sync: false, attachTo: 'body' },
 | 
			
		||||
    );
 | 
			
		||||
    await asyncExpect(() => {});
 | 
			
		||||
    expect(wrapper.findAll('tr')).toHaveLength(2);
 | 
			
		||||
    await asyncExpect(() => {
 | 
			
		||||
      expect(wrapper.findAll('tr')).toHaveLength(2);
 | 
			
		||||
    });
 | 
			
		||||
    wrapper.unmount();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('columns 5 with customize', () => {
 | 
			
		||||
    const wrapper = mount({
 | 
			
		||||
      render() {
 | 
			
		||||
        return (
 | 
			
		||||
          <Descriptions layout="vertical" column={4}>
 | 
			
		||||
            {/* 1 1 1 1 */}
 | 
			
		||||
            <Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
 | 
			
		||||
            <Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
 | 
			
		||||
            <Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
 | 
			
		||||
            <Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
 | 
			
		||||
            {/* 2 2 */}
 | 
			
		||||
            <Descriptions.Item label="bamboo" span={2}>
 | 
			
		||||
              bamboo
 | 
			
		||||
            </Descriptions.Item>
 | 
			
		||||
            <Descriptions.Item label="bamboo" span={2}>
 | 
			
		||||
              bamboo
 | 
			
		||||
            </Descriptions.Item>
 | 
			
		||||
            {/* 3 1 */}
 | 
			
		||||
            <Descriptions.Item label="bamboo" span={3}>
 | 
			
		||||
              bamboo
 | 
			
		||||
            </Descriptions.Item>
 | 
			
		||||
            <Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
 | 
			
		||||
          </Descriptions>
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    function matchSpan(rowIndex, spans) {
 | 
			
		||||
      const tr = wrapper.findAll('tr')[rowIndex];
 | 
			
		||||
      const tds = tr.findAll('th');
 | 
			
		||||
      expect(tds.length).toEqual(spans.length);
 | 
			
		||||
      tds.forEach((td, index) => {
 | 
			
		||||
        expect(parseInt(td.attributes().colspan)).toEqual(spans[index]);
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    matchSpan(0, [1, 1, 1, 1]);
 | 
			
		||||
    matchSpan(2, [2, 2]);
 | 
			
		||||
    matchSpan(4, [3, 1]);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('number value should render correct', () => {
 | 
			
		||||
    const wrapper = mount({
 | 
			
		||||
      render() {
 | 
			
		||||
        return (
 | 
			
		||||
          <Descriptions bordered>
 | 
			
		||||
            <Descriptions.Item label={0}>{0}</Descriptions.Item>
 | 
			
		||||
          </Descriptions>
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    expect(wrapper.find('th').classes()).toContain('ant-descriptions-item-label');
 | 
			
		||||
    expect(wrapper.find('td').classes()).toContain('ant-descriptions-item-content');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Descriptions support extra', async () => {
 | 
			
		||||
    const wrapper = mount({
 | 
			
		||||
      render() {
 | 
			
		||||
        return (
 | 
			
		||||
          <Descriptions extra="Edit">
 | 
			
		||||
            <Descriptions.Item label="UserName">Zhou Maomao</Descriptions.Item>
 | 
			
		||||
          </Descriptions>
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    await asyncExpect(() => {
 | 
			
		||||
      expect(wrapper.find('.ant-descriptions-extra').exists()).toBe(true);
 | 
			
		||||
      wrapper.setProps({ extra: undefined });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    await asyncExpect(() => {
 | 
			
		||||
      expect(wrapper.find('.ant-descriptions-extra').exists()).toBe(false);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,27 @@
 | 
			
		|||
import { inject, cloneVNode, App, defineComponent, PropType, VNode, Plugin } from 'vue';
 | 
			
		||||
import {
 | 
			
		||||
  inject,
 | 
			
		||||
  ref,
 | 
			
		||||
  App,
 | 
			
		||||
  defineComponent,
 | 
			
		||||
  PropType,
 | 
			
		||||
  VNode,
 | 
			
		||||
  HTMLAttributes,
 | 
			
		||||
  ExtractPropTypes,
 | 
			
		||||
  onMounted,
 | 
			
		||||
  onBeforeUnmount,
 | 
			
		||||
} from 'vue';
 | 
			
		||||
import warning from '../_util/warning';
 | 
			
		||||
import ResponsiveObserve, { Breakpoint, responsiveArray } from '../_util/responsiveObserve';
 | 
			
		||||
import ResponsiveObserve, {
 | 
			
		||||
  Breakpoint,
 | 
			
		||||
  responsiveArray,
 | 
			
		||||
  ScreenMap,
 | 
			
		||||
} from '../_util/responsiveObserve';
 | 
			
		||||
import { defaultConfigProvider } from '../config-provider';
 | 
			
		||||
import Col from './Col';
 | 
			
		||||
import Row from './Row';
 | 
			
		||||
import PropTypes from '../_util/vue-types';
 | 
			
		||||
import { getOptionProps, getComponent, isValidElement, getSlot } from '../_util/props-util';
 | 
			
		||||
import BaseMixin from '../_util/BaseMixin';
 | 
			
		||||
import { tuple, VueNode } from '../_util/type';
 | 
			
		||||
import { tuple } from '../_util/type';
 | 
			
		||||
import { cloneElement } from '../_util/vnode';
 | 
			
		||||
import { filterEmpty } from '../_util/props-util';
 | 
			
		||||
 | 
			
		||||
export const DescriptionsItemProps = {
 | 
			
		||||
  prefixCls: PropTypes.string,
 | 
			
		||||
| 
						 | 
				
			
			@ -14,16 +29,6 @@ export const DescriptionsItemProps = {
 | 
			
		|||
  span: PropTypes.number,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function toArray(value: any) {
 | 
			
		||||
  let ret = value;
 | 
			
		||||
  if (value === undefined) {
 | 
			
		||||
    ret = [];
 | 
			
		||||
  } else if (!Array.isArray(value)) {
 | 
			
		||||
    ret = [value];
 | 
			
		||||
  }
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const DescriptionsItem = {
 | 
			
		||||
  name: 'ADescriptionsItem',
 | 
			
		||||
  props: {
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +41,7 @@ export const DescriptionsItem = {
 | 
			
		|||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const defaultColumnMap = {
 | 
			
		||||
const DEFAULT_COLUMN_MAP: Record<Breakpoint, number> = {
 | 
			
		||||
  xxl: 3,
 | 
			
		||||
  xl: 3,
 | 
			
		||||
  lg: 3,
 | 
			
		||||
| 
						 | 
				
			
			@ -45,229 +50,172 @@ const defaultColumnMap = {
 | 
			
		|||
  xs: 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const DescriptionsProps = {
 | 
			
		||||
function getColumn(column: DescriptionsProps['column'], screens: ScreenMap): number {
 | 
			
		||||
  if (typeof column === 'number') {
 | 
			
		||||
    return column;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (typeof column === 'object') {
 | 
			
		||||
    for (let i = 0; i < responsiveArray.length; i++) {
 | 
			
		||||
      const breakpoint: Breakpoint = responsiveArray[i];
 | 
			
		||||
      if (screens[breakpoint] && column[breakpoint] !== undefined) {
 | 
			
		||||
        return column[breakpoint] || DEFAULT_COLUMN_MAP[breakpoint];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return 3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getFilledItem(node: VNode, span: number | undefined, rowRestCol: number): VNode {
 | 
			
		||||
  let clone = node;
 | 
			
		||||
 | 
			
		||||
  if (span === undefined || span > rowRestCol) {
 | 
			
		||||
    clone = cloneElement(node, {
 | 
			
		||||
      span: rowRestCol,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    warning(
 | 
			
		||||
      span === undefined,
 | 
			
		||||
      'Descriptions',
 | 
			
		||||
      'Sum of column `span` in a line not match `column` of Descriptions.',
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return clone;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getRows(children: VNode[], column: number) {
 | 
			
		||||
  const childNodes = filterEmpty(children);
 | 
			
		||||
  const rows: VNode[][] = [];
 | 
			
		||||
 | 
			
		||||
  let tmpRow: VNode[] = [];
 | 
			
		||||
  let rowRestCol = column;
 | 
			
		||||
 | 
			
		||||
  childNodes.forEach((node, index) => {
 | 
			
		||||
    const span: number | undefined = node.props?.span;
 | 
			
		||||
    const mergedSpan = span || 1;
 | 
			
		||||
 | 
			
		||||
    // Additional handle last one
 | 
			
		||||
    if (index === childNodes.length - 1) {
 | 
			
		||||
      tmpRow.push(getFilledItem(node, span, rowRestCol));
 | 
			
		||||
      rows.push(tmpRow);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (mergedSpan < rowRestCol) {
 | 
			
		||||
      rowRestCol -= mergedSpan;
 | 
			
		||||
      tmpRow.push(node);
 | 
			
		||||
    } else {
 | 
			
		||||
      tmpRow.push(getFilledItem(node, mergedSpan, rowRestCol));
 | 
			
		||||
      rows.push(tmpRow);
 | 
			
		||||
      rowRestCol = column;
 | 
			
		||||
      tmpRow = [];
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return rows;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const descriptionsProps = {
 | 
			
		||||
  prefixCls: PropTypes.string,
 | 
			
		||||
  bordered: PropTypes.looseBool,
 | 
			
		||||
  size: PropTypes.oneOf(tuple('default', 'middle', 'small')).def('default'),
 | 
			
		||||
  title: PropTypes.VNodeChild,
 | 
			
		||||
  extra: PropTypes.VNodeChild,
 | 
			
		||||
  column: {
 | 
			
		||||
    type: [Number, Object] as PropType<number | Partial<Record<Breakpoint, number>>>,
 | 
			
		||||
    default: () => defaultColumnMap,
 | 
			
		||||
    default: () => DEFAULT_COLUMN_MAP,
 | 
			
		||||
  },
 | 
			
		||||
  layout: PropTypes.oneOf(tuple('horizontal', 'vertical')),
 | 
			
		||||
  colon: PropTypes.looseBool,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Convert children into `column` groups.
 | 
			
		||||
 * @param children: DescriptionsItem
 | 
			
		||||
 * @param column: number
 | 
			
		||||
 */
 | 
			
		||||
const generateChildrenRows = (children: VueNode, column: number) => {
 | 
			
		||||
  const rows = [];
 | 
			
		||||
  let columns = null;
 | 
			
		||||
  let leftSpans: number;
 | 
			
		||||
export type DescriptionsProps = HTMLAttributes &
 | 
			
		||||
  Partial<ExtractPropTypes<typeof descriptionsProps>>;
 | 
			
		||||
 | 
			
		||||
  const itemNodes = toArray(children);
 | 
			
		||||
  itemNodes.forEach((node: VNode, index: number) => {
 | 
			
		||||
    const itemProps = getOptionProps(node);
 | 
			
		||||
    let itemNode = node;
 | 
			
		||||
 | 
			
		||||
    if (!columns) {
 | 
			
		||||
      leftSpans = column;
 | 
			
		||||
      columns = [];
 | 
			
		||||
      rows.push(columns);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Always set last span to align the end of Descriptions
 | 
			
		||||
    const lastItem = index === itemNodes.length - 1;
 | 
			
		||||
    let lastSpanSame = true;
 | 
			
		||||
    if (lastItem) {
 | 
			
		||||
      lastSpanSame = !itemProps.span || itemProps.span === leftSpans;
 | 
			
		||||
      itemNode = cloneVNode(itemNode, {
 | 
			
		||||
        span: leftSpans,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Calculate left fill span
 | 
			
		||||
    const { span = 1 } = itemProps;
 | 
			
		||||
    columns.push(itemNode);
 | 
			
		||||
    leftSpans -= span;
 | 
			
		||||
 | 
			
		||||
    if (leftSpans <= 0) {
 | 
			
		||||
      columns = null;
 | 
			
		||||
 | 
			
		||||
      warning(
 | 
			
		||||
        leftSpans === 0 && lastSpanSame,
 | 
			
		||||
        'Descriptions',
 | 
			
		||||
        'Sum of column `span` in a line exceeds `column` of Descriptions.',
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return rows;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const Descriptions = defineComponent({
 | 
			
		||||
const Descriptions = defineComponent<DescriptionsProps>({
 | 
			
		||||
  name: 'ADescriptions',
 | 
			
		||||
  Item: DescriptionsItem,
 | 
			
		||||
  mixins: [BaseMixin],
 | 
			
		||||
  props: DescriptionsProps,
 | 
			
		||||
  setup() {
 | 
			
		||||
    return {
 | 
			
		||||
      configProvider: inject('configProvider', defaultConfigProvider),
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      screens: {},
 | 
			
		||||
      token: undefined,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getColumn() {
 | 
			
		||||
      const { column } = this.$props;
 | 
			
		||||
      if (typeof column === 'object') {
 | 
			
		||||
        for (let i = 0; i < responsiveArray.length; i++) {
 | 
			
		||||
          const breakpoint = responsiveArray[i];
 | 
			
		||||
          if (this.screens[breakpoint] && column[breakpoint] !== undefined) {
 | 
			
		||||
            return column[breakpoint] || defaultColumnMap[breakpoint];
 | 
			
		||||
          }
 | 
			
		||||
  setup(props, { slots }) {
 | 
			
		||||
    const { getPrefixCls } = inject('configProvider', defaultConfigProvider);
 | 
			
		||||
 | 
			
		||||
    let token: number;
 | 
			
		||||
 | 
			
		||||
    const screens = ref<ScreenMap>({});
 | 
			
		||||
 | 
			
		||||
    onMounted(() => {
 | 
			
		||||
      token = ResponsiveObserve.subscribe(screen => {
 | 
			
		||||
        if (typeof props.column !== 'object') {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      // If the configuration is not an object, it is a number, return number
 | 
			
		||||
      if (typeof column === 'number') {
 | 
			
		||||
        return column;
 | 
			
		||||
      }
 | 
			
		||||
      // If it is an object, but no response is found, this happens only in the test.
 | 
			
		||||
      // Maybe there are some strange environments
 | 
			
		||||
      return 3;
 | 
			
		||||
    },
 | 
			
		||||
    renderRow(
 | 
			
		||||
      children: VNode[],
 | 
			
		||||
      index: number,
 | 
			
		||||
      { prefixCls }: { prefixCls: string },
 | 
			
		||||
      bordered: boolean,
 | 
			
		||||
      layout: 'horizontal' | 'vertical',
 | 
			
		||||
      colon: boolean,
 | 
			
		||||
    ) {
 | 
			
		||||
      const renderCol = (colItem: VNode, type: 'label' | 'content', idx: number) => {
 | 
			
		||||
        return (
 | 
			
		||||
          <Col
 | 
			
		||||
            child={colItem}
 | 
			
		||||
            bordered={bordered}
 | 
			
		||||
            colon={colon}
 | 
			
		||||
            type={type}
 | 
			
		||||
            key={`${type}-${colItem.key || idx}`}
 | 
			
		||||
            colKey={`${type}-${colItem.key || idx}`}
 | 
			
		||||
            layout={layout}
 | 
			
		||||
          />
 | 
			
		||||
        );
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      const cloneChildren = [];
 | 
			
		||||
      const cloneContentChildren = [];
 | 
			
		||||
      toArray(children).forEach((childrenItem: VNode, idx: number) => {
 | 
			
		||||
        cloneChildren.push(renderCol(childrenItem, 'label', idx));
 | 
			
		||||
        if (layout === 'vertical') {
 | 
			
		||||
          cloneContentChildren.push(renderCol(childrenItem, 'content', idx));
 | 
			
		||||
        } else if (bordered) {
 | 
			
		||||
          cloneChildren.push(renderCol(childrenItem, 'content', idx));
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      if (layout === 'vertical') {
 | 
			
		||||
        return [
 | 
			
		||||
          <tr class={`${prefixCls}-row`} key={`label-${index}`}>
 | 
			
		||||
            {cloneChildren}
 | 
			
		||||
          </tr>,
 | 
			
		||||
          <tr class={`${prefixCls}-row`} key={`content-${index}`}>
 | 
			
		||||
            {cloneContentChildren}
 | 
			
		||||
          </tr>,
 | 
			
		||||
        ];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return (
 | 
			
		||||
        <tr class={`${prefixCls}-row`} key={index}>
 | 
			
		||||
          {cloneChildren}
 | 
			
		||||
        </tr>
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    const { column } = this.$props;
 | 
			
		||||
    this.token = ResponsiveObserve.subscribe(screens => {
 | 
			
		||||
      if (typeof column !== 'object') {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      this.setState({
 | 
			
		||||
        screens,
 | 
			
		||||
        screens.value = screen;
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  beforeUnmount() {
 | 
			
		||||
    ResponsiveObserve.unsubscribe(this.token);
 | 
			
		||||
  },
 | 
			
		||||
  render() {
 | 
			
		||||
    const {
 | 
			
		||||
      prefixCls: customizePrefixCls,
 | 
			
		||||
      size,
 | 
			
		||||
      bordered = false,
 | 
			
		||||
      layout = 'horizontal',
 | 
			
		||||
      colon = true,
 | 
			
		||||
    } = this.$props;
 | 
			
		||||
    const title = getComponent(this, 'title');
 | 
			
		||||
    const getPrefixCls = this.configProvider.getPrefixCls;
 | 
			
		||||
    const prefixCls = getPrefixCls('descriptions', customizePrefixCls);
 | 
			
		||||
 | 
			
		||||
    const column = this.getColumn();
 | 
			
		||||
    const children = getSlot(this);
 | 
			
		||||
    const cloneChildren = toArray(children)
 | 
			
		||||
      .map((child: VNode) => {
 | 
			
		||||
        if (isValidElement(child)) {
 | 
			
		||||
          return cloneVNode(child, {
 | 
			
		||||
    onBeforeUnmount(() => {
 | 
			
		||||
      ResponsiveObserve.unsubscribe(token);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return () => {
 | 
			
		||||
      const {
 | 
			
		||||
        prefixCls: customizePrefixCls,
 | 
			
		||||
        column,
 | 
			
		||||
        size,
 | 
			
		||||
        bordered = false,
 | 
			
		||||
        layout = 'horizontal',
 | 
			
		||||
        colon = true,
 | 
			
		||||
        title = slots.title?.(),
 | 
			
		||||
        extra = slots.extra?.(),
 | 
			
		||||
      } = props;
 | 
			
		||||
 | 
			
		||||
      const prefixCls = getPrefixCls('descriptions', customizePrefixCls);
 | 
			
		||||
      const mergeColumn = getColumn(column, screens.value);
 | 
			
		||||
      const children = slots.default?.();
 | 
			
		||||
      const rows = getRows(children, mergeColumn);
 | 
			
		||||
 | 
			
		||||
      return (
 | 
			
		||||
        <div
 | 
			
		||||
          class={[
 | 
			
		||||
            prefixCls,
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
      })
 | 
			
		||||
      .filter(node => node);
 | 
			
		||||
 | 
			
		||||
    const childrenArray = generateChildrenRows(cloneChildren, column);
 | 
			
		||||
    return (
 | 
			
		||||
      <div
 | 
			
		||||
        class={[
 | 
			
		||||
          prefixCls,
 | 
			
		||||
          {
 | 
			
		||||
            [`${prefixCls}-${size}`]: size !== 'default',
 | 
			
		||||
            [`${prefixCls}-bordered`]: !!bordered,
 | 
			
		||||
          },
 | 
			
		||||
        ]}
 | 
			
		||||
      >
 | 
			
		||||
        {title && <div class={`${prefixCls}-title`}>{title}</div>}
 | 
			
		||||
        <div class={`${prefixCls}-view`}>
 | 
			
		||||
          <table>
 | 
			
		||||
            <tbody>
 | 
			
		||||
              {childrenArray.map((child, index) =>
 | 
			
		||||
                this.renderRow(
 | 
			
		||||
                  child,
 | 
			
		||||
                  index,
 | 
			
		||||
                  {
 | 
			
		||||
                    prefixCls,
 | 
			
		||||
                  },
 | 
			
		||||
                  bordered,
 | 
			
		||||
                  layout,
 | 
			
		||||
                  colon,
 | 
			
		||||
                ),
 | 
			
		||||
              )}
 | 
			
		||||
            </tbody>
 | 
			
		||||
          </table>
 | 
			
		||||
            {
 | 
			
		||||
              [`${prefixCls}-${size}`]: size !== 'default',
 | 
			
		||||
              [`${prefixCls}-bordered`]: !!bordered,
 | 
			
		||||
            },
 | 
			
		||||
          ]}
 | 
			
		||||
        >
 | 
			
		||||
          {(title || extra) && (
 | 
			
		||||
            <div class={`${prefixCls}-header`}>
 | 
			
		||||
              <div class={`${prefixCls}-title`}>{title}</div>
 | 
			
		||||
              <div class={`${prefixCls}-extra`}>{extra}</div>
 | 
			
		||||
            </div>
 | 
			
		||||
          )}
 | 
			
		||||
          <div class={`${prefixCls}-view`}>
 | 
			
		||||
            <table>
 | 
			
		||||
              <tbody>
 | 
			
		||||
                {rows.map((row, index) => (
 | 
			
		||||
                  <Row
 | 
			
		||||
                    key={index}
 | 
			
		||||
                    index={index}
 | 
			
		||||
                    colon={colon}
 | 
			
		||||
                    prefixCls={prefixCls}
 | 
			
		||||
                    vertical={layout === 'vertical'}
 | 
			
		||||
                    bordered={bordered}
 | 
			
		||||
                    row={row}
 | 
			
		||||
                  />
 | 
			
		||||
                ))}
 | 
			
		||||
              </tbody>
 | 
			
		||||
            </table>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
      );
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Descriptions.props = descriptionsProps;
 | 
			
		||||
 | 
			
		||||
Descriptions.install = function(app: App) {
 | 
			
		||||
  app.component(Descriptions.name, Descriptions);
 | 
			
		||||
  app.component(Descriptions.Item.name, Descriptions.Item);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,17 +3,28 @@
 | 
			
		|||
 | 
			
		||||
@descriptions-prefix-cls: ~'@{ant-prefix}-descriptions';
 | 
			
		||||
 | 
			
		||||
@descriptions-default-padding: 16px 24px;
 | 
			
		||||
@descriptions-middle-padding: 12px 24px;
 | 
			
		||||
@descriptions-small-padding: 8px 16px;
 | 
			
		||||
 | 
			
		||||
.@{descriptions-prefix-cls} {
 | 
			
		||||
  &-header {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    margin-bottom: @descriptions-title-margin-bottom;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &-title {
 | 
			
		||||
    margin-bottom: 20px;
 | 
			
		||||
    flex: auto;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    color: @heading-color;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    font-size: @font-size-lg;
 | 
			
		||||
    line-height: @line-height-base;
 | 
			
		||||
    white-space: nowrap;
 | 
			
		||||
    text-overflow: ellipsis;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &-extra {
 | 
			
		||||
    margin-left: auto;
 | 
			
		||||
    color: @descriptions-extra-color;
 | 
			
		||||
    font-size: @font-size-base;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &-view {
 | 
			
		||||
| 
						 | 
				
			
			@ -29,7 +40,7 @@
 | 
			
		|||
  &-row {
 | 
			
		||||
    > th,
 | 
			
		||||
    > td {
 | 
			
		||||
      padding-bottom: 16px;
 | 
			
		||||
      padding-bottom: @descriptions-item-padding-bottom;
 | 
			
		||||
    }
 | 
			
		||||
    &:last-child {
 | 
			
		||||
      border-bottom: none;
 | 
			
		||||
| 
						 | 
				
			
			@ -41,18 +52,24 @@
 | 
			
		|||
    font-weight: normal;
 | 
			
		||||
    font-size: @font-size-base;
 | 
			
		||||
    line-height: @line-height-base;
 | 
			
		||||
    text-align: start;
 | 
			
		||||
 | 
			
		||||
    &::after {
 | 
			
		||||
      & when (@descriptions-item-trailing-colon=true) {
 | 
			
		||||
        content: ':';
 | 
			
		||||
      }
 | 
			
		||||
      & when not (@descriptions-item-trailing-colon=true) {
 | 
			
		||||
        content: ' ';
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      position: relative;
 | 
			
		||||
      top: -0.5px;
 | 
			
		||||
      margin: 0 8px 0 2px;
 | 
			
		||||
      content: ' ';
 | 
			
		||||
      margin: 0 @descriptions-item-label-colon-margin-right 0
 | 
			
		||||
        @descriptions-item-label-colon-margin-left;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &-item-colon {
 | 
			
		||||
    &::after {
 | 
			
		||||
      content: ':';
 | 
			
		||||
    &.@{descriptions-prefix-cls}-item-no-colon::after {
 | 
			
		||||
      content: ' ';
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -65,15 +82,23 @@
 | 
			
		|||
 | 
			
		||||
  &-item-content {
 | 
			
		||||
    display: table-cell;
 | 
			
		||||
    flex: 1;
 | 
			
		||||
    color: @text-color;
 | 
			
		||||
    font-size: @font-size-base;
 | 
			
		||||
    line-height: @line-height-base;
 | 
			
		||||
    overflow-wrap: break-word;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &-item {
 | 
			
		||||
    padding-bottom: 0;
 | 
			
		||||
    vertical-align: top;
 | 
			
		||||
    > span {
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
      display: inline-flex;
 | 
			
		||||
      align-items: baseline;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &-container {
 | 
			
		||||
      display: flex;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -90,7 +115,7 @@
 | 
			
		|||
    .@{descriptions-prefix-cls}-row {
 | 
			
		||||
      > th,
 | 
			
		||||
      > td {
 | 
			
		||||
        padding-bottom: 8px;
 | 
			
		||||
        padding-bottom: @padding-xs;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -192,6 +192,15 @@
 | 
			
		|||
 | 
			
		||||
// Descriptions
 | 
			
		||||
@descriptions-bg: #fafafa;
 | 
			
		||||
@descriptions-title-margin-bottom: 20px;
 | 
			
		||||
@descriptions-default-padding: @padding-md @padding-lg;
 | 
			
		||||
@descriptions-middle-padding: @padding-sm @padding-lg;
 | 
			
		||||
@descriptions-small-padding: @padding-xs @padding-md;
 | 
			
		||||
@descriptions-item-padding-bottom: @padding-md;
 | 
			
		||||
@descriptions-item-trailing-colon: true;
 | 
			
		||||
@descriptions-item-label-colon-margin-right: 8px;
 | 
			
		||||
@descriptions-item-label-colon-margin-left: 2px;
 | 
			
		||||
@descriptions-extra-color: @text-color;
 | 
			
		||||
 | 
			
		||||
// Dropdown
 | 
			
		||||
@dropdown-selected-color: @primary-color;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
import { defineComponent } from 'vue';
 | 
			
		||||
import { ColumnProps } from './interface';
 | 
			
		||||
import { columnProps } from './interface';
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: 'ATableColumn',
 | 
			
		||||
  props: ColumnProps,
 | 
			
		||||
  props: columnProps,
 | 
			
		||||
  render() {
 | 
			
		||||
    return null;
 | 
			
		||||
  },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,11 +17,11 @@ import initDefaultProps from '../_util/props-util/initDefaultProps';
 | 
			
		|||
import BaseMixin from '../_util/BaseMixin';
 | 
			
		||||
import { defaultConfigProvider } from '../config-provider';
 | 
			
		||||
import {
 | 
			
		||||
  TableProps,
 | 
			
		||||
  tableProps,
 | 
			
		||||
  TableComponents,
 | 
			
		||||
  TableState,
 | 
			
		||||
  ITableProps,
 | 
			
		||||
  IColumnProps,
 | 
			
		||||
  TableProps,
 | 
			
		||||
  ColumnProps,
 | 
			
		||||
  TableStateFilters,
 | 
			
		||||
} from './interface';
 | 
			
		||||
import Pagination from '../pagination';
 | 
			
		||||
| 
						 | 
				
			
			@ -38,15 +38,15 @@ function stopPropagation(e) {
 | 
			
		|||
  e.stopPropagation();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getRowSelection(props: ITableProps) {
 | 
			
		||||
function getRowSelection(props: TableProps) {
 | 
			
		||||
  return props.rowSelection || {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getColumnKey(column: IColumnProps, index?: number) {
 | 
			
		||||
function getColumnKey(column: ColumnProps, index?: number) {
 | 
			
		||||
  return column.key || column.dataIndex || index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isSameColumn(a: IColumnProps, b: IColumnProps): boolean {
 | 
			
		||||
function isSameColumn(a: ColumnProps, b: ColumnProps): boolean {
 | 
			
		||||
  if (a && b && a.key && a.key === b.key) {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -94,16 +94,16 @@ function isTheSameComponents(components1: TableComponents = {}, components2: Tab
 | 
			
		|||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getFilteredValueColumns(state: TableState, columns?: IColumnProps) {
 | 
			
		||||
function getFilteredValueColumns(state: TableState, columns?: ColumnProps) {
 | 
			
		||||
  return flatFilter(
 | 
			
		||||
    columns || (state || {}).columns || [],
 | 
			
		||||
    (column: IColumnProps) => typeof column.filteredValue !== 'undefined',
 | 
			
		||||
    (column: ColumnProps) => typeof column.filteredValue !== 'undefined',
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getFiltersFromColumns(state: TableState, columns: IColumnProps) {
 | 
			
		||||
function getFiltersFromColumns(state: TableState, columns: ColumnProps) {
 | 
			
		||||
  const filters = {};
 | 
			
		||||
  getFilteredValueColumns(state, columns).forEach((col: IColumnProps) => {
 | 
			
		||||
  getFilteredValueColumns(state, columns).forEach((col: ColumnProps) => {
 | 
			
		||||
    const colKey = getColumnKey(col);
 | 
			
		||||
    filters[colKey] = col.filteredValue;
 | 
			
		||||
  });
 | 
			
		||||
| 
						 | 
				
			
			@ -117,26 +117,28 @@ function isFiltersChanged(state: TableState, filters: TableStateFilters[]) {
 | 
			
		|||
  return Object.keys(filters).some(columnKey => filters[columnKey] !== state.filters[columnKey]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const defaultTableProps = initDefaultProps(tableProps, {
 | 
			
		||||
  dataSource: [],
 | 
			
		||||
  useFixedHeader: false,
 | 
			
		||||
  // rowSelection: null,
 | 
			
		||||
  size: 'default',
 | 
			
		||||
  loading: false,
 | 
			
		||||
  bordered: false,
 | 
			
		||||
  indentSize: 20,
 | 
			
		||||
  locale: {},
 | 
			
		||||
  rowKey: 'key',
 | 
			
		||||
  showHeader: true,
 | 
			
		||||
  sortDirections: ['ascend', 'descend'],
 | 
			
		||||
  childrenColumnName: 'children',
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: 'Table',
 | 
			
		||||
  mixins: [BaseMixin],
 | 
			
		||||
  inheritAttrs: false,
 | 
			
		||||
  Column,
 | 
			
		||||
  ColumnGroup,
 | 
			
		||||
  props: initDefaultProps(TableProps, {
 | 
			
		||||
    dataSource: [],
 | 
			
		||||
    useFixedHeader: false,
 | 
			
		||||
    // rowSelection: null,
 | 
			
		||||
    size: 'default',
 | 
			
		||||
    loading: false,
 | 
			
		||||
    bordered: false,
 | 
			
		||||
    indentSize: 20,
 | 
			
		||||
    locale: {},
 | 
			
		||||
    rowKey: 'key',
 | 
			
		||||
    showHeader: true,
 | 
			
		||||
    sortDirections: ['ascend', 'descend'],
 | 
			
		||||
    childrenColumnName: 'children',
 | 
			
		||||
  }),
 | 
			
		||||
  props: defaultTableProps,
 | 
			
		||||
 | 
			
		||||
  setup() {
 | 
			
		||||
    return {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import { App, defineComponent } from 'vue';
 | 
			
		||||
import T from './Table';
 | 
			
		||||
import T, { defaultTableProps } from './Table';
 | 
			
		||||
import Column from './Column';
 | 
			
		||||
import ColumnGroup from './ColumnGroup';
 | 
			
		||||
import {} from './interface';
 | 
			
		||||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ const Table = defineComponent({
 | 
			
		|||
  name: 'ATable',
 | 
			
		||||
  Column: T.Column,
 | 
			
		||||
  ColumnGroup: T.ColumnGroup,
 | 
			
		||||
  props: T.props,
 | 
			
		||||
  props: defaultTableProps,
 | 
			
		||||
  inheritAttrs: false,
 | 
			
		||||
  methods: {
 | 
			
		||||
    normalize(elements = []) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,21 +1,21 @@
 | 
			
		|||
import { ExtractPropTypes, PropType } from 'vue';
 | 
			
		||||
import PropTypes, { withUndefined } from '../_util/vue-types';
 | 
			
		||||
import { PaginationProps as getPaginationProps } from '../pagination';
 | 
			
		||||
import { SpinProps as getSpinProps } from '../spin';
 | 
			
		||||
import { Store } from './createStore';
 | 
			
		||||
import { tuple } from '../_util/type';
 | 
			
		||||
import { ExtractPropTypes } from 'vue';
 | 
			
		||||
 | 
			
		||||
const PaginationProps = getPaginationProps();
 | 
			
		||||
const SpinProps = getSpinProps();
 | 
			
		||||
 | 
			
		||||
// export type CompareFn<T> = ((a: T, b: T) => number);
 | 
			
		||||
export type CompareFn<T> = (a: T, b: T, sortOrder?: SortOrder) => number;
 | 
			
		||||
export const ColumnFilterItem = PropTypes.shape({
 | 
			
		||||
  text: PropTypes.string,
 | 
			
		||||
  value: PropTypes.string,
 | 
			
		||||
  children: PropTypes.array,
 | 
			
		||||
}).loose;
 | 
			
		||||
 | 
			
		||||
export const ColumnProps = {
 | 
			
		||||
export const columnProps = {
 | 
			
		||||
  title: PropTypes.VNodeChild,
 | 
			
		||||
  key: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
 | 
			
		||||
  dataIndex: PropTypes.string,
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +52,7 @@ export const ColumnProps = {
 | 
			
		|||
  // onHeaderCell?: (props: ColumnProps<T>) => any;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type IColumnProps = Partial<ExtractPropTypes<typeof ColumnProps>>;
 | 
			
		||||
export type ColumnProps = Partial<ExtractPropTypes<typeof columnProps>>;
 | 
			
		||||
 | 
			
		||||
export interface TableComponents {
 | 
			
		||||
  table?: any;
 | 
			
		||||
| 
						 | 
				
			
			@ -80,10 +80,10 @@ export const TableLocale = PropTypes.shape({
 | 
			
		|||
  collapse: PropTypes.string,
 | 
			
		||||
}).loose;
 | 
			
		||||
 | 
			
		||||
export const RowSelectionType = PropTypes.oneOf(['checkbox', 'radio']);
 | 
			
		||||
export const RowSelectionType = PropTypes.oneOf(tuple('checkbox', 'radio'));
 | 
			
		||||
// export type SelectionSelectFn<T> = (record: T, selected: boolean, selectedRows: Object[]) => any;
 | 
			
		||||
 | 
			
		||||
export const TableRowSelection = {
 | 
			
		||||
export const tableRowSelection = {
 | 
			
		||||
  type: RowSelectionType,
 | 
			
		||||
  selectedRowKeys: PropTypes.array,
 | 
			
		||||
  // onChange?: (selectedRowKeys: string[] | number[], selectedRows: Object[]) => any;
 | 
			
		||||
| 
						 | 
				
			
			@ -101,10 +101,12 @@ export const TableRowSelection = {
 | 
			
		|||
  columnTitle: PropTypes.any,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const TableProps = {
 | 
			
		||||
export type SortOrder = 'descend' | 'ascend';
 | 
			
		||||
 | 
			
		||||
export const tableProps = {
 | 
			
		||||
  prefixCls: PropTypes.string,
 | 
			
		||||
  dropdownPrefixCls: PropTypes.string,
 | 
			
		||||
  rowSelection: PropTypes.oneOfType([PropTypes.shape(TableRowSelection).loose, Object]),
 | 
			
		||||
  rowSelection: PropTypes.oneOfType([PropTypes.shape(tableRowSelection).loose, Object]),
 | 
			
		||||
  pagination: withUndefined(
 | 
			
		||||
    PropTypes.oneOfType([
 | 
			
		||||
      PropTypes.shape({
 | 
			
		||||
| 
						 | 
				
			
			@ -117,7 +119,9 @@ export const TableProps = {
 | 
			
		|||
  size: PropTypes.oneOf(tuple('default', 'middle', 'small', 'large')),
 | 
			
		||||
  dataSource: PropTypes.array,
 | 
			
		||||
  components: PropTypes.object,
 | 
			
		||||
  columns: PropTypes.array,
 | 
			
		||||
  columns: {
 | 
			
		||||
    type: Array as PropType<ColumnProps>,
 | 
			
		||||
  },
 | 
			
		||||
  rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
 | 
			
		||||
  rowClassName: PropTypes.func,
 | 
			
		||||
  expandedRowRender: PropTypes.any,
 | 
			
		||||
| 
						 | 
				
			
			@ -137,10 +141,18 @@ export const TableProps = {
 | 
			
		|||
  showHeader: PropTypes.looseBool,
 | 
			
		||||
  footer: PropTypes.func,
 | 
			
		||||
  title: PropTypes.func,
 | 
			
		||||
  scroll: PropTypes.object,
 | 
			
		||||
  scroll: {
 | 
			
		||||
    type: Object as PropType<{
 | 
			
		||||
      x?: boolean | number | string;
 | 
			
		||||
      y?: boolean | number | string;
 | 
			
		||||
      scrollToFirstRowOnChange?: boolean;
 | 
			
		||||
    }>,
 | 
			
		||||
  },
 | 
			
		||||
  childrenColumnName: PropTypes.oneOfType([PropTypes.array, PropTypes.string]),
 | 
			
		||||
  bodyStyle: PropTypes.any,
 | 
			
		||||
  sortDirections: PropTypes.array,
 | 
			
		||||
  bodyStyle: PropTypes.style,
 | 
			
		||||
  sortDirections: {
 | 
			
		||||
    type: Array as PropType<SortOrder[]>,
 | 
			
		||||
  },
 | 
			
		||||
  tableLayout: PropTypes.string,
 | 
			
		||||
  getPopupContainer: PropTypes.func,
 | 
			
		||||
  expandIcon: PropTypes.func,
 | 
			
		||||
| 
						 | 
				
			
			@ -153,9 +165,9 @@ export const TableProps = {
 | 
			
		|||
  // children?: React.ReactNode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type ITableRowSelection = Partial<ExtractPropTypes<typeof TableRowSelection>>;
 | 
			
		||||
export type TableRowSelection = Partial<ExtractPropTypes<typeof tableRowSelection>>;
 | 
			
		||||
 | 
			
		||||
export type ITableProps = Partial<ExtractPropTypes<typeof TableProps>>;
 | 
			
		||||
export type TableProps = Partial<ExtractPropTypes<typeof tableProps>>;
 | 
			
		||||
 | 
			
		||||
export interface TableStateFilters {
 | 
			
		||||
  [key: string]: string[];
 | 
			
		||||
| 
						 | 
				
			
			@ -164,9 +176,9 @@ export interface TableStateFilters {
 | 
			
		|||
export interface TableState {
 | 
			
		||||
  pagination?: Partial<ExtractPropTypes<typeof PaginationProps>>;
 | 
			
		||||
  filters?: TableStateFilters;
 | 
			
		||||
  sortColumn?: Partial<ExtractPropTypes<typeof ColumnProps>> | null;
 | 
			
		||||
  sortColumn?: ColumnProps | null;
 | 
			
		||||
  sortOrder?: string;
 | 
			
		||||
  columns?: IColumnProps[];
 | 
			
		||||
  columns?: ColumnProps[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// export type SelectionItemSelectFn = (key: string[]) => any;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue