mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
* feat(space): feat/space - Init commit for space component * complete code & test & partial demo * feat(space): feat/space - Finish documentation for 中文 and English. * feat(space): feat/space - Replace flatMap to reduce.
130 lines
2.9 KiB
TypeScript
130 lines
2.9 KiB
TypeScript
import { ref, computed, watch, isVNode } from 'vue'
|
|
import { isValidComponentSize } from '@element-plus/utils/validators'
|
|
import { isNumber, isArray, isString } from '@element-plus/utils/util'
|
|
|
|
import type { PropType, ExtractPropTypes, CSSProperties, VNodeChild } from 'vue'
|
|
|
|
const SizeMap: Record<ComponentSize, number> = {
|
|
mini: 4,
|
|
small: 8,
|
|
medium: 12,
|
|
large: 16,
|
|
}
|
|
|
|
export const defaultProps = {
|
|
direction: {
|
|
type: String as PropType<'horizontal' | 'vertical'>,
|
|
default: 'horizontal',
|
|
},
|
|
|
|
class: {
|
|
type: [String, Object, Array],
|
|
default: '',
|
|
},
|
|
|
|
style: {
|
|
type: [String, Array, Object] as PropType<
|
|
string | Array<any> | CSSProperties
|
|
>,
|
|
},
|
|
|
|
alignment: {
|
|
type: String as PropType<''>,
|
|
default: 'center',
|
|
},
|
|
|
|
prefixCls: {
|
|
type: String,
|
|
},
|
|
|
|
spacer: {
|
|
type: [Object, String, Number] as PropType<VNodeChild>,
|
|
default: null,
|
|
validator: (val: unknown) => {
|
|
return isVNode(val) || isNumber(val) || isString(val)
|
|
},
|
|
},
|
|
|
|
wrap: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
|
|
size: {
|
|
type: [String, Array, Number] as PropType<
|
|
ComponentSize | [number, number] | number
|
|
>,
|
|
validator: (val: unknown) => {
|
|
return (
|
|
isValidComponentSize(val as string) || isNumber(val) || isArray(val)
|
|
)
|
|
},
|
|
},
|
|
}
|
|
|
|
export function useSpace(props: ExtractPropTypes<typeof defaultProps>) {
|
|
const classes = computed(() => [
|
|
'el-space',
|
|
`el-space--${props.direction}`,
|
|
props.class,
|
|
])
|
|
|
|
const horizontalSize = ref(0)
|
|
const verticalSize = ref(0)
|
|
|
|
watch(
|
|
() => [props.size, props.wrap, props.direction],
|
|
([size = 'small', wrap, dir]) => {
|
|
// when the specified size have been given
|
|
if (isArray(size)) {
|
|
const [h = 0, v = 0] = size
|
|
horizontalSize.value = h
|
|
verticalSize.value = v
|
|
} else {
|
|
let val: number
|
|
if (isNumber(size)) {
|
|
val = size as number
|
|
} else {
|
|
val = SizeMap[size as string] || SizeMap.small
|
|
}
|
|
|
|
if (wrap && dir === 'horizontal') {
|
|
horizontalSize.value = verticalSize.value = val
|
|
} else {
|
|
if (dir === 'horizontal') {
|
|
horizontalSize.value = val
|
|
verticalSize.value = 0
|
|
} else {
|
|
verticalSize.value = val
|
|
horizontalSize.value = 0
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{ immediate: true },
|
|
)
|
|
|
|
const containerStyle = computed(() => {
|
|
const wrapKls: CSSProperties = props.wrap
|
|
? { flexWrap: 'wrap', marginBottom: `-${verticalSize.value}px` }
|
|
: null
|
|
const alignment: CSSProperties = {
|
|
alignItems: props.alignment,
|
|
}
|
|
return [wrapKls, alignment, props.style] as Array<CSSProperties>
|
|
})
|
|
|
|
const itemStyle = computed(() => {
|
|
return {
|
|
paddingBottom: `${verticalSize.value}px`,
|
|
marginRight: `${horizontalSize.value}px`,
|
|
}
|
|
})
|
|
|
|
return {
|
|
classes,
|
|
containerStyle,
|
|
itemStyle,
|
|
}
|
|
}
|