mirror of
				https://github.com/antd-tiny-vue/antd-tiny-vue.git
				synced 2025-10-31 16:51:45 +08:00 
			
		
		
		
	feat: add space
This commit is contained in:
		
							
								
								
									
										12
									
								
								components/_util/hooks/flex-gap-support.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								components/_util/hooks/flex-gap-support.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | import { useState } from '@v-c/utils' | ||||||
|  | import { onMounted } from 'vue' | ||||||
|  | import { detectFlexGapSupported } from '../style-checker' | ||||||
|  |  | ||||||
|  | export default () => { | ||||||
|  |   const [flexible, setFlexible] = useState(false) | ||||||
|  |  | ||||||
|  |   onMounted(() => { | ||||||
|  |     setFlexible(detectFlexGapSupported()) | ||||||
|  |   }) | ||||||
|  |   return flexible | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								components/_util/style-checker.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								components/_util/style-checker.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | import { canUseDom } from '@v-c/utils' | ||||||
|  |  | ||||||
|  | export const canUseDocElement = () => | ||||||
|  |   canUseDom() && window.document.documentElement | ||||||
|  |  | ||||||
|  | let flexGapSupported: boolean | ||||||
|  | export const detectFlexGapSupported = () => { | ||||||
|  |   if (!canUseDocElement()) { | ||||||
|  |     return false | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (flexGapSupported !== undefined) { | ||||||
|  |     return flexGapSupported | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // create flex container with row-gap set | ||||||
|  |   const flex = document.createElement('div') | ||||||
|  |   flex.style.display = 'flex' | ||||||
|  |   flex.style.flexDirection = 'column' | ||||||
|  |   flex.style.rowGap = '1px' | ||||||
|  |  | ||||||
|  |   // create two, elements inside it | ||||||
|  |   flex.appendChild(document.createElement('div')) | ||||||
|  |   flex.appendChild(document.createElement('div')) | ||||||
|  |  | ||||||
|  |   // append to the DOM (needed to obtain scrollHeight) | ||||||
|  |   document.body.appendChild(flex) | ||||||
|  |   flexGapSupported = flex.scrollHeight === 1 // flex container should be 1px high from the row-gap | ||||||
|  |   document.body.removeChild(flex) | ||||||
|  |  | ||||||
|  |   return flexGapSupported | ||||||
|  | } | ||||||
| @@ -53,9 +53,13 @@ const Button = defineComponent({ | |||||||
|       direction |       direction | ||||||
|     ) |     ) | ||||||
|     const sizeCls = computed(() => { |     const sizeCls = computed(() => { | ||||||
|       const sizeClassNameMap = { large: 'lg', small: 'sm', middle: undefined } |       const sizeClassNameMap: Record<string, any> = { | ||||||
|  |         large: 'lg', | ||||||
|  |         small: 'sm', | ||||||
|  |         middle: undefined | ||||||
|  |       } | ||||||
|       const sizeFullname = compactSize?.value || size.value |       const sizeFullname = compactSize?.value || size.value | ||||||
|       return sizeClassNameMap[sizeFullname!] |       return sizeClassNameMap[sizeFullname] | ||||||
|     }) |     }) | ||||||
|     const disabled = useDisabled(props) |     const disabled = useDisabled(props) | ||||||
|     const buttonRef = shallowRef<HTMLButtonElement | null>(null) |     const buttonRef = shallowRef<HTMLButtonElement | null>(null) | ||||||
|   | |||||||
| @@ -14,12 +14,12 @@ title: Type | |||||||
| There are `primary` button, `default` button, `dashed` button, `text` button and `link` button in antd. | There are `primary` button, `default` button, `dashed` button, `text` button and `link` button in antd. | ||||||
| </docs> | </docs> | ||||||
|  |  | ||||||
| <script setup lang="ts"></script> |  | ||||||
|  |  | ||||||
| <template> | <template> | ||||||
|   <a-button type="primary">Primary Button</a-button> |   <a-space wrap> | ||||||
|   <a-button>Default Button</a-button> |     <a-button type="primary">Primary Button</a-button> | ||||||
|   <a-button type="dashed">Dashed Button</a-button> |     <a-button>Default Button</a-button> | ||||||
|   <a-button type="text">Text Button</a-button> |     <a-button type="dashed">Dashed Button</a-button> | ||||||
|   <a-button type="link">Link Button</a-button> |     <a-button type="text">Text Button</a-button> | ||||||
|  |     <a-button type="link">Link Button</a-button> | ||||||
|  |   </a-space> | ||||||
| </template> | </template> | ||||||
|   | |||||||
| @@ -49,7 +49,6 @@ It accepts all props which native buttons support. | |||||||
|  |  | ||||||
| ## Design Token | ## Design Token | ||||||
|  |  | ||||||
| <ComponentTokenTable component="Button"></ComponentTokenTable> |  | ||||||
|  |  | ||||||
| ## FAQ | ## FAQ | ||||||
|  |  | ||||||
|   | |||||||
| @@ -54,7 +54,6 @@ | |||||||
|  |  | ||||||
| ## Design Token | ## Design Token | ||||||
|  |  | ||||||
| <ComponentTokenTable component="Button"></ComponentTokenTable> |  | ||||||
|  |  | ||||||
| ## FAQ | ## FAQ | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,2 +1,3 @@ | |||||||
| export { default as Button } from './button' | export { default as Button } from './button' | ||||||
| export { default as ConfigProvider } from './config-provider' | export { default as ConfigProvider } from './config-provider' | ||||||
|  | export { default as Space } from './space' | ||||||
|   | |||||||
| @@ -1,41 +0,0 @@ | |||||||
| import { classNames, createInjectionState } from '@v-c/utils' |  | ||||||
| import type { Ref } from 'vue' |  | ||||||
| import { computed } from 'vue' |  | ||||||
| import type { DirectionType } from '../config-provider' |  | ||||||
|  |  | ||||||
| const spaceCompactItem = () => { |  | ||||||
|   return { |  | ||||||
|     compactDirection: computed(() => null), |  | ||||||
|     isFirstItem: computed(() => null), |  | ||||||
|     isLastItem: computed(() => null), |  | ||||||
|     compactSize: computed(() => null) |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export const [useSpaceCompactProvider, useSpaceCompactInject] = createInjectionState(spaceCompactItem) |  | ||||||
|  |  | ||||||
| export const useSpaceCompactItemState = (): ReturnType<typeof spaceCompactItem> | undefined => useSpaceCompactInject() |  | ||||||
|  |  | ||||||
| export const useCompactItemContext = (prefixCls: Ref<string>, direction: Ref<DirectionType>) => { |  | ||||||
|   const compactItemContext = useSpaceCompactItemState() |  | ||||||
|  |  | ||||||
|   const compactItemClassnames = computed(() => { |  | ||||||
|     if (!compactItemContext) return '' |  | ||||||
|  |  | ||||||
|     const { compactDirection, isFirstItem, isLastItem } = compactItemContext |  | ||||||
|     const separator = compactDirection.value === 'vertical' ? '-vertical-' : '-' |  | ||||||
|  |  | ||||||
|     return classNames({ |  | ||||||
|       [`${prefixCls.value}-compact${separator}item`]: true, |  | ||||||
|       [`${prefixCls.value}-compact${separator}first-item`]: isFirstItem.value, |  | ||||||
|       [`${prefixCls.value}-compact${separator}last-item`]: isLastItem.value, |  | ||||||
|       [`${prefixCls.value}-compact${separator}item-rtl`]: direction.value === 'rtl' |  | ||||||
|     }) |  | ||||||
|   }) |  | ||||||
|  |  | ||||||
|   return { |  | ||||||
|     compactSize: compactItemContext?.compactSize, |  | ||||||
|     compactDirection: compactItemContext?.compactDirection, |  | ||||||
|     compactItemClassnames |  | ||||||
|   } |  | ||||||
| } |  | ||||||
							
								
								
									
										142
									
								
								components/space/compact.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								components/space/compact.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | |||||||
|  | import { | ||||||
|  |   anyType, | ||||||
|  |   booleanType, | ||||||
|  |   classNames, | ||||||
|  |   createInjectionState, | ||||||
|  |   filterEmpty, | ||||||
|  |   isObject, | ||||||
|  |   stringType | ||||||
|  | } from '@v-c/utils' | ||||||
|  | import type { Ref } from 'vue' | ||||||
|  | import { computed, defineComponent } from 'vue' | ||||||
|  | import type { DirectionType } from '../config-provider' | ||||||
|  | import type { SizeType } from '../config-provider/context' | ||||||
|  | import { useProviderConfigState } from '../config-provider/context' | ||||||
|  | import useStyle from './style' | ||||||
|  |  | ||||||
|  | const spaceCompactItem = (props: any) => { | ||||||
|  |   return { | ||||||
|  |     compactDirection: computed(() => props.compactDirection), | ||||||
|  |     isFirstItem: computed(() => props.isFirstItem), | ||||||
|  |     isLastItem: computed(() => props.isLastItem), | ||||||
|  |     compactSize: computed(() => props.compactSize) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const [useSpaceCompactProvider, useSpaceCompactInject] = | ||||||
|  |   createInjectionState(spaceCompactItem) | ||||||
|  |  | ||||||
|  | export const useSpaceCompactItemState = (): | ||||||
|  |   | ReturnType<typeof spaceCompactItem> | ||||||
|  |   | undefined => useSpaceCompactInject() | ||||||
|  |  | ||||||
|  | export const useCompactItemContext = ( | ||||||
|  |   prefixCls: Ref<string>, | ||||||
|  |   direction: Ref<DirectionType> | ||||||
|  | ) => { | ||||||
|  |   const compactItemContext = useSpaceCompactItemState() | ||||||
|  |  | ||||||
|  |   const compactItemClassnames = computed(() => { | ||||||
|  |     if (!compactItemContext) return '' | ||||||
|  |  | ||||||
|  |     const { compactDirection, isFirstItem, isLastItem } = compactItemContext | ||||||
|  |     const separator = compactDirection.value === 'vertical' ? '-vertical-' : '-' | ||||||
|  |  | ||||||
|  |     return classNames({ | ||||||
|  |       [`${prefixCls.value}-compact${separator}item`]: true, | ||||||
|  |       [`${prefixCls.value}-compact${separator}first-item`]: isFirstItem.value, | ||||||
|  |       [`${prefixCls.value}-compact${separator}last-item`]: isLastItem.value, | ||||||
|  |       [`${prefixCls.value}-compact${separator}item-rtl`]: | ||||||
|  |         direction.value === 'rtl' | ||||||
|  |     }) | ||||||
|  |   }) | ||||||
|  |  | ||||||
|  |   return { | ||||||
|  |     compactSize: compactItemContext?.compactSize, | ||||||
|  |     compactDirection: compactItemContext?.compactDirection, | ||||||
|  |     compactItemClassnames | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const CompactItem = defineComponent({ | ||||||
|  |   name: 'CompactItem', | ||||||
|  |   inheritAttrs: false, | ||||||
|  |   props: { | ||||||
|  |     compactSize: anyType<SizeType>(), | ||||||
|  |     compactDirection: stringType<'horizontal' | 'vertical'>(), | ||||||
|  |     isFirstItem: booleanType(), | ||||||
|  |     isLastItem: booleanType() | ||||||
|  |   }, | ||||||
|  |   setup(props, { slots }) { | ||||||
|  |     useSpaceCompactProvider(props) | ||||||
|  |     return () => slots.default?.() | ||||||
|  |   } | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | export const spaceCompactProps = { | ||||||
|  |   prefixCls: stringType(), | ||||||
|  |   size: anyType<SizeType>('middle'), | ||||||
|  |   direction: stringType<'horizontal' | 'vertical'>(), | ||||||
|  |   block: anyType<boolean>(), | ||||||
|  |   rootClassName: stringType() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const Compact = defineComponent({ | ||||||
|  |   name: 'Compact', | ||||||
|  |   inheritAttrs: false, | ||||||
|  |   props: spaceCompactProps, | ||||||
|  |   setup(props, { slots, attrs }) { | ||||||
|  |     const { getPrefixCls, direction: directionConfig } = | ||||||
|  |       useProviderConfigState() | ||||||
|  |     const prefixCls = computed(() => | ||||||
|  |       getPrefixCls('space-compact', props.prefixCls) | ||||||
|  |     ) | ||||||
|  |     const [wrapSSR, hashId] = useStyle(prefixCls) | ||||||
|  |     const compactItemContext = useSpaceCompactItemState() | ||||||
|  |     return () => { | ||||||
|  |       const childNodes = filterEmpty(slots.default?.()) | ||||||
|  |       if (childNodes.length === 0) return null | ||||||
|  |       const { rootClassName, size, direction } = props | ||||||
|  |       const cls = classNames( | ||||||
|  |         prefixCls.value, | ||||||
|  |         hashId.value, | ||||||
|  |         { | ||||||
|  |           [`${prefixCls.value}-rtl`]: directionConfig.value === 'rtl', | ||||||
|  |           [`${prefixCls.value}-block`]: props.block, | ||||||
|  |           [`${prefixCls.value}-vertical`]: props.direction === 'vertical' | ||||||
|  |         }, | ||||||
|  |         attrs.class, | ||||||
|  |         rootClassName | ||||||
|  |       ) | ||||||
|  |       const nodes = childNodes.map((child, index) => { | ||||||
|  |         const key = | ||||||
|  |           (isObject(child) && (child as any).key) || | ||||||
|  |           `${prefixCls.value}-item-${index}` | ||||||
|  |         return ( | ||||||
|  |           <CompactItem | ||||||
|  |             key={key} | ||||||
|  |             compactSize={size} | ||||||
|  |             compactDirection={direction} | ||||||
|  |             isFirstItem={ | ||||||
|  |               (index === 0 && !compactItemContext) || | ||||||
|  |               compactItemContext?.isFirstItem.value | ||||||
|  |             } | ||||||
|  |             isLastItem={ | ||||||
|  |               index === childNodes.length - 1 && | ||||||
|  |               (!compactItemContext || compactItemContext?.isLastItem.value) | ||||||
|  |             } | ||||||
|  |           > | ||||||
|  |             {child} | ||||||
|  |           </CompactItem> | ||||||
|  |         ) | ||||||
|  |       }) | ||||||
|  |       return wrapSSR( | ||||||
|  |         <div {...attrs} class={cls}> | ||||||
|  |           {nodes} | ||||||
|  |         </div> | ||||||
|  |       ) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | export default Compact | ||||||
							
								
								
									
										157
									
								
								components/space/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								components/space/index.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,157 @@ | |||||||
|  | import { | ||||||
|  |   anyType, | ||||||
|  |   booleanType, | ||||||
|  |   classNames, | ||||||
|  |   createInjectionState, | ||||||
|  |   filterEmpty, | ||||||
|  |   isObject, | ||||||
|  |   stringType, | ||||||
|  |   vNodeType | ||||||
|  | } from '@v-c/utils' | ||||||
|  | import type { App, CSSProperties } from 'vue' | ||||||
|  | import { computed, defineComponent, shallowRef } from 'vue' | ||||||
|  | import type { SizeType } from '../config-provider/context' | ||||||
|  | import { useProviderConfigState } from '../config-provider/context' | ||||||
|  | import useFlexGapSupport from '../_util/hooks/flex-gap-support' | ||||||
|  | import useStyle from './style' | ||||||
|  | import Item from './item' | ||||||
|  | import Compact from './compact' | ||||||
|  |  | ||||||
|  | export type SpaceSize = SizeType | number | ||||||
|  |  | ||||||
|  | const spaceState = function ({ sizes, supportFlexGap, latestIndex }: any) { | ||||||
|  |   return { | ||||||
|  |     latestIndex: computed(() => latestIndex.value), | ||||||
|  |     horizontalSize: computed(() => sizes[0]), | ||||||
|  |     verticalSize: computed(() => sizes[1]), | ||||||
|  |     supportFlexGap: computed(() => supportFlexGap.value) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const [useSpaceProvider, useSpaceInject] = | ||||||
|  |   createInjectionState(spaceState) | ||||||
|  |  | ||||||
|  | export const useSpaceContextState = () => | ||||||
|  |   useSpaceInject() ?? { | ||||||
|  |     latestIndex: computed(() => 0), | ||||||
|  |     horizontalSize: computed(() => 0), | ||||||
|  |     verticalSize: computed(() => 0), | ||||||
|  |     supportFlexGap: computed(() => false) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | export const spaceProps = { | ||||||
|  |   prefixCls: stringType(), | ||||||
|  |   rootClassName: stringType(), | ||||||
|  |   size: anyType<SizeType | [SpaceSize, SpaceSize]>('small'), | ||||||
|  |   direction: anyType<'horizontal' | 'vertical'>('horizontal'), | ||||||
|  |   align: stringType<'start' | 'end' | 'center' | 'baseline'>(), | ||||||
|  |   split: vNodeType(), | ||||||
|  |   wrap: booleanType(false) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const spaceSize = { | ||||||
|  |   small: 8, | ||||||
|  |   middle: 16, | ||||||
|  |   large: 24 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function getNumberSize(size: SpaceSize) { | ||||||
|  |   return typeof size === 'string' ? spaceSize[size] : size || 0 | ||||||
|  | } | ||||||
|  | const Space = defineComponent({ | ||||||
|  |   name: 'ASpace', | ||||||
|  |   inheritAttrs: false, | ||||||
|  |   props: spaceProps, | ||||||
|  |   setup(props, { attrs, slots }) { | ||||||
|  |     const { getPrefixCls, direction: directionConfig } = | ||||||
|  |       useProviderConfigState() | ||||||
|  |     const supportFlexGap = useFlexGapSupport() | ||||||
|  |     const prefixCls = computed(() => getPrefixCls('space', props.prefixCls)) | ||||||
|  |     const [wrapSSR, hashId] = useStyle(prefixCls) | ||||||
|  |     const sizes = computed<[SpaceSize, SpaceSize]>(() => { | ||||||
|  |       const { size } = props | ||||||
|  |       if (Array.isArray(size)) { | ||||||
|  |         return size.map(getNumberSize) as [SpaceSize, SpaceSize] | ||||||
|  |       } | ||||||
|  |       return [getNumberSize(size), getNumberSize(size)] as [ | ||||||
|  |         SpaceSize, | ||||||
|  |         SpaceSize | ||||||
|  |       ] | ||||||
|  |     }) | ||||||
|  |     const latestIndex = shallowRef(0) | ||||||
|  |  | ||||||
|  |     useSpaceProvider({ sizes, supportFlexGap, latestIndex }) | ||||||
|  |  | ||||||
|  |     return () => { | ||||||
|  |       const { align, direction, rootClassName, split, wrap } = props | ||||||
|  |       const childNodes = filterEmpty(slots.default?.()) | ||||||
|  |       const mergedAlign = | ||||||
|  |         align === undefined && direction === 'horizontal' ? 'center' : align | ||||||
|  |       const cn = classNames( | ||||||
|  |         prefixCls.value, | ||||||
|  |         hashId.value, | ||||||
|  |         `${prefixCls.value}-${direction}`, | ||||||
|  |         { | ||||||
|  |           [`${prefixCls.value}-rtl`]: directionConfig.value === 'rtl', | ||||||
|  |           [`${prefixCls.value}-align-${mergedAlign}`]: mergedAlign | ||||||
|  |         }, | ||||||
|  |         attrs.class, | ||||||
|  |         rootClassName | ||||||
|  |       ) | ||||||
|  |       const itemClassName = `${prefixCls.value}-item` | ||||||
|  |       const marginDirection = | ||||||
|  |         directionConfig.value === 'rtl' ? 'marginLeft' : 'marginRight' | ||||||
|  |       const nodes = childNodes.map((child, i) => { | ||||||
|  |         if (child !== null && child !== undefined) { | ||||||
|  |           latestIndex.value = i | ||||||
|  |         } | ||||||
|  |         const key = | ||||||
|  |           (isObject(child) && (child as any).key) || `${itemClassName}-${i}` | ||||||
|  |         return ( | ||||||
|  |           <Item | ||||||
|  |             class={itemClassName} | ||||||
|  |             key={key} | ||||||
|  |             direction={direction} | ||||||
|  |             index={i} | ||||||
|  |             marginDirection={marginDirection} | ||||||
|  |             split={split} | ||||||
|  |             wrap={wrap} | ||||||
|  |           > | ||||||
|  |             {child} | ||||||
|  |           </Item> | ||||||
|  |         ) | ||||||
|  |       }) | ||||||
|  |  | ||||||
|  |       // =========================== Render =========================== | ||||||
|  |       if (childNodes.length === 0) { | ||||||
|  |         return null | ||||||
|  |       } | ||||||
|  |       const gapStyle: CSSProperties = {} | ||||||
|  |       if (wrap) { | ||||||
|  |         gapStyle.flexWrap = 'wrap' | ||||||
|  |         if (!supportFlexGap.value) { | ||||||
|  |           gapStyle.marginBottom = `-${sizes.value[1]}px` | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       if (supportFlexGap.value) { | ||||||
|  |         gapStyle.columnGap = `${sizes.value[0]}px` | ||||||
|  |         gapStyle.rowGap = `${sizes.value[1]}px` | ||||||
|  |       } | ||||||
|  |       return wrapSSR( | ||||||
|  |         <div {...attrs} class={cn} style={[gapStyle, (attrs as any).style]}> | ||||||
|  |           {nodes} | ||||||
|  |         </div> | ||||||
|  |       ) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | Space.install = function (app: App) { | ||||||
|  |   app.component('ASpace', Space) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Space.Compact = Compact | ||||||
|  | export default Space as typeof Space & | ||||||
|  |   Plugin & { | ||||||
|  |     readonly Compact: typeof Compact | ||||||
|  |   } | ||||||
							
								
								
									
										74
									
								
								components/space/item.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								components/space/item.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | |||||||
|  | import { | ||||||
|  |   booleanType, | ||||||
|  |   filterEmpty, | ||||||
|  |   numberType, | ||||||
|  |   someType, | ||||||
|  |   stringType, | ||||||
|  |   vNodeType | ||||||
|  | } from '@v-c/utils' | ||||||
|  | import type { CSSProperties, ExtractPropTypes, VNodeChild } from 'vue' | ||||||
|  | import { defineComponent } from 'vue' | ||||||
|  | import { useSpaceContextState } from './index' | ||||||
|  |  | ||||||
|  | export const itemProps = { | ||||||
|  |   className: stringType(), | ||||||
|  |   children: vNodeType(), | ||||||
|  |   index: numberType(), | ||||||
|  |   direction: stringType<'horizontal' | 'vertical'>(), | ||||||
|  |   marginDirection: stringType<'marginLeft' | 'marginRight'>(), | ||||||
|  |   split: someType<string | (() => VNodeChild) | VNodeChild>([ | ||||||
|  |     String, | ||||||
|  |     Function, | ||||||
|  |     Object | ||||||
|  |   ]), | ||||||
|  |   wrap: booleanType() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export type ItemProps = ExtractPropTypes<typeof itemProps> | ||||||
|  |  | ||||||
|  | const Item = defineComponent({ | ||||||
|  |   name: 'VcSpaceItem', | ||||||
|  |   props: itemProps, | ||||||
|  |   setup(props, { attrs, slots }) { | ||||||
|  |     const { supportFlexGap, latestIndex, verticalSize, horizontalSize } = | ||||||
|  |       useSpaceContextState() | ||||||
|  |     return () => { | ||||||
|  |       const { direction, index, marginDirection, split, wrap } = props | ||||||
|  |       const children = slots.default?.() | ||||||
|  |       if (!children || filterEmpty(children).length === 0) { | ||||||
|  |         return null | ||||||
|  |       } | ||||||
|  |       let style: CSSProperties = {} | ||||||
|  |       if (!supportFlexGap.value) { | ||||||
|  |         if (direction === 'vertical') { | ||||||
|  |           if (index < latestIndex.value) { | ||||||
|  |             style.marginBottom = `${horizontalSize.value / (split ? 2 : 1)}px` | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           style = { | ||||||
|  |             ...(index < latestIndex.value && | ||||||
|  |               ({ | ||||||
|  |                 [marginDirection]: `${horizontalSize.value / (split ? 2 : 1)}px` | ||||||
|  |               } as CSSProperties)), | ||||||
|  |             ...(wrap && { paddingBottom: `${verticalSize.value}px` }) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       return ( | ||||||
|  |         <> | ||||||
|  |           <div class={attrs.class} style={style}> | ||||||
|  |             {children} | ||||||
|  |           </div> | ||||||
|  |           {index < latestIndex.value && split && ( | ||||||
|  |             <span class={`${attrs.class}-split`} style={style}> | ||||||
|  |               {split} | ||||||
|  |             </span> | ||||||
|  |           )} | ||||||
|  |         </> | ||||||
|  |       ) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | export default Item | ||||||
		Reference in New Issue
	
	Block a user