2021-06-26 01:35:40 +00:00
|
|
|
import type { PropType, ExtractPropTypes, CSSProperties } from 'vue';
|
|
|
|
import { defineComponent, computed, ref, watch } from 'vue';
|
2020-10-17 04:13:55 +00:00
|
|
|
import PropTypes from '../_util/vue-types';
|
2020-08-15 06:43:14 +00:00
|
|
|
import { filterEmpty } from '../_util/props-util';
|
2021-06-26 01:35:40 +00:00
|
|
|
import type { SizeType } from '../config-provider';
|
2020-11-01 07:03:33 +00:00
|
|
|
import { tuple, withInstall } from '../_util/type';
|
2021-06-07 09:35:03 +00:00
|
|
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
|
|
|
import useFlexGapSupport from '../_util/hooks/useFlexGapSupport';
|
|
|
|
import classNames from '../_util/classNames';
|
2020-08-12 10:22:21 +00:00
|
|
|
|
2021-06-07 09:35:03 +00:00
|
|
|
export type SpaceSize = SizeType | number;
|
2020-08-12 10:22:21 +00:00
|
|
|
const spaceSize = {
|
|
|
|
small: 8,
|
|
|
|
middle: 16,
|
|
|
|
large: 24,
|
|
|
|
};
|
2022-03-26 14:52:54 +00:00
|
|
|
export const spaceProps = () => ({
|
|
|
|
prefixCls: String,
|
2021-06-07 09:35:03 +00:00
|
|
|
size: {
|
|
|
|
type: [String, Number, Array] as PropType<SpaceSize | [SpaceSize, SpaceSize]>,
|
|
|
|
},
|
|
|
|
direction: PropTypes.oneOf(tuple('horizontal', 'vertical')).def('horizontal'),
|
|
|
|
align: PropTypes.oneOf(tuple('start', 'end', 'center', 'baseline')),
|
2022-03-26 14:52:54 +00:00
|
|
|
wrap: { type: Boolean, default: undefined },
|
|
|
|
});
|
2021-06-07 09:35:03 +00:00
|
|
|
|
2022-03-26 14:52:54 +00:00
|
|
|
export type SpaceProps = Partial<ExtractPropTypes<ReturnType<typeof spaceProps>>>;
|
2021-06-07 09:35:03 +00:00
|
|
|
|
|
|
|
function getNumberSize(size: SpaceSize) {
|
|
|
|
return typeof size === 'string' ? spaceSize[size] : size || 0;
|
|
|
|
}
|
2020-08-12 10:22:21 +00:00
|
|
|
|
2020-10-17 04:13:55 +00:00
|
|
|
const Space = defineComponent({
|
|
|
|
name: 'ASpace',
|
2022-03-26 14:52:54 +00:00
|
|
|
props: spaceProps(),
|
2021-06-07 09:35:03 +00:00
|
|
|
slots: ['split'],
|
2020-10-17 04:13:55 +00:00
|
|
|
setup(props, { slots }) {
|
2021-06-07 09:35:03 +00:00
|
|
|
const { prefixCls, space, direction: directionConfig } = useConfigInject('space', props);
|
|
|
|
const supportFlexGap = useFlexGapSupport();
|
2022-01-04 01:51:23 +00:00
|
|
|
const size = computed(() => props.size ?? space.value?.size ?? 'small');
|
2021-06-07 09:35:03 +00:00
|
|
|
const horizontalSize = ref<number>();
|
|
|
|
const verticalSize = ref<number>();
|
|
|
|
watch(
|
|
|
|
size,
|
|
|
|
() => {
|
2021-06-23 15:08:16 +00:00
|
|
|
[horizontalSize.value, verticalSize.value] = (
|
|
|
|
(Array.isArray(size.value) ? size.value : [size.value, size.value]) as [
|
|
|
|
SpaceSize,
|
|
|
|
SpaceSize,
|
|
|
|
]
|
|
|
|
).map(item => getNumberSize(item));
|
2021-06-07 09:35:03 +00:00
|
|
|
},
|
|
|
|
{ immediate: true },
|
|
|
|
);
|
|
|
|
|
|
|
|
const mergedAlign = computed(() =>
|
|
|
|
props.align === undefined && props.direction === 'horizontal' ? 'center' : props.align,
|
|
|
|
);
|
|
|
|
const cn = computed(() => {
|
|
|
|
return classNames(prefixCls.value, `${prefixCls.value}-${props.direction}`, {
|
|
|
|
[`${prefixCls.value}-rtl`]: directionConfig.value === 'rtl',
|
|
|
|
[`${prefixCls.value}-align-${mergedAlign.value}`]: mergedAlign.value,
|
|
|
|
});
|
|
|
|
});
|
2020-08-12 10:22:21 +00:00
|
|
|
|
2021-06-07 09:35:03 +00:00
|
|
|
const marginDirection = computed(() =>
|
|
|
|
directionConfig.value === 'rtl' ? 'marginLeft' : 'marginRight',
|
|
|
|
);
|
|
|
|
const style = computed(() => {
|
|
|
|
const gapStyle: CSSProperties = {};
|
2021-07-06 02:02:26 +00:00
|
|
|
if (supportFlexGap.value) {
|
2021-06-07 09:35:03 +00:00
|
|
|
gapStyle.columnGap = `${horizontalSize.value}px`;
|
|
|
|
gapStyle.rowGap = `${verticalSize.value}px`;
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
...gapStyle,
|
|
|
|
...(props.wrap && { flexWrap: 'wrap', marginBottom: `${-verticalSize.value}px` }),
|
|
|
|
} as CSSProperties;
|
|
|
|
});
|
2020-10-17 04:13:55 +00:00
|
|
|
return () => {
|
2021-06-07 09:35:03 +00:00
|
|
|
const { wrap, direction = 'horizontal' } = props;
|
2020-10-18 13:49:37 +00:00
|
|
|
|
2020-10-17 04:13:55 +00:00
|
|
|
const items = filterEmpty(slots.default?.());
|
|
|
|
const len = items.length;
|
2020-08-12 10:22:21 +00:00
|
|
|
|
2020-10-17 04:13:55 +00:00
|
|
|
if (len === 0) {
|
|
|
|
return null;
|
|
|
|
}
|
2021-06-07 09:35:03 +00:00
|
|
|
const split = slots.split?.();
|
|
|
|
const itemClassName = `${prefixCls.value}-item`;
|
|
|
|
const horizontalSizeVal = horizontalSize.value;
|
|
|
|
const latestIndex = len - 1;
|
2020-10-17 04:13:55 +00:00
|
|
|
return (
|
2021-06-07 09:35:03 +00:00
|
|
|
<div class={cn.value} style={style.value}>
|
|
|
|
{items.map((child, index) => {
|
|
|
|
let itemStyle: CSSProperties = {};
|
2021-07-06 02:02:26 +00:00
|
|
|
if (!supportFlexGap.value) {
|
2021-06-07 09:35:03 +00:00
|
|
|
if (direction === 'vertical') {
|
|
|
|
if (index < latestIndex) {
|
|
|
|
itemStyle = { marginBottom: `${horizontalSizeVal / (split ? 2 : 1)}px` };
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
itemStyle = {
|
|
|
|
...(index < latestIndex && {
|
|
|
|
[marginDirection.value]: `${horizontalSizeVal / (split ? 2 : 1)}px`,
|
|
|
|
}),
|
|
|
|
...(wrap && { paddingBottom: `${verticalSize.value}px` }),
|
|
|
|
};
|
2020-10-17 04:13:55 +00:00
|
|
|
}
|
2021-06-07 09:35:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<div class={itemClassName} style={itemStyle}>
|
|
|
|
{child}
|
|
|
|
</div>
|
|
|
|
{index < latestIndex && split && (
|
|
|
|
<span class={`${itemClassName}-split`} style={itemStyle}>
|
|
|
|
{split}
|
|
|
|
</span>
|
|
|
|
)}
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
})}
|
2020-08-12 14:08:06 +00:00
|
|
|
</div>
|
2020-10-17 04:13:55 +00:00
|
|
|
);
|
|
|
|
};
|
|
|
|
},
|
|
|
|
});
|
2020-08-12 10:22:21 +00:00
|
|
|
|
2020-11-01 07:03:33 +00:00
|
|
|
export default withInstall(Space);
|