diff --git a/packages/Grid/Grid.css b/packages/Grid/Grid.css new file mode 100644 index 0000000..3c09d93 --- /dev/null +++ b/packages/Grid/Grid.css @@ -0,0 +1,5 @@ +.van-grid { + position: relative; + box-sizing: border-box; + overflow: hidden; +} diff --git a/packages/Grid/Grid.tsx b/packages/Grid/Grid.tsx new file mode 100644 index 0000000..b32cf59 --- /dev/null +++ b/packages/Grid/Grid.tsx @@ -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 = (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 ( + + {children} + + ); +}; + +export default widthDefaultProps( + DefaultGridProps +)(Grid); diff --git a/packages/Grid/index.ts b/packages/Grid/index.ts new file mode 100644 index 0000000..6633c41 --- /dev/null +++ b/packages/Grid/index.ts @@ -0,0 +1,4 @@ +/** + * @description - nothing but export component + */ +export { default } from './Grid'; diff --git a/packages/GridItem/GridItem.css b/packages/GridItem/GridItem.css new file mode 100644 index 0000000..757e4d8 --- /dev/null +++ b/packages/GridItem/GridItem.css @@ -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); +} diff --git a/packages/GridItem/GridItem.tsx b/packages/GridItem/GridItem.tsx new file mode 100644 index 0000000..a1e8af7 --- /dev/null +++ b/packages/GridItem/GridItem.tsx @@ -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>; +type GridItemProps = ExogenousGridItemProps & InheritGridProps; + +// wrap children with built-in classname van-grid-item__icon, van-grid-item__text +/* + {icon} + {text} + */ + +// TODO - hairline bottom border invisible +const GridItem: FunctionComponent = (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 ( + + + {children} + + + ); +}; + +export default GridItem; diff --git a/packages/GridItem/index.ts b/packages/GridItem/index.ts new file mode 100644 index 0000000..bc35ccb --- /dev/null +++ b/packages/GridItem/index.ts @@ -0,0 +1,4 @@ +/** + * @description - nothing but export component + */ +export { default } from './GridItem'; diff --git a/public/app.config.ts b/public/app.config.ts index 6ff1dd6..3b0f5aa 100644 --- a/public/app.config.ts +++ b/public/app.config.ts @@ -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', diff --git a/public/pages/grid/index.tsx b/public/pages/grid/index.tsx new file mode 100644 index 0000000..246ab9b --- /dev/null +++ b/public/pages/grid/index.tsx @@ -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 ( + + 基础用法 + + + + + + + 文字 + + + + + + 文字 + + + + + + 文字 + + + + + + 文字 + + + + 自定义列数 + + + + + + + 文字 + + + + + + 文字 + + + + + + 文字 + + + + + + 文字 + + + + + + 文字 + + + + + + 文字 + + + + 正方形格子 + + + + + + + 文字 + + + + + + 文字 + + + + + + 文字 + + + + + + 文字 + + + + + ); +};