Skip to content

Commit

Permalink
feat: ✨ implement grid
Browse files Browse the repository at this point in the history
  • Loading branch information
huang-xiao-jian committed May 29, 2020
1 parent f8439b3 commit dc18619
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 0 deletions.
5 changes: 5 additions & 0 deletions packages/Grid/Grid.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.van-grid {
position: relative;
box-sizing: border-box;
overflow: hidden;
}
77 changes: 77 additions & 0 deletions packages/Grid/Grid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// packages
import React, {
FunctionComponent,
CSSProperties,
Children,
cloneElement,
isValidElement,
} from 'react';
import clsx from 'clsx';
import { View } from 'remax/wechat';
// internal
import widthDefaultProps from '../tools/with-default-props-advance';
import pickStyle from '../tools/pick-style';
import './Grid.css';

// 默认值填充属性
interface NeutralGridProps {
columnNum: number;
gutter: string;
// 默认为 vertical,此处仅为占位使用
direction?: 'horizontal';
border: boolean;
center: boolean;
square: boolean;
clickable: boolean;
}

interface ExogenousGridProps {
// 容器类名,用以覆盖内部
className?: string;
}

export type GridProps = NeutralGridProps & ExogenousGridProps;

// scope
const DefaultGridProps: NeutralGridProps = {
columnNum: 4,
gutter: '0px',
border: true,
center: true,
square: false,
clickable: false,
};

const Grid: FunctionComponent<GridProps> = (props) => {
const { className, children: rawChildren, ...rest } = props;
const { border, gutter } = rest;
const classnames = {
container: clsx(className, 'van-grid', {
'van-hairline--top': border && !gutter,
}),
};
const style: CSSProperties = {
paddingLeft: gutter,
};

// attach index property to grid item child
// transport share property to grid item child
const children = Children.map(rawChildren, (child, index) =>
isValidElement(child)
? cloneElement(child, {
index,
...rest,
})
: child
);

return (
<View style={pickStyle(style)} className={classnames.container}>
{children}
</View>
);
};

export default widthDefaultProps<ExogenousGridProps, NeutralGridProps>(
DefaultGridProps
)(Grid);
4 changes: 4 additions & 0 deletions packages/Grid/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* @description - nothing but export component
*/
export { default } from './Grid';
65 changes: 65 additions & 0 deletions packages/GridItem/GridItem.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
.van-grid-item {
position: relative;
float: left;
box-sizing: border-box;
}
.van-grid-item--square {
height: 0;
}
.van-grid-item__content {
display: flex;
flex-direction: column;
box-sizing: border-box;
height: 100%;
padding: 16px 8px;
padding: var(--grid-item-content-padding, 16px 8px);
background-color: #fff;
background-color: var(--grid-item-content-background-color, #fff);
}
.van-grid-item__content::after {
z-index: 1;
border-width: 0 1px 1px 0;
border-width: 0 var(--border-width-base, 1px) var(--border-width-base, 1px) 0;
}
.van-grid-item__content--surround::after {
border-width: 1px;
border-width: var(--border-width-base, 1px);
}
.van-grid-item__content--center {
align-items: center;
justify-content: center;
}
.van-grid-item__content--square {
position: absolute !important;
top: 0;
right: 0;
left: 0;
}
.van-grid-item__content--horizontal {
flex-direction: row;
}
.van-grid-item__content--horizontal
.van-grid-item__icon
+ .van-grid-item__text {
margin-top: 0;
margin-left: 8px;
}
.van-grid-item__content--clickable:active {
background-color: #f2f3f5;
background-color: var(--grid-item-content-active-color, #f2f3f5);
}
.van-grid-item__icon {
display: flex;
align-items: center;
font-size: 26px;
font-size: var(--grid-item-icon-size, 26px);
height: 26px;
height: var(--grid-item-icon-size, 26px);
}
.van-grid-item__text {
word-wrap: break-word;
color: #646566;
color: var(--grid-item-text-color, #646566);
font-size: 12px;
font-size: var(--grid-item-text-font-size, 12px);
}
89 changes: 89 additions & 0 deletions packages/GridItem/GridItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// packages
import React, { FunctionComponent, CSSProperties } from 'react';
import clsx from 'clsx';
import { View } from 'remax/wechat';
// internal
// eslint-disable-next-line import/named
import { GridProps } from '../Grid/Grid';
import pickStyle from '../tools/pick-style';
import './GridItem.css';

interface ExogenousGridItemProps {
// ITEM 序号,Grid parent 显式传入,声明非必须仅为方便类型推导
index?: number;
// 容器类名,用以覆盖内部
className?: string;
// 事件回调
onClick?: (event: any) => void;
}

// vant-weapp 使用 relations 链接
type InheritGridProps = Partial<Omit<GridProps, 'className'>>;
type GridItemProps = ExogenousGridItemProps & InheritGridProps;

// wrap children with built-in classname van-grid-item__icon, van-grid-item__text
/*
<view class="van-grid-item__icon">{icon}</view>
<view class="van-grid-item__text">{text}</view>
*/

// TODO - hairline bottom border invisible
const GridItem: FunctionComponent<GridItemProps> = (props) => {
const {
className,
square,
center,
clickable,
direction,
index,
border,
gutter,
columnNum,
children,
} = props;
const { onClick } = props;
const classnames = {
container: clsx(className, 'van-grid-item', {
'van-grid-item--square': square,
}),
item: clsx(
'van-grid-item__content',
direction && `van-grid-item__content--${direction}`,
{
'van-grid-item__content--center': center,
'van-grid-item__content--clickable': clickable,
'van-grid-item__content--surround': border && gutter,
'van-grid-item__content--square': square,
'van-hairline--surround': border,
}
),
};
const style: Record<'view' | 'content', CSSProperties> = {
view: {
width: `${100 / (columnNum as number)}%`,
paddingTop: square ? `${100 / (columnNum as number)}%` : undefined,
paddingRight: gutter ?? undefined,
marginTop:
(index as number) >= (columnNum as number) ? gutter : undefined,
},
content: {
height: 'auto',
right: square ? gutter : undefined,
bottom: square ? gutter : undefined,
},
};

return (
<View
style={pickStyle(style.view)}
className={classnames.container}
onClick={onClick}
>
<View style={pickStyle(style.content)} className={classnames.item}>
{children}
</View>
</View>
);
};

export default GridItem;
4 changes: 4 additions & 0 deletions packages/GridItem/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* @description - nothing but export component
*/
export { default } from './GridItem';
1 change: 1 addition & 0 deletions public/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { AppConfig } from 'remax/wechat';

const config: AppConfig = {
pages: [
'pages/grid/index',
'pages/image/index',
'pages/cell/index',
'pages/button/index',
Expand Down
114 changes: 114 additions & 0 deletions public/pages/grid/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// packages
import * as React from 'react';
import { View, Text } from 'remax/wechat';

// internal
import Grid from '../../../packages/Grid';
import GridItem from '../../../packages/GridItem';
import Icon from '../../../packages/Icon';

export default () => {
return (
<View className="demo-block">
<Text className="demo-block__title">基础用法</Text>
<View>
<Grid>
<GridItem>
<View className="van-grid-item__icon">
<Icon name="photo-o" />
</View>
<View className="van-grid-item__text">文字</View>
</GridItem>
<GridItem>
<View className="van-grid-item__icon">
<Icon name="photo-o" />
</View>
<View className="van-grid-item__text">文字</View>
</GridItem>
<GridItem>
<View className="van-grid-item__icon">
<Icon name="photo-o" />
</View>
<View className="van-grid-item__text">文字</View>
</GridItem>
<GridItem>
<View className="van-grid-item__icon">
<Icon name="photo-o" />
</View>
<View className="van-grid-item__text">文字</View>
</GridItem>
</Grid>
</View>
<Text className="demo-block__title">自定义列数</Text>
<View>
<Grid columnNum={3}>
<GridItem>
<View className="van-grid-item__icon">
<Icon name="photo-o" />
</View>
<View className="van-grid-item__text">文字</View>
</GridItem>
<GridItem>
<View className="van-grid-item__icon">
<Icon name="photo-o" />
</View>
<View className="van-grid-item__text">文字</View>
</GridItem>
<GridItem>
<View className="van-grid-item__icon">
<Icon name="photo-o" />
</View>
<View className="van-grid-item__text">文字</View>
</GridItem>
<GridItem>
<View className="van-grid-item__icon">
<Icon name="photo-o" />
</View>
<View className="van-grid-item__text">文字</View>
</GridItem>
<GridItem>
<View className="van-grid-item__icon">
<Icon name="photo-o" />
</View>
<View className="van-grid-item__text">文字</View>
</GridItem>
<GridItem>
<View className="van-grid-item__icon">
<Icon name="photo-o" />
</View>
<View className="van-grid-item__text">文字</View>
</GridItem>
</Grid>
</View>
<Text className="demo-block__title">正方形格子</Text>
<View>
<Grid square>
<GridItem>
<View className="van-grid-item__icon">
<Icon name="photo-o" />
</View>
<View className="van-grid-item__text">文字</View>
</GridItem>
<GridItem>
<View className="van-grid-item__icon">
<Icon name="photo-o" />
</View>
<View className="van-grid-item__text">文字</View>
</GridItem>
<GridItem>
<View className="van-grid-item__icon">
<Icon name="photo-o" />
</View>
<View className="van-grid-item__text">文字</View>
</GridItem>
<GridItem>
<View className="van-grid-item__icon">
<Icon name="photo-o" />
</View>
<View className="van-grid-item__text">文字</View>
</GridItem>
</Grid>
</View>
</View>
);
};

0 comments on commit dc18619

Please sign in to comment.