Skip to content

Commit

Permalink
fix(form-grid): add mutation observer
Browse files Browse the repository at this point in the history
  • Loading branch information
janryWang committed Feb 20, 2021
1 parent f5685fd commit 35dd3fd
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 108 deletions.
20 changes: 16 additions & 4 deletions packages/antd/docs/components/FormGrid.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import React from 'react'
import { FormItem, Input, FormGrid } from '@formily/antd'
import { FormProvider, createSchemaField } from '@formily/react'
import { createForm } from '@formily/core'
import { createForm, onFieldReact } from '@formily/core'

const SchemaField = createSchemaField({
components: {
Expand All @@ -18,7 +18,13 @@ const SchemaField = createSchemaField({
},
})

const form = createForm()
const form = createForm({
effects(form) {
onFieldReact('*(ccc,ddd,eee,fff,ggg)', (field) => {
field.visible = form.values.aaa !== '123'
})
},
})

export default () => {
return (
Expand Down Expand Up @@ -86,7 +92,7 @@ export default () => {
import React from 'react'
import { FormItem, Input, FormGrid } from '@formily/antd'
import { FormProvider, createSchemaField } from '@formily/react'
import { createForm } from '@formily/core'
import { createForm, onFieldReact } from '@formily/core'

const SchemaField = createSchemaField({
components: {
Expand All @@ -96,7 +102,13 @@ const SchemaField = createSchemaField({
},
})

const form = createForm()
const form = createForm({
effects(form) {
onFieldReact('*(ccc,ddd,eee,fff,ggg)', (field) => {
field.visible = form.values.aaa !== '123'
})
},
})

const schema = {
type: 'object',
Expand Down
144 changes: 92 additions & 52 deletions packages/antd/src/form-grid/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { usePrefixCls } from '../__builtins__'
import cls from 'classnames'
import { isValid, isNum, isBool } from '@formily/shared'
import ResizeObserver from 'resize-observer-polyfill'
import { FormGridContext } from './context';
import { FormGridContext } from './context'

interface ILayout {
ref: React.MutableRefObject<HTMLDivElement>
Expand Down Expand Up @@ -67,7 +67,6 @@ type ComposedFormGrid = React.FC<IFormGridProps> & {
useGridSpan: (gridSpan: number) => number
}


const S = 720
const MD = 1280
const LG = 1920
Expand All @@ -85,7 +84,6 @@ const useLayout = (props: ILayoutProps): ILayout => {
} = props
const ref = useRef<HTMLDivElement>(null)
const formGridPrefixCls = usePrefixCls('formily-grid')
const observer = useRef(null)
const [layoutParams, setLayout] = useState({})
const [styles, setStyles] = useState({})

Expand All @@ -102,13 +100,25 @@ const useLayout = (props: ILayoutProps): ILayout => {
minWidth: isValid(minWidth)
? minWidth[index]
: isValid(maxColumns[index])
? maxColumns ? Math.floor((clientWidth - (maxColumns[index] - 1) * props.columnGap) / maxColumns[index]) : minWidth
? maxColumns
? Math.floor(
(clientWidth - (maxColumns[index] - 1) * props.columnGap) /
maxColumns[index]
)
: minWidth
: 0,
maxWidth: isValid(maxWidth)
? maxWidth[index]
: Infinity === Math.floor((clientWidth - (minColumns[index] - 1) * props.columnGap) / minColumns[index])
maxWidth: isValid(maxWidth)
? maxWidth[index]
: Infinity ===
Math.floor(
(clientWidth - (minColumns[index] - 1) * props.columnGap) /
minColumns[index]
)
? clientWidth
: Math.floor((clientWidth - (minColumns[index] - 1) * props.columnGap) / minColumns[index]),
: Math.floor(
(clientWidth - (minColumns[index] - 1) * props.columnGap) /
minColumns[index]
),
columns: target.childNodes.length,
colWrap: colWrap[index],
minColumns: minColumns ? minColumns[index] : 1,
Expand All @@ -119,15 +129,26 @@ const useLayout = (props: ILayoutProps): ILayout => {
// maxWidth 优先级 高于maxColumns
// const minWidthUnderMinColumns = (clientWidth - (maxColumns[index] - 1) * props.columnGap) / maxColumns[index]
return {
maxWidth: isValid(maxWidth)
? maxWidth[index]
: Infinity === Math.floor((clientWidth - (minColumns[index] - 1) * props.columnGap) / minColumns[index])
? clientWidth
: Math.floor((clientWidth - (minColumns[index] - 1) * props.columnGap) / minColumns[index]),
maxWidth: isValid(maxWidth)
? maxWidth[index]
: Infinity ===
Math.floor(
(clientWidth - (minColumns[index] - 1) * props.columnGap) /
minColumns[index]
)
? clientWidth
: Math.floor(
(clientWidth - (minColumns[index] - 1) * props.columnGap) /
minColumns[index]
),
minWidth: isValid(minWidth)
? minWidth[index]
: isValid(maxColumns[index])
? Math.floor((clientWidth - (maxColumns[index] - 1) * props.columnGap) / maxColumns[index]): 0,
? Math.floor(
(clientWidth - (maxColumns[index] - 1) * props.columnGap) /
maxColumns[index]
)
: 0,
minColumns: minColumns ? minColumns[index] : 1,
maxColumns: maxColumns ? maxColumns[index] : undefined,
columns: target.childNodes.length,
Expand All @@ -138,29 +159,30 @@ const useLayout = (props: ILayoutProps): ILayout => {
}

useLayoutEffect(() => {
const observer = () => {
const params = calculateSmartColumns(ref.current)
setLayout(params)
const style = getStyle({ columnGap, rowGap, layoutParams: params, ref })
setStyles(style)
}
const resizeObserver = new ResizeObserver(observer)
const mutationObserver = new MutationObserver(observer)
if (ref.current) {
observer.current = new ResizeObserver((entries) => {
// requestAnimationFrame(() => {
entries.forEach((entry) => {
const target = entry.target as HTMLElement
const params = calculateSmartColumns(target)
setLayout(params)
const style = getStyle({ columnGap, rowGap, layoutParams: params, ref })
setStyles(style)
})
// })
}) as any
observer.current.observe(ref.current)
resizeObserver.observe(ref.current)
mutationObserver.observe(ref.current, {
childList: true,
})
}
return () => {
observer.current?.unobserve(ref.current)
resizeObserver.unobserve(ref.current)
mutationObserver.disconnect()
}
}, [])
return {
ref,
formGridPrefixCls,
layoutParams,
styles
styles,
}
}

Expand All @@ -169,45 +191,56 @@ const getStyle = (props: IStyleProps): IStyle => {
// const max = layoutParams.maxWidth ? `${layoutParams.maxWidth}px` : '1fr';
const { clientWidth, minWidth, maxColumns, minColumns } = layoutParams
const getMinMax = (minWidth: number, maxWidth: number) => {
let minmax
let minmax
if (minWidth === Infinity) {
if (!isValid(maxWidth)) {
minmax = '1fr'
} else {
minmax = `minmax(0px,${maxWidth}px)`
}
} else {
minmax = `minmax(${minWidth}px,${isValid(maxWidth) ? `${maxWidth}px` : '1fr'})`
minmax = `minmax(${minWidth}px,${
isValid(maxWidth) ? `${maxWidth}px` : '1fr'
})`
}
return minmax
}

const spans = Array.from(ref.current?.childNodes || []).reduce((buf, cur: HTMLElement) => {
const span = isValid(maxColumns) ? Math.min((Number(cur.getAttribute('data-span')) || 1) as number, maxColumns) : (Number(cur.getAttribute('data-span')) || 1)
return buf + Number(span)
}, 0)

const spans = Array.from(ref.current?.childNodes || []).reduce(
(buf, cur: HTMLElement) => {
const span = isValid(maxColumns)
? Math.min(
(Number(cur.getAttribute('data-span')) || 1) as number,
maxColumns
)
: Number(cur.getAttribute('data-span')) || 1
return buf + Number(span)
},
0
)

const calc = Math.floor((clientWidth + columnGap) / (minWidth + columnGap))
let finalColumns
finalColumns = Math.min(spans, calc)
if (isValid(maxColumns)) {
finalColumns = Math.min(spans, calc, maxColumns)
} else {

finalColumns = Math.min(spans, calc)
}

if (isValid(minColumns)) {
if(finalColumns < minColumns) {
if (finalColumns < minColumns) {
finalColumns = minColumns
}
}

const style = {
gridTemplateColumns:
`repeat(${finalColumns}, ${getMinMax(layoutParams.minWidth, layoutParams.maxWidth)})`,
gridGap: `${rowGap}px ${columnGap}px`,
}
gridTemplateColumns: `repeat(${finalColumns}, ${getMinMax(
layoutParams.minWidth,
layoutParams.maxWidth
)})`,
gridGap: `${rowGap}px ${columnGap}px`,
}
return style
}

Expand Down Expand Up @@ -257,7 +290,7 @@ export const FormGrid: ComposedFormGrid = (props) => {
)
return (
<FormGridContext.Provider
value={{columnGap: props.columnGap, ...layoutParams}}
value={{ columnGap: props.columnGap, ...layoutParams }}
>
<div
className={cls(`${formGridPrefixCls}-layout`)}
Expand All @@ -271,31 +304,38 @@ export const FormGrid: ComposedFormGrid = (props) => {
}

const GridColumn: React.FC<IGridColumnProps> = ({ gridSpan, children }) => {

const span = FormGrid.useGridSpan(gridSpan)
return (
<div style={{ gridColumnStart: `span ${span}` }} data-span={span || 1}>{children}</div>
<div style={{ gridColumnStart: `span ${span}` }} data-span={span || 1}>
{children}
</div>
)
}


GridColumn.defaultProps = {
gridSpan: 1
gridSpan: 1,
}

FormGrid.useGridSpan = (gridSpan: number) => {
const params = useContext(FormGridContext);
const params = useContext(FormGridContext)
if (!isValid(params)) {
return gridSpan
}
const { colWrap, columns, clientWidth, minWidth, columnGap, maxColumns } = params
const {
colWrap,
columns,
clientWidth,
minWidth,
columnGap,
maxColumns,
} = params
const calc = Math.floor((clientWidth + columnGap) / (minWidth + columnGap)) // 算出实际一行最多能塞进的格子数
if (colWrap === true) {
if (Math.min(calc, columns) >= gridSpan) {
if (isValid(maxColumns)) {
return Math.min(gridSpan, maxColumns)
}
return gridSpan
return gridSpan
} else {
if (isValid(maxColumns)) {
return Math.min(calc, columns, maxColumns)
Expand All @@ -310,10 +350,10 @@ FormGrid.useGridSpan = (gridSpan: number) => {
return gridSpan
} else {
if (isValid(maxColumns)) {
return Math.min(calc,columns, maxColumns)
return Math.min(calc, columns, maxColumns)
}
return Math.min(calc,columns)
}
return Math.min(calc, columns)
}
}
}
FormGrid.GridColumn = GridColumn
Expand Down
Loading

0 comments on commit 35dd3fd

Please sign in to comment.