diff --git a/packages/antd/docs/components/FormGrid.md b/packages/antd/docs/components/FormGrid.md index 64b873412eb..34b2002d69d 100644 --- a/packages/antd/docs/components/FormGrid.md +++ b/packages/antd/docs/components/FormGrid.md @@ -361,17 +361,3 @@ note: | Property name | Type | Description | Default value | | ------------- | ------ | ------------------------------------------------------------------------------------------------------------------------ | ------------- | | gridSpan | number | The number of columns spanned by the element, if it is -1, it will automatically fill the cell across columns in reverse | 1 | - -### FormGrid.useGridSpan - -#### Description - -Calculate the correct span based on the width of the container to prevent element overflow - -#### Signature - -```ts -interface uesGridSpan { - (gridSpan: number): number -} -``` diff --git a/packages/antd/docs/components/FormGrid.zh-CN.md b/packages/antd/docs/components/FormGrid.zh-CN.md index a15aa4d3802..a76b89be4b8 100644 --- a/packages/antd/docs/components/FormGrid.zh-CN.md +++ b/packages/antd/docs/components/FormGrid.zh-CN.md @@ -361,17 +361,3 @@ export default () => { | 属性名 | 类型 | 描述 | 默认值 | | -------- | ------ | ---------------------------------------------------- | ------ | | gridSpan | number | 元素所跨列数,如果为-1,那么会自动反向跨列填补单元格 | 1 | - -### FormGrid.useGridSpan - -#### 描述 - -根据容器宽度计算出正确的 span,防止元素溢出 - -#### 签名 - -```ts -interface uesGridSpan { - (gridSpan: number): number -} -``` diff --git a/packages/antd/src/form-grid/index.tsx b/packages/antd/src/form-grid/index.tsx index ba1ebd054df..47cd38f98dd 100644 --- a/packages/antd/src/form-grid/index.tsx +++ b/packages/antd/src/form-grid/index.tsx @@ -1,4 +1,4 @@ -import React, { useLayoutEffect, useRef, useContext, useMemo } from 'react' +import React, { useLayoutEffect, useRef, useMemo } from 'react' import { observer } from '@formily/react' import { Grid, IGridOptions } from '@formily/grid' import { usePrefixCls, pickDataProps } from '../__builtins__' @@ -21,7 +21,13 @@ export interface IGridColumnProps { type ComposedFormGrid = React.FC & { GridColumn: React.FC + /** + * @deprecated + */ useGridSpan: (gridSpan: number) => number + /** + * @deprecated + */ useGridColumn: (gridSpan: number) => string } @@ -35,14 +41,18 @@ const useFormGrid = (props: IFormGridProps) => { return useMemo(() => new Grid(options), [Grid.id(options)]) } +/** + * @deprecated + */ export const useGridSpan = (gridSpan = 1) => { - const grid = useContext(FormGridContext) - return grid?.calcGridSpan(gridSpan) ?? gridSpan + return gridSpan } +/** + * @deprecated + */ export const useGridColumn = (gridSpan = 1) => { - const span = useGridSpan(gridSpan) - return gridSpan === -1 ? `span ${span} / -1` : `span ${span} / auto` + return gridSpan } export const FormGrid: ComposedFormGrid = observer( @@ -84,13 +94,7 @@ export const FormGrid: ComposedFormGrid = observer( export const GridColumn: React.FC = observer( ({ gridSpan, children, ...props }) => { return ( -
+
{children}
) diff --git a/packages/antd/src/form-item/index.tsx b/packages/antd/src/form-item/index.tsx index a2542313706..936430a5223 100644 --- a/packages/antd/src/form-item/index.tsx +++ b/packages/antd/src/form-item/index.tsx @@ -4,7 +4,6 @@ import { usePrefixCls, pickDataProps } from '../__builtins__' import { isVoidField } from '@formily/core' import { connect, mapProps } from '@formily/react' import { useFormLayout, FormLayoutShallowContext } from '../form-layout' -import { useGridColumn } from '../form-grid' import { Tooltip, Popover } from 'antd' import { QuestionCircleOutlined, @@ -119,7 +118,6 @@ const ICON_MAP = { export const BaseItem: React.FC = ({ children, ...props }) => { const [active, setActive] = useState(false) const formLayout = useFormItemLayout(props) - const gridColumn = useGridColumn(props.gridSpan) const { containerRef, contentRef, overflow } = useOverflow< HTMLDivElement, HTMLLabelElement @@ -200,10 +198,6 @@ export const BaseItem: React.FC = ({ children, ...props }) => { const gridStyles: React.CSSProperties = {} - if (gridColumn) { - gridStyles.gridColumn = gridColumn - } - const getOverflowTooltip = () => { if (overflow) { return ( @@ -278,6 +272,7 @@ export const BaseItem: React.FC = ({ children, ...props }) => { ...style, ...gridStyles, }} + data-grid-span={props.gridSpan} className={cls({ [`${prefixCls}`]: true, [`${prefixCls}-layout-${layout}`]: true, diff --git a/packages/element/docs/guide/form-grid.md b/packages/element/docs/guide/form-grid.md index 919a90b93a9..6de82f3c5f2 100644 --- a/packages/element/docs/guide/form-grid.md +++ b/packages/element/docs/guide/form-grid.md @@ -41,17 +41,3 @@ | 属性名 | 类型 | 描述 | 默认值 | | -------- | ------ | ---------------------------------------------------- | ------ | | gridSpan | number | 元素所跨列数,如果为-1,那么会自动反向跨列填补单元格 | 1 | - -### FormGrid.useGridSpan - -#### 描述 - -根据容器宽度计算出正确的 span,防止元素溢出 - -#### 签名 - -```ts -interface uesGridSpan { - (gridSpan: number): number -} -``` diff --git a/packages/element/src/form-grid/index.ts b/packages/element/src/form-grid/index.ts index a9d8b6933c7..96124ff013a 100644 --- a/packages/element/src/form-grid/index.ts +++ b/packages/element/src/form-grid/index.ts @@ -5,15 +5,12 @@ import { onMounted, InjectionKey, Ref, - inject, computed, watchEffect, } from '@vue/composition-api' -import { isValid, isNum, isBool, isEqual } from '@formily/shared' import { h } from '@formily/vue' import { observer } from '@formily/reactive-vue' import { Grid, IGridOptions } from '@formily/grid' -import ResizeObserver from 'resize-observer-polyfill' import { stylePrefix } from '../__builtins__/configs' import { composeExport } from '../__builtins__/shared' import { useFormLayout } from '../form-layout' @@ -54,15 +51,18 @@ const useFormGrid = (props: IFormGridProps) => { }) } +/** + * @deprecated + */ const useGridSpan = (gridSpan: number) => { - const grid = inject(FormGridSymbol, ref(null)) - - return grid.value?.calcGridSpan(gridSpan) ?? gridSpan + return gridSpan } +/** + * @deprecated + */ export const useGridColumn = (gridSpan = 1) => { - const span = useGridSpan(gridSpan) - return gridSpan === -1 ? `span ${span} / -1` : `span ${span} / auto` + return gridSpan } const FormGridInner = observer( @@ -153,7 +153,9 @@ const FormGridColumn = observer( return h( 'div', { - style: { gridColumn: useGridColumn(props.gridSpan) }, + attrs: { + 'data-grid-span': props.gridSpan, + }, }, slots ) diff --git a/packages/element/src/form-item/index.ts b/packages/element/src/form-item/index.ts index 7f8bc2c6086..d47decbcced 100644 --- a/packages/element/src/form-item/index.ts +++ b/packages/element/src/form-item/index.ts @@ -15,7 +15,6 @@ import { stylePrefix } from '../__builtins__/configs' import { Component } from 'vue' import { Tooltip } from 'element-ui' import ResizeObserver from 'resize-observer-polyfill' -import { useGridColumn } from '../form-grid' export type FormItemProps = { className?: string @@ -153,12 +152,8 @@ export const FormBaseItem = defineComponent({ provide(FormLayoutShallowContext, ref(null)) return () => { - const gridColumn = useGridColumn(props.gridSpan) const gridStyles: Record = {} - if (gridColumn) { - gridStyles.gridColumn = gridColumn - } const deepLayout = deepLayoutRef.value const { label, @@ -456,6 +451,9 @@ export const FormBaseItem = defineComponent({ style: { ...gridStyles, }, + attrs: { + 'data-grid-span': props.gridSpan, + }, class: { [`${prefixCls}`]: true, [`${prefixCls}-layout-${layout}`]: true, diff --git a/packages/grid/src/index.ts b/packages/grid/src/index.ts index e03f74646b7..1b416da62a7 100644 --- a/packages/grid/src/index.ts +++ b/packages/grid/src/index.ts @@ -38,32 +38,37 @@ const calcFactor = (value: T | T[], breakpointIndex: number): T => { } const parseGridNode = (elements: HTMLCollection): GridNode[] => { - let index = 0 - return Array.from(elements).map((element) => { + return Array.from(elements).reduce((buf, element) => { const style = getComputedStyle(element) - const origin = element.getAttribute('data-origin-span') + const visible = !(style.display === 'none') + const origin = element.getAttribute('data-grid-span') const span = parseSpan(style.gridColumnStart) ?? 1 const originSpan = Number(origin ?? span) if (!origin) { - element.setAttribute('data-origin-span', String(span)) + element.setAttribute('data-grid-span', String(span)) } - const start = index - const end = (index += span) - 1 - return { - start, - end, + return buf.concat({ span, + visible, originSpan, element, - } - }) + }) + }, []) } const calcChildTotalColumns = (nodes: GridNode[]) => - nodes.reduce((buf, node) => buf + node.span, 0) + nodes.reduce((buf, node) => { + if (!node.visible) return buf + if (node.originSpan === -1) return buf + 1 + return buf + node.span + }, 0) const calcChildOriginTotalColumns = (nodes: GridNode[]) => - nodes.reduce((buf, node) => buf + node.originSpan, 0) + nodes.reduce((buf, node) => { + if (!node.visible) return buf + if (node.originSpan === -1) return buf + 1 + return buf + node.originSpan + }, 0) const calcSatisfyColumns = ( width: number, @@ -95,12 +100,39 @@ const parseSpan = (gridColumnStart: string) => { const factor = (value: T | T[], grid: Grid): T => isValid(value) ? calcFactor(value as any, grid.breakpoint) : value +const resolveChildren = (grid: Grid) => { + let walked = 0, + rowIndex = 0 + if (!grid.ready) return + grid.children = grid.children.map((node) => { + if (!node.visible) return node + const columnIndex = walked % grid.columns + const remainColumns = grid.columns - columnIndex + const originSpan = node.originSpan + const targetSpan = originSpan > grid.columns ? grid.columns : originSpan + const span = targetSpan > remainColumns ? remainColumns : targetSpan + const gridColumn = + originSpan === -1 ? `span ${remainColumns} / -1` : `span ${span} / auto` + if (node.element.style.gridColumn !== gridColumn) { + node.element.style.gridColumn = gridColumn + } + walked += span + if (columnIndex === 0) { + rowIndex++ + } + node.row = rowIndex + node.column = columnIndex + 1 + return node + }) +} + export type GridNode = { - start?: number - end?: number + visible?: boolean + column?: number + row?: number span?: number originSpan?: number - element?: Element + element?: HTMLElement } export class Grid { options: IGridOptions @@ -258,15 +290,19 @@ export class Grid { this.width = rect.width this.height = rect.height } - this.options?.onDigest?.(this) + resolveChildren(this) + if (this.ready) { + this.options?.onDigest?.(this) + } }) const mutationObserver = new MutationObserver(digest) const resizeObserver = new ResizeObserver(digest) resizeObserver.observe(this.container) mutationObserver.observe(this.container, { - attributeFilter: ['style'], + attributeFilter: ['style', 'class'], attributes: true, childList: true, + subtree: true, }) initialize() return () => { @@ -280,23 +316,11 @@ export class Grid { return () => {} } + /** + * @deprecated + */ calcGridSpan = (span: number) => { - if (!this.ready) { - return span - } - if (span === -1) { - const prevOriginTotalColumns = this.childOriginTotalColumns - 1 - const prevTotalColumns = this.childTotalColumns - 1 - const remainTotalColumns = this.columns - prevOriginTotalColumns - const remainOriginTotalColumns = this.columns - prevTotalColumns - const minRemainTotalColumns = Math.max( - remainTotalColumns, - remainOriginTotalColumns - ) - if (minRemainTotalColumns < 0) return 1 - return minRemainTotalColumns > 0 ? minRemainTotalColumns : this.columns - } - return this.columns < span ? this.columns : span + return span } static id = (options: IGridOptions = {}) => diff --git a/packages/next/docs/components/FormGrid.md b/packages/next/docs/components/FormGrid.md index 8c658ee102e..21358f3527f 100644 --- a/packages/next/docs/components/FormGrid.md +++ b/packages/next/docs/components/FormGrid.md @@ -361,17 +361,3 @@ note: | Property name | Type | Description | Default value | | ------------- | ------ | ------------------------------------------------------------------------------------------------------------------------ | ------------- | | gridSpan | number | The number of columns spanned by the element, if it is -1, it will automatically fill the cell across columns in reverse | 1 | - -### FormGrid.useGridSpan - -#### Description - -Calculate the correct span based on the width of the container to prevent element overflow - -#### Signature - -```ts -interface uesGridSpan { - (gridSpan: number): number -} -``` diff --git a/packages/next/docs/components/FormGrid.zh-CN.md b/packages/next/docs/components/FormGrid.zh-CN.md index 1c8106c1902..f1b6f25a7d9 100644 --- a/packages/next/docs/components/FormGrid.zh-CN.md +++ b/packages/next/docs/components/FormGrid.zh-CN.md @@ -361,17 +361,3 @@ export default () => { | 属性名 | 类型 | 描述 | 默认值 | | -------- | ------ | ----------------------------------------------------- | ------ | | gridSpan | number | 元素所跨列数 ,如果为-1,那么会自动反向跨列填补单元格 | 1 | - -### FormGrid.useGridSpan - -#### 描述 - -根据容器宽度计算出正确的 span,防止元素溢出 - -#### 签名 - -```ts -interface uesGridSpan { - (gridSpan: number): number -} -``` diff --git a/packages/next/src/form-grid/index.tsx b/packages/next/src/form-grid/index.tsx index d945e98e4d0..9539adfe95a 100644 --- a/packages/next/src/form-grid/index.tsx +++ b/packages/next/src/form-grid/index.tsx @@ -1,4 +1,4 @@ -import React, { useLayoutEffect, useRef, useContext, useMemo } from 'react' +import React, { useLayoutEffect, useRef, useMemo } from 'react' import { observer } from '@formily/react' import { Grid, IGridOptions } from '@formily/grid' import { usePrefixCls, pickDataProps } from '../__builtins__' @@ -21,7 +21,13 @@ export interface IGridColumnProps { type ComposedFormGrid = React.FC & { GridColumn: React.FC + /** + * @deprecated + */ useGridSpan: (gridSpan: number) => number + /** + * @deprecated + */ useGridColumn: (gridSpan: number) => string } @@ -35,14 +41,17 @@ const useFormGrid = (props: IFormGridProps) => { return useMemo(() => new Grid(options), [Grid.id(options)]) } +/** + * @deprecated + */ export const useGridSpan = (gridSpan = 1) => { - const grid = useContext(FormGridContext) - return grid?.calcGridSpan(gridSpan) ?? gridSpan + return gridSpan } - +/** + * @deprecated + */ export const useGridColumn = (gridSpan = 1) => { - const span = useGridSpan(gridSpan) - return gridSpan === -1 ? `span ${span} / -1` : `span ${span} / auto` + return gridSpan } export const FormGrid: ComposedFormGrid = observer( @@ -84,13 +93,7 @@ export const FormGrid: ComposedFormGrid = observer( export const GridColumn: React.FC = observer( ({ gridSpan, children, ...props }) => { return ( -
+
{children}
) diff --git a/packages/next/src/form-item/index.tsx b/packages/next/src/form-item/index.tsx index 19c3b5b3870..44ee98cb326 100644 --- a/packages/next/src/form-item/index.tsx +++ b/packages/next/src/form-item/index.tsx @@ -4,7 +4,6 @@ import { usePrefixCls, pickDataProps } from '../__builtins__' import { isVoidField } from '@formily/core' import { connect, mapProps } from '@formily/react' import { useFormLayout, FormLayoutShallowContext } from '../form-layout' -import { useGridColumn } from '../form-grid' import { Balloon } from '@alifd/next' import { QuestionCircleOutlined, @@ -119,7 +118,6 @@ const ICON_MAP = { export const BaseItem: React.FC = (props) => { const { children, ...others } = props const [active, setActive] = useState(false) - const gridColumn = useGridColumn(props.gridSpan) const formLayout = useFormItemLayout(others) const { containerRef, contentRef, overflow } = useOverflow< HTMLDivElement, @@ -200,10 +198,6 @@ export const BaseItem: React.FC = (props) => { const gridStyles: React.CSSProperties = {} - if (gridColumn) { - gridStyles.gridColumn = gridColumn - } - const getOverflowTooltip = () => { if (overflow) { return ( @@ -276,6 +270,7 @@ export const BaseItem: React.FC = (props) => { ...style, ...gridStyles, }} + data-grid-span={props.gridSpan} className={cls({ [`${prefixCls}`]: true, [`${prefixCls}-layout-${layout}`]: true,