mirror of
https://github.com/ant-design/ant-design.git
synced 2025-06-11 03:22:59 +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 * as React from 'react';
|
||||||
import { LastIndexContext } from '.';
|
import { SpaceContext } from '.';
|
||||||
import { SizeType } from '../config-provider/SizeContext';
|
|
||||||
|
|
||||||
const spaceSize = {
|
|
||||||
small: 8,
|
|
||||||
middle: 16,
|
|
||||||
large: 24,
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface ItemProps {
|
export interface ItemProps {
|
||||||
className: string;
|
className: string;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
index: number;
|
index: number;
|
||||||
direction?: 'horizontal' | 'vertical';
|
direction?: 'horizontal' | 'vertical';
|
||||||
size?: SizeType | number;
|
|
||||||
marginDirection: 'marginLeft' | 'marginRight';
|
marginDirection: 'marginLeft' | 'marginRight';
|
||||||
split?: string | React.ReactNode;
|
split?: string | React.ReactNode;
|
||||||
|
wrap?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Item({
|
export default function Item({
|
||||||
className,
|
className,
|
||||||
direction,
|
direction,
|
||||||
index,
|
index,
|
||||||
size,
|
|
||||||
marginDirection,
|
marginDirection,
|
||||||
children,
|
children,
|
||||||
split,
|
split,
|
||||||
|
wrap,
|
||||||
}: ItemProps) {
|
}: 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) {
|
if (children === null || children === undefined) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const style =
|
|
||||||
index >= latestIndex
|
|
||||||
? {}
|
|
||||||
: {
|
|
||||||
[direction === 'vertical' ? 'marginBottom' : marginDirection]:
|
|
||||||
((typeof size === 'string' ? spaceSize[size] : size) ?? 0) / (split ? 2 : 1),
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={className} style={style}>
|
<div className={className} style={style}>
|
||||||
|
@ -657,3 +657,271 @@ exports[`renders ./components/space/demo/vertical.md correctly 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</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 |
|
| align | Align items | `start` \| `end` \|`center` \|`baseline` | - | 4.2.0 |
|
||||||
| direction | The space direction | `vertical` \| `horizontal` | `horizontal` | 4.1.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 |
|
| 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 { SizeType } from '../config-provider/SizeContext';
|
||||||
import Item from './Item';
|
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 {
|
export interface SpaceProps {
|
||||||
prefixCls?: string;
|
prefixCls?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
size?: SizeType | number;
|
size?: SpaceSize | [SpaceSize, SpaceSize];
|
||||||
direction?: 'horizontal' | 'vertical';
|
direction?: 'horizontal' | 'vertical';
|
||||||
// No `stretch` since many components do not support that.
|
// No `stretch` since many components do not support that.
|
||||||
align?: 'start' | 'end' | 'center' | 'baseline';
|
align?: 'start' | 'end' | 'center' | 'baseline';
|
||||||
split?: React.ReactNode;
|
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 => {
|
const Space: React.FC<SpaceProps> = props => {
|
||||||
@ -29,9 +46,19 @@ const Space: React.FC<SpaceProps> = props => {
|
|||||||
direction = 'horizontal',
|
direction = 'horizontal',
|
||||||
prefixCls: customizePrefixCls,
|
prefixCls: customizePrefixCls,
|
||||||
split,
|
split,
|
||||||
|
style,
|
||||||
|
wrap = false,
|
||||||
...otherProps
|
...otherProps
|
||||||
} = props;
|
} = 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 });
|
const childNodes = toArray(children, { keepEmpty: true });
|
||||||
|
|
||||||
if (childNodes.length === 0) {
|
if (childNodes.length === 0) {
|
||||||
@ -67,10 +94,10 @@ const Space: React.FC<SpaceProps> = props => {
|
|||||||
className={itemClassName}
|
className={itemClassName}
|
||||||
key={`${itemClassName}-${i}`}
|
key={`${itemClassName}-${i}`}
|
||||||
direction={direction}
|
direction={direction}
|
||||||
size={size}
|
|
||||||
index={i}
|
index={i}
|
||||||
marginDirection={marginDirection}
|
marginDirection={marginDirection}
|
||||||
split={split}
|
split={split}
|
||||||
|
wrap={wrap}
|
||||||
>
|
>
|
||||||
{child}
|
{child}
|
||||||
</Item>
|
</Item>
|
||||||
@ -79,8 +106,17 @@ const Space: React.FC<SpaceProps> = props => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn} {...otherProps}>
|
<div
|
||||||
<LastIndexContext.Provider value={latestIndex}>{nodes}</LastIndexContext.Provider>
|
className={cn}
|
||||||
|
style={{
|
||||||
|
...(wrap && { flexWrap: 'wrap', marginBottom: -verticalSize }),
|
||||||
|
...style,
|
||||||
|
}}
|
||||||
|
{...otherProps}
|
||||||
|
>
|
||||||
|
<SpaceContext.Provider value={{ horizontalSize, verticalSize, latestIndex }}>
|
||||||
|
{nodes}
|
||||||
|
</SpaceContext.Provider>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -22,5 +22,10 @@ cover: https://gw.alipayobjects.com/zos/antfincdn/wc6%263gJ0Y8/Space.svg
|
|||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| align | 对齐方式 | `start` \| `end` \|`center` \|`baseline` | - | 4.2.0 |
|
| align | 对齐方式 | `start` \| `end` \|`center` \|`baseline` | - | 4.2.0 |
|
||||||
| direction | 间距方向 | `vertical` \| `horizontal` | `horizontal` | 4.1.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 |
|
| 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