Skip to content

Commit

Permalink
feat(component): 新增Grid组件
Browse files Browse the repository at this point in the history
  • Loading branch information
ShanaMaid committed Sep 27, 2018
1 parent d95def9 commit a2bc971
Show file tree
Hide file tree
Showing 42 changed files with 1,022 additions and 32 deletions.
94 changes: 94 additions & 0 deletions components/Grid/Col.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@

import {Component} from 'react';
import * as React from 'react';
import * as classNames from 'classnames';
import {IBaseComponent} from '../template/component';

export interface ICol {
offset?: number;
order?: number;
pull?: number;
push?: number;
span?: number;
}

export interface IColProps extends IBaseComponent, ICol {
xs?: number | ICol;
sm?: number | ICol;
md?: number | ICol;
lg?: number | ICol;
xl?: number | ICol;
xxl?: number | ICol;
}

export interface IColState {

}

const sizes = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];

/**
* **组件中文名称**-组件描述。
*/
export class Col extends Component<IColProps, IColState> {
preCls = 'yoshino-col';

static defaultProps = {
offset: 0,
order: 0,
pull: 0,
push: 0,
};

render() {
const {
className, style, span,
offset, order, pull, push, children,
...otherProps} = this.props;
const preCls = this.preCls;
let sizeCls = {};

sizes.forEach((size: 'xxl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs') => {
let sizeProps: ICol = {};
// tslint:disable-next-line
const props = this.props as any;
if (typeof props[size] === 'number') {
sizeProps.span = props[size];
} else if (typeof props[size] === 'object') {
sizeProps = props[size] || {};
}

delete otherProps[size];

sizeCls = {
...sizeCls,
[`${preCls}-${size}-${sizeProps.span}`]: sizeProps.span !== undefined,
[`${preCls}-${size}-order-${sizeProps.order}`]: sizeProps.order || sizeProps.order === 0,
[`${preCls}-${size}-offset-${sizeProps.offset}`]: sizeProps.offset || sizeProps.offset === 0,
[`${preCls}-${size}-push-${sizeProps.push}`]: sizeProps.push || sizeProps.push === 0,
[`${preCls}-${size}-pull-${sizeProps.pull}`]: sizeProps.pull || sizeProps.pull === 0,
};
});

const clsName = classNames(
preCls, className, sizeCls, {
[`${preCls}-${span}`]: span !== undefined,
[`${preCls}-order-${order}`]: !!order,
[`${preCls}-offset-${offset}`]: !!offset,
[`${preCls}-push-${push}`]: !!push,
[`${preCls}-pull-${pull}`]: !!pull,
}
);
return (
<div
className={clsName}
style={style}
{...otherProps}
>
{children}
</div>
);
}
}

export default Col;
71 changes: 71 additions & 0 deletions components/Grid/Row.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// tslint:disable no-any
import {Component} from 'react';
import * as React from 'react';
import * as classNames from 'classnames';
import {IBaseComponent} from '../template/component';

export interface IRowProps extends IBaseComponent {
align?: 'top' | 'middle' | 'bottom';
gutter?: number ;
justify?: 'start' | 'end' | 'center' | 'space-around' | 'space-between';
type?: 'flex';
}

export interface IRowState {
screens: {[index: string]: any};
}

/**
* **组件中文名称**-组件描述。
*/
export class Row extends Component<IRowProps, IRowState> {
preCls = 'yoshino-row';

static defaultProps = {
type: '',
gutter: 0,
justify: 'start',
align: 'top',
};

render() {
const {
className, style,
align = 'top', gutter = 0, justify = 'start',
type = '', children,
...otherProps} = this.props;
const preCls = this.preCls;
const clsName = classNames(
preCls, className, {
[preCls]: !type,
[`${preCls}-${type}`]: !!type,
[`${preCls}-${type}-${justify}`]: !!type && !!justify,
[`${preCls}-${type}-${align}`]: !!type && !!align,
}
);
const offsetStyle = gutter > 0 ? {
marginLeft: gutter / -2,
marginRight: gutter / -2,
} : {};
const colChildren = React.Children.map(children, (child: React.ReactElement<HTMLDivElement>) => {
return React.cloneElement(child, {
style: {
paddingLeft: gutter / 2,
paddingRight: gutter / 2,
...child.props.style,
},
});
});
return (
<div
className={clsName}
style={{...offsetStyle, ...style}}
{...otherProps}
>
{colChildren}
</div>
);
}
}

export default Row;
12 changes: 12 additions & 0 deletions components/Grid/__tests__/e2e.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from 'react';
import {Simulate, renderIntoDocument, scryRenderedComponentsWithType} from 'react-dom/test-utils';
import {findDOMNode} from 'react-dom';
import Grid from '../index';

describe('多选', () => {
test('点击其中一个选项后可通过 onChange 拿到最新的值', () => {
const component = renderIntoDocument(
<Grid/>,
) as Grid;
});
});
14 changes: 14 additions & 0 deletions components/Grid/__tests__/props.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as renderer from 'react-test-renderer';
import * as React from 'react';
import Grid from '../index';

describe('Props', () => {

test('默认', () => {
const component = renderer.create(
<Grid/>,
);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
});
8 changes: 8 additions & 0 deletions components/Grid/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// tks for https://github.com/ant-design/ant-design/tree/master/components/grid
import Col from './Col';
import Row from './Row';

export default {
Col,
Row,
};
112 changes: 112 additions & 0 deletions components/Grid/style/grid.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// thanks for antd
// https://github.com/ant-design/ant-design/blob/master/components/grid/style/mixin.less
@import './var.less';

.make-row(@gutter: @grid-gutter-width) {
position: relative;
margin-left: (@gutter / -2);
margin-right: (@gutter / -2);
height: auto;
.clearfix;
}

.make-grid-columns() {
.col(@index) {
@item: ~".@{css-prefix}-col-@{index}, .@{css-prefix}-col-xs-@{index}, .@{css-prefix}-col-sm-@{index}, .@{css-prefix}-col-md-@{index}, .@{css-prefix}-col-lg-@{index}";
.col((@index + 1), @item);
}
.col(@index, @list) when (@index =< @grid-columns) {
@item: ~".@{css-prefix}-col-@{index}, .@{css-prefix}-col-xs-@{index}, .@{css-prefix}-col-sm-@{index}, .@{css-prefix}-col-md-@{index}, .@{css-prefix}-col-lg-@{index}";
.col((@index + 1), ~"@{list}, @{item}");
}
.col(@index, @list) when (@index > @grid-columns) {
@{list} {
position: relative;
// Prevent columns from collapsing when empty
min-height: 1px;
padding-left: (@grid-gutter-width / 2);
padding-right: (@grid-gutter-width / 2);
}
}
.col(1);
}

.float-grid-columns(@class) {
.col(@index) { // initial
@item: ~".@{css-prefix}-col@{class}-@{index}";
.col((@index + 1), @item);
}
.col(@index, @list) when (@index =< @grid-columns) { // general
@item: ~".@{css-prefix}-col@{class}-@{index}";
.col((@index + 1), ~"@{list}, @{item}");
}
.col(@index, @list) when (@index > @grid-columns) { // terminal
@{list} {
float: left;
flex: 0 0 auto;
}
}
.col(1); // kickstart it
}

// lesshint false
.loop-grid-columns(@index, @class) when (@index > 0) {
.@{css-prefix}-col@{class}-@{index} {
display: block;
box-sizing: border-box;
width: percentage((@index / @grid-columns));
}

.@{css-prefix}-col@{class}-push-@{index} {
left: percentage((@index / @grid-columns));
}

.@{css-prefix}-col@{class}-pull-@{index} {
right: percentage((@index / @grid-columns));
}

.@{css-prefix}-col@{class}-offset-@{index} {
margin-left: percentage((@index / @grid-columns));
}

.@{css-prefix}-col@{class}-order-@{index} {
order: @index;
}

.loop-grid-columns((@index - 1), @class);
}

.loop-grid-columns(@index, @class) when (@index = 0) {
.@{css-prefix}-col@{class}-@{index} {
display: none;
}

.@{css-prefix}-col-push-@{index} {
left: auto;
}

.@{css-prefix}-col-pull-@{index} {
right: auto;
}

.@{css-prefix}-col@{class}-push-@{index} {
left: auto;
}

.@{css-prefix}-col@{class}-pull-@{index} {
right: auto;
}

.@{css-prefix}-col@{class}-offset-@{index} {
margin-left: 0;
}

.@{css-prefix}-col@{class}-order-@{index} {
order: 0;
}
}

.make-grid(@class: ~'') {
.float-grid-columns(@class);
.loop-grid-columns(@grid-columns, @class);
}
Loading

0 comments on commit a2bc971

Please sign in to comment.