Skip to content

Commit

Permalink
feat(next): add FormGrid
Browse files Browse the repository at this point in the history
  • Loading branch information
ZirkleTsing committed Feb 5, 2021
1 parent ac3783d commit 1805d8d
Show file tree
Hide file tree
Showing 8 changed files with 291 additions and 2 deletions.
30 changes: 30 additions & 0 deletions packages/next/docs/components/FormGrid.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# FormGrid

> FormGrid 组件
```tsx
import React from 'react'
import { FormGrid } from '@formily/next'

export default () => {
return (
<FormGrid
// minWidth={[100]}
colWrap
// maxWidth={[200]}
// maxColumns={[20]}
minColumns={5}
>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
</FormGrid>
)
}
```
5 changes: 3 additions & 2 deletions packages/next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@
"@formily/shared": "^2.0.0-beta.3",
"classnames": "^2.2.6",
"react-sortable-hoc": "^1.11.0",
"react-sticky-box": "^0.9.3"
"react-sticky-box": "^0.9.3",
"yarn": "^1.22.10"
},
"publishConfig": {
"access": "public"
},
"gitHead": "4d068dad6183e8da294a4c899a158326c0b0b050"
}
}
240 changes: 240 additions & 0 deletions packages/next/src/form-grid/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
import React, { useLayoutEffect, useRef, useState } from 'react'
import { usePrefixCls } from '../__builtins__'
import cls from 'classnames'
import { isValid, isNum, isBool } from '@formily/shared'
import ResizeObserver from 'resize-observer-polyfill'
// import './style.less';
interface ILayout {
ref: React.MutableRefObject<HTMLDivElement>
formGridPrefixCls: string
responsiveColumns: number
layoutParams: {
minWidth?: number
columns?: number
colWrap?: boolean
}
}

interface ILayoutProps {
minWidth: number | number[]
maxWidth: number | number[]
minColumns: number | number[]
maxColumns: number | number[]
intervals: Array<number[]>
colWrap: boolean[]
columnGap: number
}

interface IFormGridProps {
minWidth?: number | number[]
maxWidth?: number | number[]
minColumns?: number | number[]
maxColumns?: number | number[]
colWrap?: boolean | boolean[]
breakpoints: number[]
columnGap: number
rowGap: number
}

interface IStyle {
[key: string]: string
}

interface IStyleProps extends IFormGridProps {
responsiveColumns?: number
layoutParams?: {
minWidth?: number
columns?: number
colWrap?: boolean
}
}

// const MAX_COLUMN_WIDTH = 300;
// const MIN_COLUMN_WIDTH = 100;
// const DEFAULT_COLUMNS = 4;
const S = 720
const MD = 1280
const LG = 1920

const useLayout = (props: ILayoutProps): ILayout => {
const {
intervals,
minColumns,
maxColumns,
minWidth,
// maxWidth,
colWrap,
} = props
const ref = useRef<HTMLDivElement>(null)
const formGridPrefixCls = usePrefixCls('form-grid')
const observer = useRef(null)
const [responsiveColumns] = useState(undefined)
const [layoutParams, setLayout] = useState({})

const calculateSmartColumns = (target: HTMLElement) => {
const { clientWidth } = target
const index = intervals.findIndex((interval) => {
const [min, max] = interval
if (clientWidth >= min && max > clientWidth) {
return true
}
})

if (!isValid(maxColumns) && !isValid(maxColumns)) {
const minWidthUnderMinColumns = clientWidth / minColumns[index]
// console.log('@@:', minColumns[index], minWidthUnderMinColumns, minWidth)
// console.log({
// minWidth: minWidthUnderMinColumns > minWidth[index] ? minWidth[index] : minWidthUnderMinColumns,
// columns: target.childNodes.length,
// colWrap: colWrap[index]
// })
return {
minWidth: isValid(minWidth)
? minWidthUnderMinColumns > minWidth[index]
? minWidth[index]
: minWidthUnderMinColumns
: isValid(minColumns[index])
? Math.floor(
(clientWidth - (minColumns[index] - 1) * props.columnGap) /
minColumns[index]
)
: //
0,
columns: target.childNodes.length,
colWrap: colWrap[index],
}
} else {
// const currentMinColumn = minColumns[index];
// const currentMaxColumn = maxColumns[index];
// const currentMinWidth = minWidth[index];
// const currentMaxWidth = maxWidth[index];
// const minColumnsUnderMinWidth = Math.ceil(clientWidth / currentMinWidth);
// const maxColumnsUnderMaxWidth = Math.floor(clientWidth / currentMaxWidth);
// const minColumn = minColumnsUnderMinWidth > currentMinColumn ? minColumnsUnderMinWidth : currentMinColumn
}
}

useLayoutEffect(() => {
if (ref.current) {
observer.current = new ResizeObserver((entries) => {
requestAnimationFrame(() => {
entries.forEach((entry) => {
const target = entry.target as HTMLElement
const params = calculateSmartColumns(target)
// setColumns(columns)
setLayout(params)
})
})
}) as any
observer.current.observe(ref.current)
}
return () => {
observer.current?.unobserve(ref.current)
}
}, [])
return {
ref,
formGridPrefixCls,
responsiveColumns,
layoutParams,
}
}

const useStyle = (props: IStyleProps): IStyle => {
const { responsiveColumns, columnGap, rowGap, layoutParams } = props

const style = isNum(responsiveColumns)
? {
gridTemplateColumns: `repeat(${responsiveColumns},1fr)`,
gridGap: `${rowGap}px ${columnGap}px`,
}
: {
// 自动换行必须指定最小宽度
// 比自动换行
gridTemplateColumns: layoutParams.colWrap
? `repeat(auto-fill, minmax(${layoutParams.minWidth}px,1fr))`
: `repeat(${layoutParams.columns}, minmax(${layoutParams.minWidth}px,1fr))`,
gridGap: `${rowGap}px ${columnGap}px`,
}

return style
}

export const FormGrid: React.FC<IFormGridProps> = (props) => {
const normalizeProps = (props: IFormGridProps): ILayoutProps => {
const { breakpoints } = props

const intervals = breakpoints.reduce((buf, cur, index, array) => {
if (index === array.length - 1) {
return [...buf, [array[index], Infinity]]
}
if (index === 0) {
return [...buf, [0, cur], [cur, array[index + 1]]]
}
return [...buf, [cur, array[index + 1]]]
}, [])

const normalize = (prop) => {
if (isNum(prop) || isBool(prop)) {
return intervals.map(() => prop)
} else if (Array.isArray(prop)) {
let lastVal
return intervals.map((it, idx) => {
const res = isValid(prop[idx]) ? prop[idx] : lastVal
lastVal = isValid(prop[idx]) ? prop[idx] : lastVal
return res
})
} else {
return undefined
}
}

return {
...props,
intervals,
colWrap: normalize(props.colWrap),
minWidth: normalize(props.minWidth),
maxWidth: normalize(props.maxWidth),
minColumns: normalize(props.minColumns),
maxColumns: normalize(props.maxColumns),
}
}
const { children, columnGap, rowGap, breakpoints } = props
const normalizedProps = normalizeProps(props)
const { ref, formGridPrefixCls, responsiveColumns, layoutParams } = useLayout(
normalizedProps
)

const styles = useStyle({
columnGap,
rowGap,
breakpoints,
responsiveColumns,
layoutParams,
})

return (
<div
className={cls(`${formGridPrefixCls}-layout`, {
flex: !isNum(responsiveColumns),
})}
style={styles}
ref={ref}
>
{children}
</div>
)
}

FormGrid.defaultProps = {
columnGap: 10,
rowGap: 5,
// minWidth: 0,
// maxWidth: Infinity,
minColumns: 0,
// maxColumns: 5,
breakpoints: [S, MD, LG],
colWrap: false,
}

export default FormGrid
10 changes: 10 additions & 0 deletions packages/next/src/form-grid/style.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@form-grid-prefix-cls: ~'next-form-grid-layout';

.@{form-grid-prefix-cls} {
display: grid;
// &.flex {
// & > * {
// flex: 1 1 auto;
// }
// }
}
1 change: 1 addition & 0 deletions packages/next/src/form-grid/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import './style.less'
1 change: 1 addition & 0 deletions packages/next/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from './array-cards'
export * from './array-items'
export * from './form-dialog'
export * from './form-drawer'
export * from './form-grid'
export * from './form-item'
export * from './form-step'
export * from './form-tab'
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import './form-collapse/style'
import './form-dialog/style'
import './form-drawer/style'
import './form-item/style'
import './form-grid/style'
import './form-step/style'
import './form-tab/style'
import './upload/style'
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -19027,6 +19027,11 @@ yargs@^16.0.0:
y18n "^5.0.5"
yargs-parser "^20.2.2"

yarn@^1.22.10:
version "1.22.10"
resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.22.10.tgz#c99daa06257c80f8fa2c3f1490724e394c26b18c"
integrity sha512-IanQGI9RRPAN87VGTF7zs2uxkSyQSrSPsju0COgbsKQOOXr5LtcVPeyXWgwVa0ywG3d8dg6kSYKGBuYK021qeA==

[email protected]:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
Expand Down

0 comments on commit 1805d8d

Please sign in to comment.