From a2edbc326f9fde00eb7351abf580042c5b9bf74f Mon Sep 17 00:00:00 2001 From: sosohime Date: Tue, 24 Sep 2019 21:44:20 +0800 Subject: [PATCH] feat: Grid support row vertical gutter (#18979) * row vertical gutter * run test --- components/grid/RowContext.tsx | 2 +- .../__tests__/__snapshots__/demo.test.js.snap | 202 +++++++++++++++++- components/grid/__tests__/index.test.js | 14 +- components/grid/col.tsx | 18 +- components/grid/demo/gutter.md | 18 ++ components/grid/demo/playground.md | 31 ++- components/grid/index.en-US.md | 2 +- components/grid/index.zh-CN.md | 2 +- components/grid/row.tsx | 57 +++-- 9 files changed, 309 insertions(+), 37 deletions(-) diff --git a/components/grid/RowContext.tsx b/components/grid/RowContext.tsx index c16af4888b65..ec246b172786 100644 --- a/components/grid/RowContext.tsx +++ b/components/grid/RowContext.tsx @@ -1,7 +1,7 @@ import createContext, { Context } from '@ant-design/create-react-context'; export interface RowContextState { - gutter?: number; + gutter?: [number, number]; } const RowContext: Context = createContext({}); diff --git a/components/grid/__tests__/__snapshots__/demo.test.js.snap b/components/grid/__tests__/__snapshots__/demo.test.js.snap index 27b8a0c86982..df518e4a165d 100644 --- a/components/grid/__tests__/__snapshots__/demo.test.js.snap +++ b/components/grid/__tests__/__snapshots__/demo.test.js.snap @@ -414,6 +414,51 @@ exports[`renders ./components/grid/demo/gutter.md correctly 1`] = ` +
+
+
+ col-6 +
+
+
+
+ col-6 +
+
+
+
+ col-6 +
+
+
+
+ col-6 +
+
+
`; @@ -467,7 +512,105 @@ exports[`renders ./components/grid/demo/playground.md correctly 1`] = ` - Gutter (px): + Horizontal Gutter (px): + +
+
+
+
+
+ + + + + + +
+
+
+ + 8 + + + 16 + + + 24 + + + 32 + + + 40 + + + 48 + +
+
+
+ + Vertical Gutter (px):
Column @@ -675,7 +818,7 @@ exports[`renders ./components/grid/demo/playground.md correctly 1`] = `
Column @@ -683,7 +826,7 @@ exports[`renders ./components/grid/demo/playground.md correctly 1`] = `
Column @@ -691,15 +834,60 @@ exports[`renders ./components/grid/demo/playground.md correctly 1`] = `
Column
+
+
+
+ Column +
+
+
+
+ Column +
+
+
+
+ Column +
+
+
+
+ Column +
+
+
+
+    <Row gutter={[16, 16]}>
+  <Col span={6} />
+  <Col span={6} />
+  <Col span={6} />
+  <Col span={6} />
+</Row>
+  
-    <Row gutter={16}>
+    <Row gutter={[16, 16]}>
   <Col span={6} />
   <Col span={6} />
   <Col span={6} />
diff --git a/components/grid/__tests__/index.test.js b/components/grid/__tests__/index.test.js
index a2a7b78c77a9..b4da13161aeb 100644
--- a/components/grid/__tests__/index.test.js
+++ b/components/grid/__tests__/index.test.js
@@ -37,7 +37,7 @@ describe('Grid', () => {
 
   it('when typeof getGutter is object', () => {
     const wrapper = mount();
-    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();
+    expect(wrapper.find('div').prop('style')).toEqual({
+      marginLeft: -8,
+      marginRight: -8,
+      marginTop: -10,
+      marginBottom: -10,
+    });
+  });
 });
diff --git a/components/grid/col.tsx b/components/grid/col.tsx
index c2640882fc5e..32d28a324ee4 100644
--- a/components/grid/col.tsx
+++ b/components/grid/col.tsx
@@ -102,13 +102,25 @@ export default class Col extends React.Component {
       
         {({ 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 (
             
{children} diff --git a/components/grid/demo/gutter.md b/components/grid/demo/gutter.md index 4515b67c108c..a21fd20128d2 100644 --- a/components/grid/demo/gutter.md +++ b/components/grid/demo/gutter.md @@ -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(
col-6
+ + +
col-6
+ + +
col-6
+ + +
col-6
+ + +
col-6
+ +
, mountNode, ); diff --git a/components/grid/demo/playground.md b/components/grid/demo/playground.md index cff7b2382b83..940be3f45b6e 100644 --- a/components/grid/demo/playground.md +++ b/components/grid/demo/playground.md @@ -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 (
- Gutter (px): + Horizontal Gutter (px):
+ Vertical Gutter (px): +
+ +
Column Count:
- {cols} -
{`\n${colCode}`}
+ {cols} + {cols} +
{`\n${colCode}`}
+
{`\n${colCode}`}
); } diff --git a/components/grid/index.en-US.md b/components/grid/index.en-US.md index a0170d85c97e..e50d73bd5954 100644 --- a/components/grid/index.en-US.md +++ b/components/grid/index.en-US.md @@ -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 | | | diff --git a/components/grid/index.zh-CN.md b/components/grid/index.zh-CN.md index ee5ee8261bc3..2ddb78714362 100644 --- a/components/grid/index.zh-CN.md +++ b/components/grid/index.zh-CN.md @@ -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 | | | diff --git a/components/grid/row.tsx b/components/grid/row.tsx index 7ac7ea8bd755..7565c3343d2c 100644 --- a/components/grid/row.tsx +++ b/components/grid/row.tsx @@ -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>; export interface RowProps extends React.HTMLAttributes { - gutter?: number | Partial>; + 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 { 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 { 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 { 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 { }, className, ); - const rowStyle = - gutter! > 0 + const rowStyle = { + ...(gutter[0]! > 0 + ? { + marginLeft: gutter[0]! / -2, + marginRight: gutter[0]! / -2, + } + : {}), + ...(gutter[1]! > 0 ? { - marginLeft: gutter! / -2, - marginRight: gutter! / -2, - ...style, + marginTop: gutter[1]! / -2, + marginBottom: gutter[1]! / -2, } - : style; + : {}), + ...style, + }; const otherProps = { ...others }; delete otherProps.gutter; + return (