mirror of
https://github.com/ant-design/ant-design.git
synced 2025-06-08 01:53:34 +08:00
feat: Grid support row vertical gutter (#18979)
* row vertical gutter * run test
This commit is contained in:
parent
a5efb30b83
commit
a2edbc326f
@ -1,7 +1,7 @@
|
||||
import createContext, { Context } from '@ant-design/create-react-context';
|
||||
|
||||
export interface RowContextState {
|
||||
gutter?: number;
|
||||
gutter?: [number, number];
|
||||
}
|
||||
|
||||
const RowContext: Context<RowContextState> = createContext({});
|
||||
|
@ -414,6 +414,51 @@ exports[`renders ./components/grid/demo/gutter.md correctly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-row"
|
||||
style="margin-top:-10px;margin-bottom:-10px"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-col-6 gutter-row"
|
||||
style="padding-top:10px;padding-bottom:10px"
|
||||
>
|
||||
<div
|
||||
class="gutter-box"
|
||||
>
|
||||
col-6
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-col-6 gutter-row"
|
||||
style="padding-top:10px;padding-bottom:10px"
|
||||
>
|
||||
<div
|
||||
class="gutter-box"
|
||||
>
|
||||
col-6
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-col-6 gutter-row"
|
||||
style="padding-top:10px;padding-bottom:10px"
|
||||
>
|
||||
<div
|
||||
class="gutter-box"
|
||||
>
|
||||
col-6
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-col-6 gutter-row"
|
||||
style="padding-top:10px;padding-bottom:10px"
|
||||
>
|
||||
<div
|
||||
class="gutter-box"
|
||||
>
|
||||
col-6
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -467,7 +512,105 @@ exports[`renders ./components/grid/demo/playground.md correctly 1`] = `
|
||||
<span
|
||||
style="margin-right:6px"
|
||||
>
|
||||
Gutter (px):
|
||||
Horizontal Gutter (px):
|
||||
</span>
|
||||
<div
|
||||
style="width:50%"
|
||||
>
|
||||
<div
|
||||
class="ant-slider ant-slider-with-marks"
|
||||
>
|
||||
<div
|
||||
class="ant-slider-rail"
|
||||
/>
|
||||
<div
|
||||
class="ant-slider-track"
|
||||
style="left:0%;right:auto;width:20%"
|
||||
/>
|
||||
<div
|
||||
class="ant-slider-step"
|
||||
>
|
||||
<span
|
||||
class="ant-slider-dot ant-slider-dot-active"
|
||||
style="left:0%"
|
||||
/>
|
||||
<span
|
||||
class="ant-slider-dot ant-slider-dot-active"
|
||||
style="left:20%"
|
||||
/>
|
||||
<span
|
||||
class="ant-slider-dot"
|
||||
style="left:40%"
|
||||
/>
|
||||
<span
|
||||
class="ant-slider-dot"
|
||||
style="left:60%"
|
||||
/>
|
||||
<span
|
||||
class="ant-slider-dot"
|
||||
style="left:80%"
|
||||
/>
|
||||
<span
|
||||
class="ant-slider-dot"
|
||||
style="left:100%"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
aria-disabled="false"
|
||||
aria-valuemax="5"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="1"
|
||||
class="ant-slider-handle"
|
||||
role="slider"
|
||||
style="left:20%;right:auto;transform:translateX(-50%)"
|
||||
tabindex="0"
|
||||
/>
|
||||
<div
|
||||
class="ant-slider-mark"
|
||||
>
|
||||
<span
|
||||
class="ant-slider-mark-text ant-slider-mark-text-active"
|
||||
style="transform:translateX(-50%);-ms-transform:translateX(-50%);left:0%"
|
||||
>
|
||||
8
|
||||
</span>
|
||||
<span
|
||||
class="ant-slider-mark-text ant-slider-mark-text-active"
|
||||
style="transform:translateX(-50%);-ms-transform:translateX(-50%);left:20%"
|
||||
>
|
||||
16
|
||||
</span>
|
||||
<span
|
||||
class="ant-slider-mark-text"
|
||||
style="transform:translateX(-50%);-ms-transform:translateX(-50%);left:40%"
|
||||
>
|
||||
24
|
||||
</span>
|
||||
<span
|
||||
class="ant-slider-mark-text"
|
||||
style="transform:translateX(-50%);-ms-transform:translateX(-50%);left:60%"
|
||||
>
|
||||
32
|
||||
</span>
|
||||
<span
|
||||
class="ant-slider-mark-text"
|
||||
style="transform:translateX(-50%);-ms-transform:translateX(-50%);left:80%"
|
||||
>
|
||||
40
|
||||
</span>
|
||||
<span
|
||||
class="ant-slider-mark-text"
|
||||
style="transform:translateX(-50%);-ms-transform:translateX(-50%);left:100%"
|
||||
>
|
||||
48
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
style="margin-right:6px"
|
||||
>
|
||||
Vertical Gutter (px):
|
||||
</span>
|
||||
<div
|
||||
style="width:50%"
|
||||
@ -663,11 +806,11 @@ exports[`renders ./components/grid/demo/playground.md correctly 1`] = `
|
||||
</div>
|
||||
<div
|
||||
class="ant-row"
|
||||
style="margin-left:-8px;margin-right:-8px"
|
||||
style="margin-left:-8px;margin-right:-8px;margin-top:-8px;margin-bottom:-8px"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-col-6"
|
||||
style="padding-left:8px;padding-right:8px"
|
||||
style="padding-left:8px;padding-right:8px;padding-top:8px;padding-bottom:8px"
|
||||
>
|
||||
<div>
|
||||
Column
|
||||
@ -675,7 +818,7 @@ exports[`renders ./components/grid/demo/playground.md correctly 1`] = `
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-col-6"
|
||||
style="padding-left:8px;padding-right:8px"
|
||||
style="padding-left:8px;padding-right:8px;padding-top:8px;padding-bottom:8px"
|
||||
>
|
||||
<div>
|
||||
Column
|
||||
@ -683,7 +826,7 @@ exports[`renders ./components/grid/demo/playground.md correctly 1`] = `
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-col-6"
|
||||
style="padding-left:8px;padding-right:8px"
|
||||
style="padding-left:8px;padding-right:8px;padding-top:8px;padding-bottom:8px"
|
||||
>
|
||||
<div>
|
||||
Column
|
||||
@ -691,7 +834,44 @@ exports[`renders ./components/grid/demo/playground.md correctly 1`] = `
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-col-6"
|
||||
style="padding-left:8px;padding-right:8px"
|
||||
style="padding-left:8px;padding-right:8px;padding-top:8px;padding-bottom:8px"
|
||||
>
|
||||
<div>
|
||||
Column
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-row"
|
||||
style="margin-left:-8px;margin-right:-8px;margin-top:-8px;margin-bottom:-8px"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-col-6"
|
||||
style="padding-left:8px;padding-right:8px;padding-top:8px;padding-bottom:8px"
|
||||
>
|
||||
<div>
|
||||
Column
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-col-6"
|
||||
style="padding-left:8px;padding-right:8px;padding-top:8px;padding-bottom:8px"
|
||||
>
|
||||
<div>
|
||||
Column
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-col-6"
|
||||
style="padding-left:8px;padding-right:8px;padding-top:8px;padding-bottom:8px"
|
||||
>
|
||||
<div>
|
||||
Column
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-col-6"
|
||||
style="padding-left:8px;padding-right:8px;padding-top:8px;padding-bottom:8px"
|
||||
>
|
||||
<div>
|
||||
Column
|
||||
@ -699,7 +879,15 @@ exports[`renders ./components/grid/demo/playground.md correctly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<pre>
|
||||
<Row gutter={16}>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={6} />
|
||||
<Col span={6} />
|
||||
<Col span={6} />
|
||||
<Col span={6} />
|
||||
</Row>
|
||||
</pre>
|
||||
<pre>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={6} />
|
||||
<Col span={6} />
|
||||
<Col span={6} />
|
||||
|
@ -37,7 +37,7 @@ describe('Grid', () => {
|
||||
|
||||
it('when typeof getGutter is object', () => {
|
||||
const wrapper = mount(<Row gutter={{ xs: 8, sm: 16, md: 24 }} />);
|
||||
expect(wrapper.instance().getGutter()).toBe(8);
|
||||
expect(wrapper.instance().getGutter()).toEqual([8, 0]);
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
@ -75,8 +75,18 @@ describe('Grid', () => {
|
||||
.update()
|
||||
.find('div')
|
||||
.prop('style'),
|
||||
).toEqual(undefined);
|
||||
).toEqual({});
|
||||
wrapper.unmount();
|
||||
expect(enquire.unregister).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should work currect when gutter is array', () => {
|
||||
const wrapper = mount(<Row gutter={[16, 20]} />);
|
||||
expect(wrapper.find('div').prop('style')).toEqual({
|
||||
marginLeft: -8,
|
||||
marginRight: -8,
|
||||
marginTop: -10,
|
||||
marginBottom: -10,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -102,13 +102,25 @@ export default class Col extends React.Component<ColProps, {}> {
|
||||
<RowContext.Consumer>
|
||||
{({ gutter }) => {
|
||||
let { style } = others;
|
||||
if (gutter! > 0) {
|
||||
|
||||
if (gutter) {
|
||||
style = {
|
||||
paddingLeft: gutter! / 2,
|
||||
paddingRight: gutter! / 2,
|
||||
...(gutter[0]! > 0
|
||||
? {
|
||||
paddingLeft: gutter[0]! / 2,
|
||||
paddingRight: gutter[0]! / 2,
|
||||
}
|
||||
: {}),
|
||||
...(gutter[1]! > 0
|
||||
? {
|
||||
paddingTop: gutter[1]! / 2,
|
||||
paddingBottom: gutter[1]! / 2,
|
||||
}
|
||||
: {}),
|
||||
...style,
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<div {...others} style={style} className={classes}>
|
||||
{children}
|
||||
|
@ -11,12 +11,16 @@ title:
|
||||
|
||||
如果要支持响应式,可以写成 `{ xs: 8, sm: 16, md: 24, lg: 32 }`。
|
||||
|
||||
如果需要垂直间距,可以写成数组形式 `[水平间距, 垂直间距]` `[16, { xs: 8, sm: 16, md: 24, lg: 32 }]`。
|
||||
|
||||
## en-US
|
||||
|
||||
You can use the `gutter` property of `Row` as grid spacing, we recommend set it to `(16 + 8n) px`. (`n` stands for natural number.)
|
||||
|
||||
You can set it to a object like `{ xs: 8, sm: 16, md: 24, lg: 32 }` for responsive design.
|
||||
|
||||
You can use a array to set vertical spacing, `[horizontal, vertical]` `[16, { xs: 8, sm: 16, md: 24, lg: 32 }]`.
|
||||
|
||||
```jsx
|
||||
import { Row, Col } from 'antd';
|
||||
|
||||
@ -36,6 +40,20 @@ ReactDOM.render(
|
||||
<div className="gutter-box">col-6</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={[{ xs: 8, sm: 16, md: 24, lg: 32 }, 20]}>
|
||||
<Col className="gutter-row" span={6}>
|
||||
<div className="gutter-box">col-6</div>
|
||||
</Col>
|
||||
<Col className="gutter-row" span={6}>
|
||||
<div className="gutter-box">col-6</div>
|
||||
</Col>
|
||||
<Col className="gutter-row" span={6}>
|
||||
<div className="gutter-box">col-6</div>
|
||||
</Col>
|
||||
<Col className="gutter-row" span={6}>
|
||||
<div className="gutter-box">col-6</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>,
|
||||
mountNode,
|
||||
);
|
||||
|
@ -19,17 +19,23 @@ import { Row, Col, Slider } from 'antd';
|
||||
class App extends React.Component {
|
||||
gutters = {};
|
||||
|
||||
vgutters = {};
|
||||
|
||||
colCounts = {};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
gutterKey: 1,
|
||||
vgutterKey: 1,
|
||||
colCountKey: 2,
|
||||
};
|
||||
[8, 16, 24, 32, 40, 48].forEach((value, i) => {
|
||||
this.gutters[i] = value;
|
||||
});
|
||||
[8, 16, 24, 32, 40, 48].forEach((value, i) => {
|
||||
this.vgutters[i] = value;
|
||||
});
|
||||
[2, 3, 4, 6, 8, 12].forEach((value, i) => {
|
||||
this.colCounts[i] = value;
|
||||
});
|
||||
@ -39,12 +45,16 @@ class App extends React.Component {
|
||||
this.setState({ gutterKey });
|
||||
};
|
||||
|
||||
onVGutterChange = vgutterKey => {
|
||||
this.setState({ vgutterKey });
|
||||
};
|
||||
|
||||
onColCountChange = colCountKey => {
|
||||
this.setState({ colCountKey });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { gutterKey, colCountKey } = this.state;
|
||||
const { gutterKey, vgutterKey, colCountKey } = this.state;
|
||||
const cols = [];
|
||||
const colCount = this.colCounts[colCountKey];
|
||||
let colCode = '';
|
||||
@ -59,7 +69,7 @@ class App extends React.Component {
|
||||
return (
|
||||
<div>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<span style={{ marginRight: 6 }}>Gutter (px): </span>
|
||||
<span style={{ marginRight: 6 }}>Horizontal Gutter (px): </span>
|
||||
<div style={{ width: '50%' }}>
|
||||
<Slider
|
||||
min={0}
|
||||
@ -70,6 +80,17 @@ class App extends React.Component {
|
||||
step={null}
|
||||
/>
|
||||
</div>
|
||||
<span style={{ marginRight: 6 }}>Vertical Gutter (px): </span>
|
||||
<div style={{ width: '50%' }}>
|
||||
<Slider
|
||||
min={0}
|
||||
max={Object.keys(this.vgutters).length - 1}
|
||||
value={vgutterKey}
|
||||
onChange={this.onVGutterChange}
|
||||
marks={this.vgutters}
|
||||
step={null}
|
||||
/>
|
||||
</div>
|
||||
<span style={{ marginRight: 6 }}>Column Count:</span>
|
||||
<div style={{ width: '50%' }}>
|
||||
<Slider
|
||||
@ -82,8 +103,10 @@ class App extends React.Component {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Row gutter={this.gutters[gutterKey]}>{cols}</Row>
|
||||
<pre>{`<Row gutter={${this.gutters[gutterKey]}}>\n${colCode}</Row>`}</pre>
|
||||
<Row gutter={[this.gutters[gutterKey], this.vgutters[vgutterKey]]}>{cols}</Row>
|
||||
<Row gutter={[this.gutters[gutterKey], this.vgutters[vgutterKey]]}>{cols}</Row>
|
||||
<pre>{`<Row gutter={[${this.gutters[gutterKey]}, ${this.vgutters[vgutterKey]}]}>\n${colCode}</Row>`}</pre>
|
||||
<pre>{`<Row gutter={[${this.gutters[gutterKey]}, ${this.vgutters[vgutterKey]}]}>\n${colCode}</Row>`}</pre>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ If the Ant Design grid layout component does not meet your needs, you can use th
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| align | the vertical alignment of the flex layout: `top` `middle` `bottom` | string | `top` | |
|
||||
| gutter | spacing between grids, could be a number or a object like `{ xs: 8, sm: 16, md: 24}` | number/object | 0 | |
|
||||
| gutter | spacing between grids, could be a number or a object like `{ xs: 8, sm: 16, md: 24}`, or you can use array to make horizontal and vertical spacing work at the same time `[horizontal, vertical]` | number/object/array | 0 | |
|
||||
| justify | horizontal arrangement of the flex layout: `start` `end` `center` `space-around` `space-between` | string | `start` | |
|
||||
| type | layout mode, optional `flex`, [browser support](http://caniuse.com/#search=flex) | string | | |
|
||||
|
||||
|
@ -90,7 +90,7 @@ Ant Design 的布局组件若不能满足你的需求,你也可以直接使用
|
||||
| 成员 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| align | flex 布局下的垂直对齐方式:`top` `middle` `bottom` | string | `top` | |
|
||||
| gutter | 栅格间隔,可以写成像素值或支持响应式的对象写法 `{ xs: 8, sm: 16, md: 24}` | number/object | 0 | |
|
||||
| gutter | 栅格间隔,可以写成像素值或支持响应式的对象写法来设置水平间隔 `{ xs: 8, sm: 16, md: 24}`,或者使用数组形式同时设置`[水平间距, 垂直间距]` | number/object/array | 0 | |
|
||||
| justify | flex 布局下的水平排列方式:`start` `end` `center` `space-around` `space-between` | string | `start` | |
|
||||
| type | 布局模式,可选 `flex`,[现代浏览器](http://caniuse.com/#search=flex) 下有效 | string | | |
|
||||
|
||||
|
@ -12,8 +12,10 @@ import ResponsiveObserve, {
|
||||
|
||||
const RowAligns = tuple('top', 'middle', 'bottom', 'stretch');
|
||||
const RowJustify = tuple('start', 'end', 'center', 'space-around', 'space-between');
|
||||
|
||||
export type Gutter = number | Partial<Record<Breakpoint, number>>;
|
||||
export interface RowProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
gutter?: number | Partial<Record<Breakpoint, number>>;
|
||||
gutter?: Gutter | [Gutter, Gutter];
|
||||
type?: 'flex';
|
||||
align?: (typeof RowAligns)[number];
|
||||
justify?: (typeof RowJustify)[number];
|
||||
@ -35,7 +37,7 @@ export default class Row extends React.Component<RowProps, RowState> {
|
||||
justify: PropTypes.oneOf(RowJustify),
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
gutter: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
|
||||
gutter: PropTypes.oneOfType([PropTypes.object, PropTypes.number, PropTypes.array]),
|
||||
prefixCls: PropTypes.string,
|
||||
};
|
||||
|
||||
@ -47,7 +49,11 @@ export default class Row extends React.Component<RowProps, RowState> {
|
||||
|
||||
componentDidMount() {
|
||||
this.token = ResponsiveObserve.subscribe(screens => {
|
||||
if (typeof this.props.gutter === 'object') {
|
||||
const { gutter } = this.props;
|
||||
if (
|
||||
typeof gutter === 'object' ||
|
||||
(Array.isArray(gutter) && (typeof gutter[0] === 'object' || typeof gutter[1] === 'object'))
|
||||
) {
|
||||
this.setState({ screens });
|
||||
}
|
||||
});
|
||||
@ -57,17 +63,24 @@ export default class Row extends React.Component<RowProps, RowState> {
|
||||
ResponsiveObserve.unsubscribe(this.token);
|
||||
}
|
||||
|
||||
getGutter(): number | undefined {
|
||||
const { gutter } = this.props;
|
||||
if (typeof gutter === 'object') {
|
||||
for (let i = 0; i < responsiveArray.length; i++) {
|
||||
const breakpoint: Breakpoint = responsiveArray[i];
|
||||
if (this.state.screens[breakpoint] && gutter[breakpoint] !== undefined) {
|
||||
return gutter[breakpoint];
|
||||
getGutter(): [number, number] {
|
||||
const gutter: [number, number] = [0, 0];
|
||||
const { gutter: gutter_setting } = this.props;
|
||||
|
||||
(Array.isArray(gutter_setting) ? gutter_setting : [gutter_setting, 0]).forEach((g, index) => {
|
||||
if (typeof g === 'object') {
|
||||
for (let i = 0; i < responsiveArray.length; i++) {
|
||||
const breakpoint: Breakpoint = responsiveArray[i];
|
||||
if (this.state.screens[breakpoint] && g[breakpoint] !== undefined) {
|
||||
gutter[index] = g[breakpoint] as number;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gutter[index] = g as number;
|
||||
}
|
||||
}
|
||||
return gutter as number;
|
||||
});
|
||||
|
||||
return gutter;
|
||||
}
|
||||
|
||||
renderRow = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
@ -92,16 +105,24 @@ export default class Row extends React.Component<RowProps, RowState> {
|
||||
},
|
||||
className,
|
||||
);
|
||||
const rowStyle =
|
||||
gutter! > 0
|
||||
const rowStyle = {
|
||||
...(gutter[0]! > 0
|
||||
? {
|
||||
marginLeft: gutter! / -2,
|
||||
marginRight: gutter! / -2,
|
||||
...style,
|
||||
marginLeft: gutter[0]! / -2,
|
||||
marginRight: gutter[0]! / -2,
|
||||
}
|
||||
: style;
|
||||
: {}),
|
||||
...(gutter[1]! > 0
|
||||
? {
|
||||
marginTop: gutter[1]! / -2,
|
||||
marginBottom: gutter[1]! / -2,
|
||||
}
|
||||
: {}),
|
||||
...style,
|
||||
};
|
||||
const otherProps = { ...others };
|
||||
delete otherProps.gutter;
|
||||
|
||||
return (
|
||||
<RowContext.Provider value={{ gutter }}>
|
||||
<div {...otherProps} className={classes} style={rowStyle}>
|
||||
|
Loading…
Reference in New Issue
Block a user