diff --git a/packages/components/package.json b/packages/components/package.json index acb32a8..58c7fca 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -28,12 +28,13 @@ "typings": "lib/index.d.ts", "scripts": { "build": "formily-tpl build", - "start": "dumi dev", - "release": "npm run build && npm version patch -m 'chore: publish release [patch]' && npm publish" + "release": "npm run build && npm version patch -m 'chore: publish release [patch]' && npm publish", + "start": "dumi dev" }, "dependencies": { + "@dnd-kit/core": "^6.0.0", + "@dnd-kit/sortable": "^7.0.0", "dayjs": "^1.10.7", - "react-sortable-hoc": "^2.0.0", "react-sticky-box": "^0.9.3" }, "devDependencies": { diff --git a/packages/components/src/__builtins__/index.ts b/packages/components/src/__builtins__/index.ts index 4d1f08c..be230ae 100644 --- a/packages/components/src/__builtins__/index.ts +++ b/packages/components/src/__builtins__/index.ts @@ -3,3 +3,4 @@ export * from "./moment"; export * from "./pickDataProps"; export * from "./portal"; export * from "./loading"; +export * from "./sort"; diff --git a/packages/components/src/__builtins__/sort.tsx b/packages/components/src/__builtins__/sort.tsx new file mode 100644 index 0000000..f570b5b --- /dev/null +++ b/packages/components/src/__builtins__/sort.tsx @@ -0,0 +1,143 @@ +import { DndContext, DragEndEvent, DragStartEvent } from "@dnd-kit/core"; +import { + SortableContext, + useSortable, + verticalListSortingStrategy, +} from "@dnd-kit/sortable"; +import { ReactFC } from "@formily/reactive-react"; +import React, { createContext, useContext, useMemo } from "react"; + +export interface ISortableContainerProps { + list: any[]; + start?: number; + accessibility?: { + container?: Element; + }; + onSortStart?: (event: DragStartEvent) => void; + onSortEnd?: (event: { oldIndex: number; newIndex: number }) => void; +} + +export function SortableContainer>( + Component: ReactFC +): ReactFC { + return ({ + list, + start = 0, + accessibility, + onSortStart, + onSortEnd, + ...props + }) => { + const _onSortEnd = (event: DragEndEvent) => { + const { active, over } = event; + const oldIndex = (active.id as number) - 1; + const newIndex = (over?.id as number) - 1; + onSortEnd?.({ + oldIndex, + newIndex, + }); + }; + + return ( + + index + start + 1)} + strategy={verticalListSortingStrategy} + > + {props.children} + + + ); + }; +} + +export const useSortableItem = () => { + return useContext(SortableItemContext); +}; + +export const SortableItemContext = createContext< + Partial> +>({}); + +export interface ISortableElementProps { + index?: number; + lockAxis?: "x" | "y"; +} + +export function SortableElement>( + Component: ReactFC +): ReactFC { + return ({ index = 0, lockAxis, ...props }) => { + const sortable = useSortable({ + id: index + 1, + }); + const { setNodeRef, transform, transition, isDragging } = sortable; + if (transform) { + switch (lockAxis) { + case "x": + transform.y = 0; + break; + case "y": + transform.x = 0; + break; + default: + break; + } + } + + const style = useMemo(() => { + const itemStyle: React.CSSProperties = { + position: "relative", + touchAction: "none", + zIndex: 1, + transform: `translate3d(${transform?.x || 0}px, ${ + transform?.y || 0 + }px, 0)`, + transition: `${transform ? "all 200ms ease" : ""}`, + }; + const dragStyle: React.CSSProperties = { + transition, + opacity: "0.8", + transform: `translate3d(${transform?.x || 0}px, ${ + transform?.y || 0 + }px, 0)`, + }; + + const computedStyle = isDragging + ? { + ...itemStyle, + ...dragStyle, + ...props.style, + } + : { + ...itemStyle, + ...props.style, + }; + + return computedStyle; + }, [isDragging, transform, transition, props.style]); + + return ( + + {Component({ + ...props, + style, + ref: setNodeRef, + } as unknown as T)} + + ); + }; +} + +export function SortableHandle>( + Component: ReactFC +): ReactFC { + return (props: T) => { + const { attributes, listeners } = useSortableItem(); + return ; + }; +} diff --git a/packages/components/src/array-base/index.scss b/packages/components/src/array-base/index.scss index 1192d0f..3eab216 100644 --- a/packages/components/src/array-base/index.scss +++ b/packages/components/src/array-base/index.scss @@ -1,10 +1,9 @@ -@import '../__styles__/theme.scss'; - -$array-base-prefix-cls: '#{$semi-form-prefix}-array-base'; +@import "../__styles__/theme.scss"; +$array-base-prefix-cls: "#{$semi-form-prefix}-array-base"; .#{$array-base-prefix-cls}-remove { - transition: all .25s ease-in-out; + transition: all 0.25s ease-in-out; font-size: 16px; cursor: pointer; @@ -13,17 +12,17 @@ $array-base-prefix-cls: '#{$semi-form-prefix}-array-base'; } } -.#{array-base-prefix-cls}-sort-handle { +.#{$array-base-prefix-cls}-sort-handle { cursor: move; color: #888 !important; } .#{$array-base-prefix-cls}-addition { - transition: all .25s ease-in-out; + transition: all 0.25s ease-in-out; } .#{$array-base-prefix-cls}-move-down { - transition: all .25s ease-in-out; + transition: all 0.25s ease-in-out; font-size: 16px; margin-left: 6px; @@ -33,7 +32,7 @@ $array-base-prefix-cls: '#{$semi-form-prefix}-array-base'; } .#{$array-base-prefix-cls}-move-up { - transition: all .25s ease-in-out; + transition: all 0.25s ease-in-out; font-size: 16px; margin-left: 6px; diff --git a/packages/components/src/array-base/index.tsx b/packages/components/src/array-base/index.tsx index 1bbe102..1ec77d1 100644 --- a/packages/components/src/array-base/index.tsx +++ b/packages/components/src/array-base/index.tsx @@ -1,22 +1,21 @@ -import React, { createContext, useContext } from 'react'; -import { Button } from '@douyinfe/semi-ui'; +import React, { createContext, useContext } from "react"; +import { Button } from "@douyinfe/semi-ui"; import { ButtonProps } from "@douyinfe/semi-ui/lib/es/button"; import { IconPlus, IconDelete, IconMenu, IconChevronDown, - IconChevronUp -} from '@douyinfe/semi-icons'; + IconChevronUp, +} from "@douyinfe/semi-icons"; import { IconProps as SemiIconProps } from "@douyinfe/semi-ui/lib/es/icons"; -import { useField, useFieldSchema, Schema, JSXComponent } from '@formily/react'; -import { ArrayField } from '@formily/core'; -import { isValid } from '@formily/shared'; -import { SortableHandle } from 'react-sortable-hoc'; -import cls from 'classnames'; +import { useField, useFieldSchema, Schema, JSXComponent } from "@formily/react"; +import { ArrayField } from "@formily/core"; +import { isValid } from "@formily/shared"; +import cls from "classnames"; -import './index.scss'; -import { usePrefixCls } from '../__builtins__'; +import "./index.scss"; +import { usePrefixCls, SortableHandle } from "../__builtins__"; interface IconProps extends SemiIconProps { style?: React.CSSProperties; @@ -25,7 +24,7 @@ interface IconProps extends SemiIconProps { export interface IArrayBaseAdditionProps extends ButtonProps { title?: string; - method?: 'push' | 'unshift'; + method?: "push" | "unshift"; } export interface IArrayBaseProps { @@ -57,7 +56,7 @@ export type ArrayBaseMixins = { Index?: React.FC; useArray?: () => IArrayBaseContext; useIndex?: () => number; - useRecord?: (record?: number) => any + useRecord?: (record?: number) => any; }; type ComposedArrayBase = React.FC> & @@ -78,21 +77,21 @@ const useIndex = (index?: number) => { }; const useRecord = (record?: number) => { - const ctx = useContext(ItemContext) - return ctx ? ctx.record : record -} + const ctx = useContext(ItemContext); + return ctx ? ctx.record : record; +}; const getDefaultValue = (defaultValue: any, schema: Schema) => { if (isValid(defaultValue)) return defaultValue; if (Array.isArray(schema?.items)) return getDefaultValue(defaultValue, schema.items[0]); - if (schema?.items?.type === 'array') return []; - if (schema?.items?.type === 'boolean') return true; - if (schema?.items?.type === 'date') return ''; - if (schema?.items?.type === 'datetime') return ''; - if (schema?.items?.type === 'number') return 0; - if (schema?.items?.type === 'object') return {}; - if (schema?.items?.type === 'string') return ''; + if (schema?.items?.type === "array") return []; + if (schema?.items?.type === "boolean") return true; + if (schema?.items?.type === "date") return ""; + if (schema?.items?.type === "datetime") return ""; + if (schema?.items?.type === "number") return 0; + if (schema?.items?.type === "object") return {}; + if (schema?.items?.type === "string") return ""; return null; }; @@ -111,27 +110,27 @@ ArrayBase.Item = ({ children, ...props }: any) => ( ); const SortHandle = SortableHandle((props: any) => { - const prefixCls = usePrefixCls('array-base') + const prefixCls = usePrefixCls("array-base"); return ( - ) -}) as any + ); +}) as any; ArrayBase.SortHandle = (props) => { const array = useArray(); if (!array) return null; - if (array.field?.pattern !== 'editable') return null; + if (array.field?.pattern !== "editable") return null; return ; }; const Index = (props) => { const { renderIndex } = props; const index = useIndex(); - const prefixCls = usePrefixCls('array-base'); + const prefixCls = usePrefixCls("array-base"); return ( {renderIndex?.(index) ?? `#${index + 1}.`} @@ -144,11 +143,11 @@ ArrayBase.Index = Index; const Addition = (props) => { const self = useField(); const array = useArray(); - const prefixCls = usePrefixCls('array-base'); + const prefixCls = usePrefixCls("array-base"); if (!array) return null; if ( - array?.field?.pattern !== 'editable' && - array?.field?.pattern !== 'disabled' + array?.field?.pattern !== "editable" && + array?.field?.pattern !== "disabled" ) { return null; } @@ -161,7 +160,7 @@ const Addition = (props) => { onClick={(e) => { if (array.props?.disabled) return; const defaultValue = getDefaultValue(props.defaultValue, array.schema); - if (props.method === 'unshift') { + if (props.method === "unshift") { array?.field?.unshift(defaultValue); array.props?.onAdd?.(0); } else { @@ -184,9 +183,9 @@ ArrayBase.Addition = Addition; ArrayBase.Remove = React.forwardRef((props, ref) => { const index = useIndex(); const array = useArray(); - const prefixCls = usePrefixCls('array-base'); + const prefixCls = usePrefixCls("array-base"); if (!array) return null; - if (array?.field?.pattern !== 'editable') return null; + if (array?.field?.pattern !== "editable") return null; return ( { ArrayBase.MoveDown = React.forwardRef((props, ref) => { const index = useIndex(props.index); const array = useArray(); - const prefixCls = usePrefixCls('array-base-move-down'); - if (array?.field?.pattern !== 'editable') return null; + const prefixCls = usePrefixCls("array-base-move-down"); + if (array?.field?.pattern !== "editable") return null; return ( { ArrayBase.MoveUp = React.forwardRef((props, ref) => { const index = useIndex(props.index); const array = useArray(); - const prefixCls = usePrefixCls('array-base-move-up'); - if (array?.field?.pattern !== 'editable') return null; + const prefixCls = usePrefixCls("array-base-move-up"); + if (array?.field?.pattern !== "editable") return null; return ( { className={cls(prefixCls, props.className)} > { field.move(oldIndex, newIndex); }} @@ -86,7 +88,7 @@ export const ArrayItems: ComposedArrayItems = observer((props) => { : schema.items; return ( - +
diff --git a/packages/components/src/array-table/demo/config.ts b/packages/components/src/array-table/demo/config.ts index 86b7ca3..871ca4e 100644 --- a/packages/components/src/array-table/demo/config.ts +++ b/packages/components/src/array-table/demo/config.ts @@ -1,123 +1,123 @@ import { ISchema } from "@formily/json-schema"; export default { - type: 'object', + type: "object", properties: { array_table: { - type: 'array', - 'x-decorator': 'FormItem', - 'x-component': 'ArrayTable', - 'x-component-props': { - pagination: { pageSize: 10 }, - scroll: { x: '100%' }, + type: "array", + "x-decorator": "FormItem", + "x-component": "ArrayTable", + "x-component-props": { + pagination: { pageSize: 5 }, + scroll: { x: "100%" }, arrayBaseProps: { - onRemove: console.log - } + onRemove: console.log, + }, }, items: { - type: 'object', + type: "object", properties: { column1: { - type: 'void', - 'x-component': 'ArrayTable.Column', - 'x-component-props': { width: 50, title: 'Sort', align: 'center' }, + type: "void", + "x-component": "ArrayTable.Column", + "x-component-props": { width: 50, title: "Sort", align: "center" }, properties: { sort: { - type: 'void', - 'x-component': 'ArrayTable.SortHandle' - } - } + type: "void", + "x-component": "ArrayTable.SortHandle", + }, + }, }, column2: { - type: 'void', - 'x-component': 'ArrayTable.Column', - 'x-component-props': { width: 80, title: 'Index', align: 'center' }, + type: "void", + "x-component": "ArrayTable.Column", + "x-component-props": { width: 80, title: "Index", align: "center" }, properties: { index: { - type: 'void', - 'x-component': 'ArrayTable.Index', + type: "void", + "x-component": "ArrayTable.Index", }, }, }, column3: { - type: 'void', - 'x-component': 'ArrayTable.Column', - 'x-component-props': { width: 200, title: 'A1' }, + type: "void", + "x-component": "ArrayTable.Column", + "x-component-props": { width: 200, title: "A1" }, properties: { a1: { - type: 'string', + type: "string", required: true, - 'x-decorator': 'FormItem', - 'x-component': 'Input', + "x-decorator": "FormItem", + "x-component": "Input", }, }, }, column4: { - type: 'void', - 'x-component': 'ArrayTable.Column', - 'x-component-props': { width: 200, title: 'A2' }, + type: "void", + "x-component": "ArrayTable.Column", + "x-component-props": { width: 200, title: "A2" }, properties: { a2: { - type: 'string', - 'x-decorator': 'FormItem', - 'x-component': 'Switch', + type: "string", + "x-decorator": "FormItem", + "x-component": "Switch", }, }, }, column5: { - type: 'void', - 'x-component': 'ArrayTable.Column', - 'x-component-props': { width: 200, title: 'A3' }, + type: "void", + "x-component": "ArrayTable.Column", + "x-component-props": { width: 200, title: "A3" }, properties: { a3: { - type: 'string', - 'x-decorator': 'FormItem', - 'x-component': 'Input.TextArea', + type: "string", + "x-decorator": "FormItem", + "x-component": "Input.TextArea", }, }, }, column6: { - type: 'void', - 'x-component': 'ArrayTable.Column', - 'x-component-props': { - title: 'Operations', - dataIndex: 'operations', + type: "void", + "x-component": "ArrayTable.Column", + "x-component-props": { + title: "Operations", + dataIndex: "operations", width: 200, - fixed: 'right', + fixed: "right", }, properties: { item: { - type: 'void', - 'x-component': 'FormItem', + type: "void", + "x-component": "FormItem", properties: { remove: { - type: 'void', - 'x-component': 'ArrayTable.Remove', + type: "void", + "x-component": "ArrayTable.Remove", }, moveDown: { - type: 'void', - 'x-component': 'ArrayTable.MoveDown', + type: "void", + "x-component": "ArrayTable.MoveDown", }, moveUp: { - type: 'void', - 'x-component': 'ArrayTable.MoveUp', + type: "void", + "x-component": "ArrayTable.MoveUp", }, }, }, }, }, - } + }, }, properties: { add: { - type: 'void', - 'x-component': 'ArrayTable.Addition', - 'x-component-props': { - method: 'unshift' + type: "void", + "x-component": "ArrayTable.Addition", + "x-component-props": { + // method: 'unshift' }, - title: '添加条目', + title: "添加条目", }, }, - } - } -} as ISchema + }, + }, +} as ISchema; diff --git a/packages/components/src/array-table/index.scss b/packages/components/src/array-table/index.scss index 2875776..b2e97b1 100644 --- a/packages/components/src/array-table/index.scss +++ b/packages/components/src/array-table/index.scss @@ -1,6 +1,6 @@ -@import '../__styles__/theme.scss'; +@import "../__styles__/theme.scss"; -$array-table-prefix-cls: '#{$semi-form-prefix}-array-table'; +$array-table-prefix-cls: "#{$semi-form-prefix}-array-table"; .#{$array-table-prefix-cls} { .#{$array-table-prefix-cls}-pagination { @@ -15,6 +15,8 @@ $array-table-prefix-cls: '#{$semi-form-prefix}-array-table'; } .#{$semi-prefix}-table { + overflow: hidden; + td { visibility: visible; diff --git a/packages/components/src/array-table/index.tsx b/packages/components/src/array-table/index.tsx index 32b2ba5..19c9508 100644 --- a/packages/components/src/array-table/index.tsx +++ b/packages/components/src/array-table/index.tsx @@ -2,16 +2,15 @@ import React, { Fragment, useState, useRef, - forwardRef, - useContext, useEffect, + createContext, + useContext, } from "react"; import { Table, Pagination, Space, Select, Badge } from "@douyinfe/semi-ui"; import { PaginationProps } from "@douyinfe/semi-ui/lib/es/pagination"; import { TableProps, ColumnProps } from "@douyinfe/semi-ui/lib/es/table"; import { SelectProps } from "@douyinfe/semi-ui/lib/es/select"; import cls from "classnames"; -import { SortableContainer, SortableElement } from "react-sortable-hoc"; import { GeneralField, FieldDisplayTypes, ArrayField } from "@formily/core"; import { useField, @@ -19,11 +18,15 @@ import { useFieldSchema, RecursionField, } from "@formily/react"; -import { isArr, isBool, uid } from "@formily/shared"; +import { isArr, isBool, isFn, uid } from "@formily/shared"; import { Schema } from "@formily/json-schema"; import "./index.scss"; -import { usePrefixCls } from "../__builtins__"; +import { + usePrefixCls, + SortableContainer, + SortableElement, +} from "../__builtins__"; import { ArrayBase, ArrayBaseMixins, IArrayBaseProps } from "../array-base"; interface ObservableColumnSource { @@ -35,9 +38,13 @@ interface ObservableColumnSource { } interface IArrayTablePaginationProps extends PaginationProps { dataSource?: any[]; + showPagination?: boolean; children?: ( dataSource: any[], - pagination: React.ReactNode + pagination: React.ReactNode, + options: { + startIndex: number; + } ) => React.ReactElement; } @@ -45,11 +52,23 @@ interface IStatusSelectProps extends SelectProps { pageSize?: number; } -type ComposedArrayTable = React.FC> & +type ComposedArrayTable = React.FC< + TableProps & + IArrayBaseProps & { + arrayBaseProps: IArrayBaseProps; + } +> & ArrayBaseMixins & { Column?: React.FC>; }; +interface PaginationAction { + totalPage?: number; + pageSize?: number; + showPagination?: boolean; + changePage?: (page: number) => void; +} + const SortableRow = SortableElement((props: any) => ); const SortableBody = SortableContainer((props: any) => ); @@ -99,6 +118,7 @@ const useArrayTableSources = () => { }; const parseArrayItems = (schema: Schema["items"]) => { + if (!schema) return []; const sources: ObservableColumnSource[] = []; const items = isArr(schema) ? schema : [schema]; return items.reduce((columns, schema) => { @@ -127,10 +147,10 @@ const useArrayTableColumns = ( ...columnProps, key, dataIndex: name, - render: (value: any, record: any) => { + render: (_: any, record: any) => { const index = dataSource.indexOf(record); const children = ( - + record}> = observer( } ); +const PaginationContext = createContext({}); +const usePagination = () => { + return useContext(PaginationContext); +}; + const ArrayTablePagination: React.FC = (props) => { const [current, setCurrent] = useState(1); const prefixCls = usePrefixCls("array-table"); + const showPagination = props.showPagination ?? true; const pageSize = props.pageSize || 10; const size = props.size || "default"; const dataSource = props.dataSource || []; @@ -237,7 +263,7 @@ const ArrayTablePagination: React.FC = (props) => { }, [totalPage, current]); const renderPagination = () => { - if (totalPage <= 1) return; + if (totalPage <= 1 || !showPagination) return; return (
@@ -264,10 +290,22 @@ const ArrayTablePagination: React.FC = (props) => { return ( - {props.children?.( - dataSource?.slice(startIndex, endIndex + 1), - renderPagination() - )} + + {props.children?.( + showPagination + ? dataSource?.slice(startIndex, endIndex + 1) + : dataSource, + renderPagination(), + { startIndex } + )} + ); }; @@ -277,14 +315,17 @@ const ArrayTableComponentsContext = React.createContext<{ field?: ArrayField; }>({}); -const ArrayTableWrapper: React.FC = (props: any) => { - const { ref, field } = useContext(ArrayTableComponentsContext); - const prefixCls = usePrefixCls("formily-array-table"); +const getWrapperComp: (dataSource: any[], start: number) => React.FC = + (dataSource, start) => (props) => { + const { ref, field } = useContext(ArrayTableComponentsContext); + const prefixCls = usePrefixCls("formily-array-table"); - const addTdStyles = (node: HTMLElement) => { - const helper = document.body.querySelector(`.${prefixCls}-sort-helper`); - if (helper) { + const addTdStyles = (id: number) => { + const node = ref.current?.querySelector(`.${prefixCls}-row-${id}`); + const helper = document.body.querySelector(`.${prefixCls}-sort-helper`); + if (!helper) return; const tds = node.querySelectorAll("td"); + if (!tds) return; requestAnimationFrame(() => { helper.querySelectorAll("td").forEach((td, index) => { if (tds[index]) { @@ -292,27 +333,26 @@ const ArrayTableWrapper: React.FC = (props: any) => { } }); }); - } - }; + }; - return ( - { - return ref?.current?.querySelector("tbody"); - }} - onSortStart={({ node }) => { - addTdStyles(node); - }} - onSortEnd={({ oldIndex, newIndex }) => { - field?.move(oldIndex, newIndex); - }} - {...props} - /> - ); -}; + return ( + { + addTdStyles(event.active.id); + }} + onSortEnd={({ oldIndex, newIndex }) => { + field?.move(oldIndex, newIndex); + }} + className={cls(`${prefixCls}-sort-helper`, props.className)} + /> + ); + }; /** * 这里将Table.components写在函数外,使得components避免不必要的更新 @@ -320,67 +360,74 @@ const ArrayTableWrapper: React.FC = (props: any) => { * 原因:如果每次render时Table每次都拿到一个新的对象。Table内部是lodash.merge深拷贝了一份这个对象,导致components.body.row & wrapper每次都会变。 * 当在array-table中用如文件上传组件时,会将原先的input销毁,导致没法监听到组件的onChange事件 */ -const arrayTableComponents = { +const getArrayTableComponents = (dataSource: any[], startIndex: number) => ({ body: { - wrapper: ArrayTableWrapper, - row: forwardRef((props: any, ref) => { - return ; - }), + wrapper: getWrapperComp(dataSource, startIndex), + row: (props: any) => { + const prefixCls = usePrefixCls("formily-array-table"); + const index = props.index || props["data-row-key"] || 0; + return ( + + ); + }, }, -}; +}); -export const ArrayTable: ComposedArrayTable = observer( - (props: TableProps & { arrayBaseProps: IArrayBaseProps }) => { - const ref: any = useRef(); - const field = useField(); - const prefixCls = usePrefixCls("array-table"); - const dataSource = Array.isArray(field.value) ? field.value.slice() : []; - const sources = useArrayTableSources(); - const columns = useArrayTableColumns(dataSource, sources); - const pagination = isBool(props.pagination) ? {} : props.pagination; - const addition = useAddition(); - const defaultRowKey = () => uid().toString(); +export const ArrayTable: ComposedArrayTable = observer((props) => { + const ref: any = useRef(); + const field = useField(); + const prefixCls = usePrefixCls("array-table"); + const dataSource = Array.isArray(field.value) ? field.value.slice() : []; + const sources = useArrayTableSources(); + const columns = useArrayTableColumns(dataSource, sources); + const pagination = isBool(props.pagination) ? {} : props.pagination; + const addition = useAddition(); + const defaultRowKey = () => uid().toString(); - return ( - - {(innerDataSource, pager) => ( -
- - - {}} - pagination={false} - columns={columns} - dataSource={innerDataSource} - components={arrayTableComponents} - onRow={(record) => ({ - index: dataSource.indexOf(record), - })} - /> - -
{pager}
- {sources.map((column, key) => { - // 承接对Column的状态管理 - if (!isColumnComponent(column.schema)) return; - return React.createElement(RecursionField, { - name: column.name, - schema: column.schema, - onlyRenderSelf: true, - key, - }); - })} - {addition} - - - )} - - ); - } -); + return ( + + {(innerDataSource, pager, { startIndex }) => ( +
+ + +
{}} + pagination={false} + columns={columns} + dataSource={innerDataSource} + components={getArrayTableComponents(dataSource, startIndex)} + onRow={(record) => ({ + index: dataSource.indexOf(record), + })} + /> + +
{pager}
+ {sources.map((column, key) => { + // 承接对Column的状态管理 + if (!isColumnComponent(column.schema)) return; + return React.createElement(RecursionField, { + name: column.name, + schema: column.schema, + onlyRenderSelf: true, + key, + }); + })} + {addition} + + + )} + + ); +}); ArrayTable.displayName = "ArrayTable"; @@ -390,4 +437,32 @@ ArrayTable.Column = () => { ArrayBase.mixin(ArrayTable); +const Addition: ArrayBaseMixins["Addition"] = (props) => { + const array = ArrayBase.useArray(); + const { + totalPage = 0, + pageSize = 10, + changePage, + showPagination, + } = usePagination(); + return ( + { + // 如果添加数据后将超过当前页,则自动切换到下一页 + const total = array?.field?.value.length || 0; + if ( + showPagination && + total === totalPage * pageSize + 1 && + isFn(changePage) + ) { + changePage(totalPage + 1); + } + props.onClick?.(e); + }} + /> + ); +}; +ArrayTable.Addition = Addition; + export default ArrayTable; diff --git a/yarn.lock b/yarn.lock index 2b6ce08..43c0b42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -497,6 +497,37 @@ resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== +"@dnd-kit/accessibility@^3.1.0": + version "3.1.0" + resolved "https://bnpm.byted.org/@dnd-kit/accessibility/-/accessibility-3.1.0.tgz#1054e19be276b5f1154ced7947fc0cb5d99192e0" + integrity sha512-ea7IkhKvlJUv9iSHJOnxinBcoOI3ppGnnL+VDJ75O45Nss6HtZd8IdN8touXPDtASfeI2T2LImb8VOZcL47wjQ== + dependencies: + tslib "^2.0.0" + +"@dnd-kit/core@^6.0.0": + version "6.1.0" + resolved "https://bnpm.byted.org/@dnd-kit/core/-/core-6.1.0.tgz#e81a3d10d9eca5d3b01cbf054171273a3fe01def" + integrity sha512-J3cQBClB4TVxwGo3KEjssGEXNJqGVWx17aRTZ1ob0FliR5IjYgTxl5YJbKTzA6IzrtelotH19v6y7uoIRUZPSg== + dependencies: + "@dnd-kit/accessibility" "^3.1.0" + "@dnd-kit/utilities" "^3.2.2" + tslib "^2.0.0" + +"@dnd-kit/sortable@^7.0.0": + version "7.0.2" + resolved "https://bnpm.byted.org/@dnd-kit/sortable/-/sortable-7.0.2.tgz#791d550872457f3f3c843e00d159b640f982011c" + integrity sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA== + dependencies: + "@dnd-kit/utilities" "^3.2.0" + tslib "^2.0.0" + +"@dnd-kit/utilities@^3.2.0", "@dnd-kit/utilities@^3.2.2": + version "3.2.2" + resolved "https://bnpm.byted.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz#5a32b6af356dc5f74d61b37d6f7129a4040ced7b" + integrity sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg== + dependencies: + tslib "^2.0.0" + "@douyinfe/semi-animation-react@2.5.0": version "2.5.0" resolved "https://registry.yarnpkg.com/@douyinfe/semi-animation-react/-/semi-animation-react-2.5.0.tgz#b23f91c507e62f899984a8d69d83d467367a94e7" @@ -12551,6 +12582,11 @@ tslib@^2, tslib@^2.0.3, tslib@^2.3.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== +tslib@^2.0.0: + version "2.6.3" + resolved "https://bnpm.byted.org/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"