mirror of
https://gitee.com/ant-design-vue/ant-design-vue.git
synced 2024-11-30 02:57:50 +08:00
Merge branches 'next' and 'next' of https://github.com/vueComponent/ant-design-vue into next
This commit is contained in:
commit
948727a2ef
55
components/descriptions/Cell.tsx
Normal file
55
components/descriptions/Cell.tsx
Normal file
@ -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;
|
|
109
components/descriptions/Row.tsx
Normal file
109
components/descriptions/Row.tsx
Normal file
@ -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>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="ant-descriptions-row">
|
<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>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -22,7 +22,9 @@ exports[`Descriptions Descriptions support style 1`] = `
|
|||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="ant-descriptions-row">
|
<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>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -37,7 +39,7 @@ exports[`Descriptions Descriptions.Item support className 1`] = `
|
|||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="ant-descriptions-row">
|
<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>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -52,12 +54,12 @@ exports[`Descriptions column is number 1`] = `
|
|||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="ant-descriptions-row">
|
<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 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 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 class="ant-descriptions-item" colspan="1"><span class="ant-descriptions-item-label">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">time</span><span class="ant-descriptions-item-content">18:00:00</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="ant-descriptions-row">
|
<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>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -72,20 +74,36 @@ exports[`Descriptions vertical layout 1`] = `
|
|||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="ant-descriptions-row">
|
<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>
|
<th class="ant-descriptions-item" colspan="1"><span class="ant-descriptions-item-label">Product</span>
|
||||||
<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>
|
||||||
|
<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>
|
||||||
<tr class="ant-descriptions-row">
|
<tr class="ant-descriptions-row">
|
||||||
<td colspan="1" class="ant-descriptions-item"><span class="ant-descriptions-item-content">Cloud Database</span></td>
|
<td class="ant-descriptions-item" colspan="1">
|
||||||
<td colspan="1" class="ant-descriptions-item"><span class="ant-descriptions-item-content">Prepaid</span></td>
|
<!----><span class="ant-descriptions-item-content">Cloud Database</span>
|
||||||
<td colspan="1" class="ant-descriptions-item"><span class="ant-descriptions-item-content">18:00:00</span></td>
|
</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>
|
||||||
<tr class="ant-descriptions-row">
|
<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>
|
||||||
<tr class="ant-descriptions-row">
|
<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>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -100,12 +118,12 @@ exports[`Descriptions when item is rendered conditionally 1`] = `
|
|||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="ant-descriptions-row">
|
<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 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 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 class="ant-descriptions-item" colspan="1"><span class="ant-descriptions-item-label">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">time</span><span class="ant-descriptions-item-content">18:00:00</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="ant-descriptions-row">
|
<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>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -33,7 +33,9 @@ describe('Descriptions', () => {
|
|||||||
{ sync: false, attachTo: 'body' },
|
{ sync: false, attachTo: 'body' },
|
||||||
);
|
);
|
||||||
await asyncExpect(() => {
|
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);
|
}, 100);
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
@ -74,7 +76,7 @@ describe('Descriptions', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(errorSpy).toHaveBeenCalledWith(
|
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() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Descriptions>
|
<Descriptions>
|
||||||
<Descriptions.Item label="Product" className="my-class">
|
<Descriptions.Item label="Product" class="my-class">
|
||||||
Cloud Database
|
Cloud Database
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
</Descriptions>
|
</Descriptions>
|
||||||
@ -176,7 +178,7 @@ describe('Descriptions', () => {
|
|||||||
);
|
);
|
||||||
await asyncExpect(() => {
|
await asyncExpect(() => {
|
||||||
expect(wrapper.findAll('tr')).toHaveLength(5);
|
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();
|
wrapper.unmount();
|
||||||
@ -198,8 +200,86 @@ describe('Descriptions', () => {
|
|||||||
},
|
},
|
||||||
{ sync: false, attachTo: 'body' },
|
{ sync: false, attachTo: 'body' },
|
||||||
);
|
);
|
||||||
await asyncExpect(() => {});
|
await asyncExpect(() => {
|
||||||
expect(wrapper.findAll('tr')).toHaveLength(2);
|
expect(wrapper.findAll('tr')).toHaveLength(2);
|
||||||
|
});
|
||||||
wrapper.unmount();
|
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 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 { defaultConfigProvider } from '../config-provider';
|
||||||
import Col from './Col';
|
import Row from './Row';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import { getOptionProps, getComponent, isValidElement, getSlot } from '../_util/props-util';
|
import { tuple } from '../_util/type';
|
||||||
import BaseMixin from '../_util/BaseMixin';
|
import { cloneElement } from '../_util/vnode';
|
||||||
import { tuple, VueNode } from '../_util/type';
|
import { filterEmpty } from '../_util/props-util';
|
||||||
|
|
||||||
export const DescriptionsItemProps = {
|
export const DescriptionsItemProps = {
|
||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
@ -14,16 +29,6 @@ export const DescriptionsItemProps = {
|
|||||||
span: PropTypes.number,
|
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 = {
|
export const DescriptionsItem = {
|
||||||
name: 'ADescriptionsItem',
|
name: 'ADescriptionsItem',
|
||||||
props: {
|
props: {
|
||||||
@ -36,7 +41,7 @@ export const DescriptionsItem = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultColumnMap = {
|
const DEFAULT_COLUMN_MAP: Record<Breakpoint, number> = {
|
||||||
xxl: 3,
|
xxl: 3,
|
||||||
xl: 3,
|
xl: 3,
|
||||||
lg: 3,
|
lg: 3,
|
||||||
@ -45,229 +50,172 @@ const defaultColumnMap = {
|
|||||||
xs: 1,
|
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,
|
prefixCls: PropTypes.string,
|
||||||
bordered: PropTypes.looseBool,
|
bordered: PropTypes.looseBool,
|
||||||
size: PropTypes.oneOf(tuple('default', 'middle', 'small')).def('default'),
|
size: PropTypes.oneOf(tuple('default', 'middle', 'small')).def('default'),
|
||||||
title: PropTypes.VNodeChild,
|
title: PropTypes.VNodeChild,
|
||||||
|
extra: PropTypes.VNodeChild,
|
||||||
column: {
|
column: {
|
||||||
type: [Number, Object] as PropType<number | Partial<Record<Breakpoint, number>>>,
|
type: [Number, Object] as PropType<number | Partial<Record<Breakpoint, number>>>,
|
||||||
default: () => defaultColumnMap,
|
default: () => DEFAULT_COLUMN_MAP,
|
||||||
},
|
},
|
||||||
layout: PropTypes.oneOf(tuple('horizontal', 'vertical')),
|
layout: PropTypes.oneOf(tuple('horizontal', 'vertical')),
|
||||||
colon: PropTypes.looseBool,
|
colon: PropTypes.looseBool,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
export type DescriptionsProps = HTMLAttributes &
|
||||||
* Convert children into `column` groups.
|
Partial<ExtractPropTypes<typeof descriptionsProps>>;
|
||||||
* @param children: DescriptionsItem
|
|
||||||
* @param column: number
|
|
||||||
*/
|
|
||||||
const generateChildrenRows = (children: VueNode, column: number) => {
|
|
||||||
const rows = [];
|
|
||||||
let columns = null;
|
|
||||||
let leftSpans: number;
|
|
||||||
|
|
||||||
const itemNodes = toArray(children);
|
const Descriptions = defineComponent<DescriptionsProps>({
|
||||||
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({
|
|
||||||
name: 'ADescriptions',
|
name: 'ADescriptions',
|
||||||
Item: DescriptionsItem,
|
Item: DescriptionsItem,
|
||||||
mixins: [BaseMixin],
|
setup(props, { slots }) {
|
||||||
props: DescriptionsProps,
|
const { getPrefixCls } = inject('configProvider', defaultConfigProvider);
|
||||||
setup() {
|
|
||||||
return {
|
let token: number;
|
||||||
configProvider: inject('configProvider', defaultConfigProvider),
|
|
||||||
};
|
const screens = ref<ScreenMap>({});
|
||||||
},
|
|
||||||
data() {
|
onMounted(() => {
|
||||||
return {
|
token = ResponsiveObserve.subscribe(screen => {
|
||||||
screens: {},
|
if (typeof props.column !== 'object') {
|
||||||
token: undefined,
|
return;
|
||||||
};
|
|
||||||
},
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// 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 = [];
|
screens.value = screen;
|
||||||
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,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
|
||||||
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();
|
onBeforeUnmount(() => {
|
||||||
const children = getSlot(this);
|
ResponsiveObserve.unsubscribe(token);
|
||||||
const cloneChildren = toArray(children)
|
});
|
||||||
.map((child: VNode) => {
|
|
||||||
if (isValidElement(child)) {
|
return () => {
|
||||||
return cloneVNode(child, {
|
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,
|
prefixCls,
|
||||||
});
|
{
|
||||||
}
|
[`${prefixCls}-${size}`]: size !== 'default',
|
||||||
return null;
|
[`${prefixCls}-bordered`]: !!bordered,
|
||||||
})
|
},
|
||||||
.filter(node => node);
|
]}
|
||||||
|
>
|
||||||
const childrenArray = generateChildrenRows(cloneChildren, column);
|
{(title || extra) && (
|
||||||
return (
|
<div class={`${prefixCls}-header`}>
|
||||||
<div
|
<div class={`${prefixCls}-title`}>{title}</div>
|
||||||
class={[
|
<div class={`${prefixCls}-extra`}>{extra}</div>
|
||||||
prefixCls,
|
</div>
|
||||||
{
|
)}
|
||||||
[`${prefixCls}-${size}`]: size !== 'default',
|
<div class={`${prefixCls}-view`}>
|
||||||
[`${prefixCls}-bordered`]: !!bordered,
|
<table>
|
||||||
},
|
<tbody>
|
||||||
]}
|
{rows.map((row, index) => (
|
||||||
>
|
<Row
|
||||||
{title && <div class={`${prefixCls}-title`}>{title}</div>}
|
key={index}
|
||||||
<div class={`${prefixCls}-view`}>
|
index={index}
|
||||||
<table>
|
colon={colon}
|
||||||
<tbody>
|
prefixCls={prefixCls}
|
||||||
{childrenArray.map((child, index) =>
|
vertical={layout === 'vertical'}
|
||||||
this.renderRow(
|
bordered={bordered}
|
||||||
child,
|
row={row}
|
||||||
index,
|
/>
|
||||||
{
|
))}
|
||||||
prefixCls,
|
</tbody>
|
||||||
},
|
</table>
|
||||||
bordered,
|
</div>
|
||||||
layout,
|
|
||||||
colon,
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Descriptions.props = descriptionsProps;
|
||||||
|
|
||||||
Descriptions.install = function(app: App) {
|
Descriptions.install = function(app: App) {
|
||||||
app.component(Descriptions.name, Descriptions);
|
app.component(Descriptions.name, Descriptions);
|
||||||
app.component(Descriptions.Item.name, Descriptions.Item);
|
app.component(Descriptions.Item.name, Descriptions.Item);
|
||||||
|
@ -3,17 +3,28 @@
|
|||||||
|
|
||||||
@descriptions-prefix-cls: ~'@{ant-prefix}-descriptions';
|
@descriptions-prefix-cls: ~'@{ant-prefix}-descriptions';
|
||||||
|
|
||||||
@descriptions-default-padding: 16px 24px;
|
|
||||||
@descriptions-middle-padding: 12px 24px;
|
|
||||||
@descriptions-small-padding: 8px 16px;
|
|
||||||
|
|
||||||
.@{descriptions-prefix-cls} {
|
.@{descriptions-prefix-cls} {
|
||||||
|
&-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: @descriptions-title-margin-bottom;
|
||||||
|
}
|
||||||
|
|
||||||
&-title {
|
&-title {
|
||||||
margin-bottom: 20px;
|
flex: auto;
|
||||||
|
overflow: hidden;
|
||||||
color: @heading-color;
|
color: @heading-color;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: @font-size-lg;
|
font-size: @font-size-lg;
|
||||||
line-height: @line-height-base;
|
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 {
|
&-view {
|
||||||
@ -29,7 +40,7 @@
|
|||||||
&-row {
|
&-row {
|
||||||
> th,
|
> th,
|
||||||
> td {
|
> td {
|
||||||
padding-bottom: 16px;
|
padding-bottom: @descriptions-item-padding-bottom;
|
||||||
}
|
}
|
||||||
&:last-child {
|
&:last-child {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
@ -41,18 +52,24 @@
|
|||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: @font-size-base;
|
font-size: @font-size-base;
|
||||||
line-height: @line-height-base;
|
line-height: @line-height-base;
|
||||||
|
text-align: start;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
|
& when (@descriptions-item-trailing-colon=true) {
|
||||||
|
content: ':';
|
||||||
|
}
|
||||||
|
& when not (@descriptions-item-trailing-colon=true) {
|
||||||
|
content: ' ';
|
||||||
|
}
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
top: -0.5px;
|
top: -0.5px;
|
||||||
margin: 0 8px 0 2px;
|
margin: 0 @descriptions-item-label-colon-margin-right 0
|
||||||
content: ' ';
|
@descriptions-item-label-colon-margin-left;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
&-item-colon {
|
&.@{descriptions-prefix-cls}-item-no-colon::after {
|
||||||
&::after {
|
content: ' ';
|
||||||
content: ':';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,15 +82,23 @@
|
|||||||
|
|
||||||
&-item-content {
|
&-item-content {
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
|
flex: 1;
|
||||||
color: @text-color;
|
color: @text-color;
|
||||||
font-size: @font-size-base;
|
font-size: @font-size-base;
|
||||||
line-height: @line-height-base;
|
line-height: @line-height-base;
|
||||||
|
overflow-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-item {
|
&-item {
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
|
vertical-align: top;
|
||||||
> span {
|
> span {
|
||||||
display: inline-block;
|
display: inline-flex;
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-container {
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +115,7 @@
|
|||||||
.@{descriptions-prefix-cls}-row {
|
.@{descriptions-prefix-cls}-row {
|
||||||
> th,
|
> th,
|
||||||
> td {
|
> td {
|
||||||
padding-bottom: 8px;
|
padding-bottom: @padding-xs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,6 +192,15 @@
|
|||||||
|
|
||||||
// Descriptions
|
// Descriptions
|
||||||
@descriptions-bg: #fafafa;
|
@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
|
||||||
@dropdown-selected-color: @primary-color;
|
@dropdown-selected-color: @primary-color;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { ColumnProps } from './interface';
|
import { columnProps } from './interface';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ATableColumn',
|
name: 'ATableColumn',
|
||||||
props: ColumnProps,
|
props: columnProps,
|
||||||
render() {
|
render() {
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
@ -17,11 +17,11 @@ import initDefaultProps from '../_util/props-util/initDefaultProps';
|
|||||||
import BaseMixin from '../_util/BaseMixin';
|
import BaseMixin from '../_util/BaseMixin';
|
||||||
import { defaultConfigProvider } from '../config-provider';
|
import { defaultConfigProvider } from '../config-provider';
|
||||||
import {
|
import {
|
||||||
TableProps,
|
tableProps,
|
||||||
TableComponents,
|
TableComponents,
|
||||||
TableState,
|
TableState,
|
||||||
ITableProps,
|
TableProps,
|
||||||
IColumnProps,
|
ColumnProps,
|
||||||
TableStateFilters,
|
TableStateFilters,
|
||||||
} from './interface';
|
} from './interface';
|
||||||
import Pagination from '../pagination';
|
import Pagination from '../pagination';
|
||||||
@ -38,15 +38,15 @@ function stopPropagation(e) {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRowSelection(props: ITableProps) {
|
function getRowSelection(props: TableProps) {
|
||||||
return props.rowSelection || {};
|
return props.rowSelection || {};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getColumnKey(column: IColumnProps, index?: number) {
|
function getColumnKey(column: ColumnProps, index?: number) {
|
||||||
return column.key || column.dataIndex || index;
|
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) {
|
if (a && b && a.key && a.key === b.key) {
|
||||||
return true;
|
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(
|
return flatFilter(
|
||||||
columns || (state || {}).columns || [],
|
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 = {};
|
const filters = {};
|
||||||
getFilteredValueColumns(state, columns).forEach((col: IColumnProps) => {
|
getFilteredValueColumns(state, columns).forEach((col: ColumnProps) => {
|
||||||
const colKey = getColumnKey(col);
|
const colKey = getColumnKey(col);
|
||||||
filters[colKey] = col.filteredValue;
|
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]);
|
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({
|
export default defineComponent({
|
||||||
name: 'Table',
|
name: 'Table',
|
||||||
mixins: [BaseMixin],
|
mixins: [BaseMixin],
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
Column,
|
Column,
|
||||||
ColumnGroup,
|
ColumnGroup,
|
||||||
props: initDefaultProps(TableProps, {
|
props: defaultTableProps,
|
||||||
dataSource: [],
|
|
||||||
useFixedHeader: false,
|
|
||||||
// rowSelection: null,
|
|
||||||
size: 'default',
|
|
||||||
loading: false,
|
|
||||||
bordered: false,
|
|
||||||
indentSize: 20,
|
|
||||||
locale: {},
|
|
||||||
rowKey: 'key',
|
|
||||||
showHeader: true,
|
|
||||||
sortDirections: ['ascend', 'descend'],
|
|
||||||
childrenColumnName: 'children',
|
|
||||||
}),
|
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
return {
|
return {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { App, defineComponent } from 'vue';
|
import { App, defineComponent } from 'vue';
|
||||||
import T from './Table';
|
import T, { defaultTableProps } from './Table';
|
||||||
import Column from './Column';
|
import Column from './Column';
|
||||||
import ColumnGroup from './ColumnGroup';
|
import ColumnGroup from './ColumnGroup';
|
||||||
import {} from './interface';
|
import {} from './interface';
|
||||||
@ -9,7 +9,7 @@ const Table = defineComponent({
|
|||||||
name: 'ATable',
|
name: 'ATable',
|
||||||
Column: T.Column,
|
Column: T.Column,
|
||||||
ColumnGroup: T.ColumnGroup,
|
ColumnGroup: T.ColumnGroup,
|
||||||
props: T.props,
|
props: defaultTableProps,
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
methods: {
|
methods: {
|
||||||
normalize(elements = []) {
|
normalize(elements = []) {
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
|
import { ExtractPropTypes, PropType } from 'vue';
|
||||||
import PropTypes, { withUndefined } from '../_util/vue-types';
|
import PropTypes, { withUndefined } from '../_util/vue-types';
|
||||||
import { PaginationProps as getPaginationProps } from '../pagination';
|
import { PaginationProps as getPaginationProps } from '../pagination';
|
||||||
import { SpinProps as getSpinProps } from '../spin';
|
import { SpinProps as getSpinProps } from '../spin';
|
||||||
import { Store } from './createStore';
|
import { Store } from './createStore';
|
||||||
import { tuple } from '../_util/type';
|
import { tuple } from '../_util/type';
|
||||||
import { ExtractPropTypes } from 'vue';
|
|
||||||
|
|
||||||
const PaginationProps = getPaginationProps();
|
const PaginationProps = getPaginationProps();
|
||||||
const SpinProps = getSpinProps();
|
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({
|
export const ColumnFilterItem = PropTypes.shape({
|
||||||
text: PropTypes.string,
|
text: PropTypes.string,
|
||||||
value: PropTypes.string,
|
value: PropTypes.string,
|
||||||
children: PropTypes.array,
|
children: PropTypes.array,
|
||||||
}).loose;
|
}).loose;
|
||||||
|
|
||||||
export const ColumnProps = {
|
export const columnProps = {
|
||||||
title: PropTypes.VNodeChild,
|
title: PropTypes.VNodeChild,
|
||||||
key: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
key: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
dataIndex: PropTypes.string,
|
dataIndex: PropTypes.string,
|
||||||
@ -52,7 +52,7 @@ export const ColumnProps = {
|
|||||||
// onHeaderCell?: (props: ColumnProps<T>) => any;
|
// onHeaderCell?: (props: ColumnProps<T>) => any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type IColumnProps = Partial<ExtractPropTypes<typeof ColumnProps>>;
|
export type ColumnProps = Partial<ExtractPropTypes<typeof columnProps>>;
|
||||||
|
|
||||||
export interface TableComponents {
|
export interface TableComponents {
|
||||||
table?: any;
|
table?: any;
|
||||||
@ -80,10 +80,10 @@ export const TableLocale = PropTypes.shape({
|
|||||||
collapse: PropTypes.string,
|
collapse: PropTypes.string,
|
||||||
}).loose;
|
}).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 type SelectionSelectFn<T> = (record: T, selected: boolean, selectedRows: Object[]) => any;
|
||||||
|
|
||||||
export const TableRowSelection = {
|
export const tableRowSelection = {
|
||||||
type: RowSelectionType,
|
type: RowSelectionType,
|
||||||
selectedRowKeys: PropTypes.array,
|
selectedRowKeys: PropTypes.array,
|
||||||
// onChange?: (selectedRowKeys: string[] | number[], selectedRows: Object[]) => any;
|
// onChange?: (selectedRowKeys: string[] | number[], selectedRows: Object[]) => any;
|
||||||
@ -101,10 +101,12 @@ export const TableRowSelection = {
|
|||||||
columnTitle: PropTypes.any,
|
columnTitle: PropTypes.any,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TableProps = {
|
export type SortOrder = 'descend' | 'ascend';
|
||||||
|
|
||||||
|
export const tableProps = {
|
||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
dropdownPrefixCls: PropTypes.string,
|
dropdownPrefixCls: PropTypes.string,
|
||||||
rowSelection: PropTypes.oneOfType([PropTypes.shape(TableRowSelection).loose, Object]),
|
rowSelection: PropTypes.oneOfType([PropTypes.shape(tableRowSelection).loose, Object]),
|
||||||
pagination: withUndefined(
|
pagination: withUndefined(
|
||||||
PropTypes.oneOfType([
|
PropTypes.oneOfType([
|
||||||
PropTypes.shape({
|
PropTypes.shape({
|
||||||
@ -117,7 +119,9 @@ export const TableProps = {
|
|||||||
size: PropTypes.oneOf(tuple('default', 'middle', 'small', 'large')),
|
size: PropTypes.oneOf(tuple('default', 'middle', 'small', 'large')),
|
||||||
dataSource: PropTypes.array,
|
dataSource: PropTypes.array,
|
||||||
components: PropTypes.object,
|
components: PropTypes.object,
|
||||||
columns: PropTypes.array,
|
columns: {
|
||||||
|
type: Array as PropType<ColumnProps>,
|
||||||
|
},
|
||||||
rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||||
rowClassName: PropTypes.func,
|
rowClassName: PropTypes.func,
|
||||||
expandedRowRender: PropTypes.any,
|
expandedRowRender: PropTypes.any,
|
||||||
@ -137,10 +141,18 @@ export const TableProps = {
|
|||||||
showHeader: PropTypes.looseBool,
|
showHeader: PropTypes.looseBool,
|
||||||
footer: PropTypes.func,
|
footer: PropTypes.func,
|
||||||
title: 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]),
|
childrenColumnName: PropTypes.oneOfType([PropTypes.array, PropTypes.string]),
|
||||||
bodyStyle: PropTypes.any,
|
bodyStyle: PropTypes.style,
|
||||||
sortDirections: PropTypes.array,
|
sortDirections: {
|
||||||
|
type: Array as PropType<SortOrder[]>,
|
||||||
|
},
|
||||||
tableLayout: PropTypes.string,
|
tableLayout: PropTypes.string,
|
||||||
getPopupContainer: PropTypes.func,
|
getPopupContainer: PropTypes.func,
|
||||||
expandIcon: PropTypes.func,
|
expandIcon: PropTypes.func,
|
||||||
@ -153,9 +165,9 @@ export const TableProps = {
|
|||||||
// children?: React.ReactNode;
|
// 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 {
|
export interface TableStateFilters {
|
||||||
[key: string]: string[];
|
[key: string]: string[];
|
||||||
@ -164,9 +176,9 @@ export interface TableStateFilters {
|
|||||||
export interface TableState {
|
export interface TableState {
|
||||||
pagination?: Partial<ExtractPropTypes<typeof PaginationProps>>;
|
pagination?: Partial<ExtractPropTypes<typeof PaginationProps>>;
|
||||||
filters?: TableStateFilters;
|
filters?: TableStateFilters;
|
||||||
sortColumn?: Partial<ExtractPropTypes<typeof ColumnProps>> | null;
|
sortColumn?: ColumnProps | null;
|
||||||
sortOrder?: string;
|
sortOrder?: string;
|
||||||
columns?: IColumnProps[];
|
columns?: ColumnProps[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// export type SelectionItemSelectFn = (key: string[]) => any;
|
// export type SelectionItemSelectFn = (key: string[]) => any;
|
||||||
|
Loading…
Reference in New Issue
Block a user