mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-12-02 03:59:01 +08:00
feat: Space add wrap (#27910)
* feat: Space add wrap
* improve
* fix
* Update index.tsx
* change doc
* change docs
* change docs
* 😂
* improve
* change doc
* improve code
* Update Item.tsx
This commit is contained in:
parent
d86c8c857e
commit
94f2ae9e87
@ -1,46 +1,44 @@
|
||||
import * as React from 'react';
|
||||
import { LastIndexContext } from '.';
|
||||
import { SizeType } from '../config-provider/SizeContext';
|
||||
|
||||
const spaceSize = {
|
||||
small: 8,
|
||||
middle: 16,
|
||||
large: 24,
|
||||
};
|
||||
import { SpaceContext } from '.';
|
||||
|
||||
export interface ItemProps {
|
||||
className: string;
|
||||
children: React.ReactNode;
|
||||
index: number;
|
||||
direction?: 'horizontal' | 'vertical';
|
||||
size?: SizeType | number;
|
||||
marginDirection: 'marginLeft' | 'marginRight';
|
||||
split?: string | React.ReactNode;
|
||||
wrap?: boolean;
|
||||
}
|
||||
|
||||
export default function Item({
|
||||
className,
|
||||
direction,
|
||||
index,
|
||||
size,
|
||||
marginDirection,
|
||||
children,
|
||||
split,
|
||||
wrap,
|
||||
}: ItemProps) {
|
||||
const latestIndex = React.useContext(LastIndexContext);
|
||||
const { horizontalSize, verticalSize, latestIndex } = React.useContext(SpaceContext);
|
||||
|
||||
let style: React.CSSProperties = {};
|
||||
|
||||
if (direction === 'vertical') {
|
||||
if (index < latestIndex) {
|
||||
style = { marginBottom: horizontalSize / (split ? 2 : 1) };
|
||||
}
|
||||
} else {
|
||||
style = {
|
||||
...(index < latestIndex && { [marginDirection]: horizontalSize / (split ? 2 : 1) }),
|
||||
...(wrap && { paddingBottom: verticalSize }),
|
||||
};
|
||||
}
|
||||
|
||||
if (children === null || children === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const style =
|
||||
index >= latestIndex
|
||||
? {}
|
||||
: {
|
||||
[direction === 'vertical' ? 'marginBottom' : marginDirection]:
|
||||
((typeof size === 'string' ? spaceSize[size] : size) ?? 0) / (split ? 2 : 1),
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={className} style={style}>
|
||||
|
@ -657,3 +657,271 @@ exports[`renders ./components/space/demo/vertical.md correctly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/space/demo/wrap.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
style="flex-wrap:wrap;margin-bottom:-16px"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px;padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="padding-bottom:16px"
|
||||
>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
31
components/space/demo/wrap.md
Normal file
31
components/space/demo/wrap.md
Normal file
@ -0,0 +1,31 @@
|
||||
---
|
||||
order: 98
|
||||
title:
|
||||
zh-CN: 自动换行
|
||||
en-US: Wrap
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
自动换行。
|
||||
|
||||
## en-US
|
||||
|
||||
Auto wrap line.
|
||||
|
||||
```jsx
|
||||
import { Space, Button } from 'antd';
|
||||
|
||||
const Demo = () => {
|
||||
return (
|
||||
<Space size={[8, 16]} wrap>
|
||||
{new Array(20).fill(null).map((_, index) => (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<Button key={index}>Button</Button>
|
||||
))}
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
|
||||
ReactDOM.render(<Demo />, mountNode);
|
||||
```
|
@ -18,5 +18,10 @@ Avoid components clinging together and set a unified space.
|
||||
| --- | --- | --- | --- | --- |
|
||||
| align | Align items | `start` \| `end` \|`center` \|`baseline` | - | 4.2.0 |
|
||||
| direction | The space direction | `vertical` \| `horizontal` | `horizontal` | 4.1.0 |
|
||||
| size | The space size | `small` \| `middle` \| `large` \| number | `small` | 4.1.0 |
|
||||
| size | The space size | [Size](#Size) \| [Size\[\]](#Size) | `small` | 4.1.0 \| Array: 4.9.0 |
|
||||
| split | Set split | ReactNode | - | 4.7.0 |
|
||||
| wrap | Auto wrap line, when `horizontal` effective | boolean | false | 4.9.0 |
|
||||
|
||||
### Size
|
||||
|
||||
`'small' | 'middle' | 'large' | number`
|
||||
|
@ -5,17 +5,34 @@ import { ConfigContext } from '../config-provider';
|
||||
import { SizeType } from '../config-provider/SizeContext';
|
||||
import Item from './Item';
|
||||
|
||||
export const LastIndexContext = React.createContext(0);
|
||||
export const SpaceContext = React.createContext({
|
||||
latestIndex: 0,
|
||||
horizontalSize: 0,
|
||||
verticalSize: 0,
|
||||
});
|
||||
|
||||
export type SpaceSize = SizeType | number;
|
||||
|
||||
export interface SpaceProps {
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
size?: SizeType | number;
|
||||
size?: SpaceSize | [SpaceSize, SpaceSize];
|
||||
direction?: 'horizontal' | 'vertical';
|
||||
// No `stretch` since many components do not support that.
|
||||
align?: 'start' | 'end' | 'center' | 'baseline';
|
||||
split?: React.ReactNode;
|
||||
wrap?: boolean;
|
||||
}
|
||||
|
||||
const spaceSize = {
|
||||
small: 8,
|
||||
middle: 16,
|
||||
large: 24,
|
||||
};
|
||||
|
||||
function getNumberSize(size: SpaceSize) {
|
||||
return typeof size === 'string' ? spaceSize[size] : size || 0;
|
||||
}
|
||||
|
||||
const Space: React.FC<SpaceProps> = props => {
|
||||
@ -29,9 +46,19 @@ const Space: React.FC<SpaceProps> = props => {
|
||||
direction = 'horizontal',
|
||||
prefixCls: customizePrefixCls,
|
||||
split,
|
||||
style,
|
||||
wrap = false,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
const [horizontalSize, verticalSize] = React.useMemo(
|
||||
() =>
|
||||
((Array.isArray(size) ? size : [size, size]) as [SpaceSize, SpaceSize]).map(item =>
|
||||
getNumberSize(item),
|
||||
),
|
||||
[size],
|
||||
);
|
||||
|
||||
const childNodes = toArray(children, { keepEmpty: true });
|
||||
|
||||
if (childNodes.length === 0) {
|
||||
@ -67,10 +94,10 @@ const Space: React.FC<SpaceProps> = props => {
|
||||
className={itemClassName}
|
||||
key={`${itemClassName}-${i}`}
|
||||
direction={direction}
|
||||
size={size}
|
||||
index={i}
|
||||
marginDirection={marginDirection}
|
||||
split={split}
|
||||
wrap={wrap}
|
||||
>
|
||||
{child}
|
||||
</Item>
|
||||
@ -79,8 +106,17 @@ const Space: React.FC<SpaceProps> = props => {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={cn} {...otherProps}>
|
||||
<LastIndexContext.Provider value={latestIndex}>{nodes}</LastIndexContext.Provider>
|
||||
<div
|
||||
className={cn}
|
||||
style={{
|
||||
...(wrap && { flexWrap: 'wrap', marginBottom: -verticalSize }),
|
||||
...style,
|
||||
}}
|
||||
{...otherProps}
|
||||
>
|
||||
<SpaceContext.Provider value={{ horizontalSize, verticalSize, latestIndex }}>
|
||||
{nodes}
|
||||
</SpaceContext.Provider>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -22,5 +22,10 @@ cover: https://gw.alipayobjects.com/zos/antfincdn/wc6%263gJ0Y8/Space.svg
|
||||
| --- | --- | --- | --- | --- |
|
||||
| align | 对齐方式 | `start` \| `end` \|`center` \|`baseline` | - | 4.2.0 |
|
||||
| direction | 间距方向 | `vertical` \| `horizontal` | `horizontal` | 4.1.0 |
|
||||
| size | 间距大小 | `small` \| `middle` \| `large` \| number | `small` | 4.1.0 |
|
||||
| size | 间距大小 | [Size](#Size) \| [Size\[\]](#Size) | `small` | 4.1.0 \| Array: 4.9.0 |
|
||||
| split | 设置拆分 | ReactNode | - | 4.7.0 |
|
||||
| wrap | 是否自动换行,仅在 `horizontal` 时有效 | boolean | false | 4.9.0 |
|
||||
|
||||
### Size
|
||||
|
||||
`'small' | 'middle' | 'large' | number`
|
||||
|
Loading…
Reference in New Issue
Block a user