Skip to content

Commit

Permalink
refactor: 💡 pro-array-table-shadow-modal, docs, but no demos up
Browse files Browse the repository at this point in the history
  • Loading branch information
charlzyx committed Jan 23, 2024
1 parent 7aeb199 commit b2f8a11
Show file tree
Hide file tree
Showing 9 changed files with 213 additions and 44 deletions.
87 changes: 86 additions & 1 deletion docs/components/pro/pro-array-table.mdx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# 👊 `Pro ArrayTable
# 👊 Pro ArrayTable

> Pro ArrayTable 是一个增强版本的 ArrayTable, 增加了以下属性与功能
- ✅ schema 拓展: RowExpand / Toolbar / Footer
- ✅ 列配置: 排序与拖动调整列宽
- ✅ 可编辑弹窗, 使用事件委托优化
- ✅ 常用功能配置简化与增强 (pagination/rowSelection/expandable)
-`expandable.defaultExpandedAllRows` 现在支持惰性加载啦!
-`expandable.expandedRowKeys` / `rowSelection.selectedRowKeys` 现在会根据页码调整进行智能重置!
Expand Down Expand Up @@ -60,3 +61,87 @@ export interface ITableSelectionContext {
setSelectedRowKeys: React.Dispatch<React.SetStateAction<RowKey[]>>;
}
```

### ProArrayTable.DelegateAction 代理动作触发器

```tsx | pure
{
/** 动作标志, 与 ShadowModal 对应 */
act: string;
/** 当前列所属 index, 默认使用 ArrayBase.useIndex() 获取当前数据对应位置 */
index?: number;
/** 数据初始化加载器, 默认使用 field.record 当前模型所对应 record */
initLoader?: object | Promise<object>;
/**
* 具体元素, 但必须有标签包装, 因为会被追加 data-属性字段标志给事件委托来识别
* 不填写的情况下, 使用 Button 标签包装 field.title
*/
children?: React.ReactElement;
}
```

### ShadowModal/ShadowModal 通用属性
```tsx | pure
{
/** 动作标志, 与 ShadowModal 对应 */
act: string;
/** 子表单Schema */
schema: ISchema,
/** createForm 创建的表单实例, 有自定义 effects 等可以通过自定义一个 form 这个传入 */
form?: ReturnType<typeof createForm>,
/** createSchemaField 函数配置 */
schemaFieldOptions?: Parameters<typeof createSchemaField>[0],
/** 取消事件 */
onCancel?: (
ctx: ReturnType<typeof useProArrayTableContext>,
) => void | Promise<void>;
/** 子表单提交事件, 可以做点什么 */
onOk?: (
data: any,
ctx: ReturnType<typeof useProArrayTableContext>,
) => void | Promise<void>;
}
```
### ProArrayTable.ShadowModal 表格共享弹窗, 结合 ShadowForm/DelegateAction 使用

除了 `onOk,onCancel` antd/Modal 其他属性

### ProArrayTable.ShadowDrawer 表格共享抽屉, 结合 ShaodwForm/DelegateAction 使用

除了 `onOk,onCancel` antd/Drawer 其他属性

### ProArrayTable.ProAddition 弹窗/抽屉形式的可编辑内容新增组件

高级自增组件, 提供了弹窗/抽屉形式的空调编辑内容, 这个本质上是一个内置了一个 ShadowForm的 Modal/Drawer

```tsx | pure
{
/** 子表单Schema */
schema: ISchema,
/** createForm 创建的表单实例, 有自定义 effects 等可以通过自定义一个 form 这个传入 */
form?: ReturnType<typeof createForm>,
/** createSchemaField 函数配置 */
schemaFieldOptions?: Parameters<typeof createSchemaField>[0],
/** 弹窗形式: Modal 或 Drawer, 默认 modal */
popType: "modal" | "drawer"
/** 其他 Modal / Drawer 原始属性 */
...others: React.ComponentProps<typeof Modal | typeof Drawer>
}
```

### ProArrayTable.Column 列配置组件

追加了可拖拽列宽配置开关, 优先级 > Table 上的 resizeable 属性

```tsx | pure
{
// 是否可拖拽调整列宽
resizeable?: boolean
// ... 其他参考 @formily/antd ArrayBase.Column 配置
}
```

### ProArrayTable.Addition 自增组件

`@formily/antd` 中的 `ArrayTable.Addition` 表现一致

2 changes: 1 addition & 1 deletion docs/components/pro/pro-editable.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 💡Pro Editable
# 💡Pro Editable (废弃, 请使用 ShadowForm)

> ProEditable 是为了解决常见的 `Popconfirm/Modal/Drawer` 弹窗编辑子表单模板代码的问题
Expand Down
8 changes: 7 additions & 1 deletion docs/components/pro/shadow-form.mdx
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# 👻 ShaowForm 影子表单

> 子表单
> 脱离于当前 Form 响应式上下文的子表单
这很有用, 解决表格中的弹窗编辑与增加, 以及对象弹窗编辑的 Pro!Editable

### 代码案例: Confirm
<code src="../demos/ShadowForm.tsx" />


### 代码案例: 在列表中使用
<code src="../demos/ShadowFormWithArray.tsx" />

### useShadowForm

### ShadowFormProvider
1 change: 1 addition & 0 deletions src/__builtins__/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./utils";
export * from "./pickomit";
33 changes: 33 additions & 0 deletions src/__builtins__/pickomit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export const omit = <T extends object, K extends keyof T>(
o: T,
...keys: K[]
) => {
if (typeof o !== "object") return o;
return Object.keys(o).reduce((p, k: string) => {
if (!keys.includes(k as any)) {
(p as any)[k] = (o as any)[k];
}
return p;
}, {} as T);
};

export const pick = <T extends object, K extends keyof T>(
o: T,
...keys: K[]
) => {
if (typeof o !== "object") return o;
return Object.keys(o).reduce(
(p, k: string) => {
if (keys.includes(k as any)) {
(p as any)[k] = (o as any)[k];
}
return p;
},
{} as T,
// {
// // 不太好用, 晚点练习一下类型体操吧
// // https://github.com/ascoders/weekly/blob/master/TS%20%E7%B1%BB%E5%9E%8B%E4%BD%93%E6%93%8D/243.%E7%B2%BE%E8%AF%BB%E3%80%8APick%2C%20Awaited%2C%20If...%E3%80%8B.md
// [Key in K]: T[K];
// },
);
};
75 changes: 46 additions & 29 deletions src/pro-array-table/mixin.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
import { FormProvider, ReactFC, observer, useField } from "@formily/react";
import { toJS } from "@formily/reactive";
import React, { Fragment, useContext, useEffect, useRef } from "react";
import { useRecord } from "..";
import { Alert, BUTTON_TYPE, Button, Divider, Modal, Space } from "../adaptor";
import { omit, pick } from "../__builtins__";
import {
Alert,
BUTTON_TYPE,
Button,
Divider,
Drawer,
Modal,
Space,
} from "../adaptor";
import { ArrayBase, ArrayBaseMixins } from "../adaptor/adaptor";
import { ShadowForm, ShadowFormContext } from "../shadow-form/shadow-form";
import {
IShadowFormOptions,
ShadowFormContext,
ShadowFormProvider,
useShadowForm,
} from "../shadow-form/shadow-form";
import { useRecord } from "../shared";
import {
ArrayTableDelegateContext,
DATE_DELEGATE_ACT_KEY,
Expand Down Expand Up @@ -92,9 +106,7 @@ export const RowSelectionPro = (props: {
rowKey: (record: any) => string | number;
}) => {
const { ds, rowKey } = props;
const array = ArrayBase.useArray();
const $row = useContext(TableRowSelectionContext);
// const [, $row] = useArrayCompPropsOf(array?.field, "rowSelection");
return ds.length > 0 ? (
<Alert
style={{ padding: "3px 4px" }}
Expand Down Expand Up @@ -172,18 +184,22 @@ export const useProArrayTableContext = () => {
return { array, pagination, rowSelection, expanedable };
};

export interface CommonShadowPopup extends IShadowFormOptions {
onCancel?: (
ctx: ReturnType<typeof useProArrayTableContext>,
) => void | Promise<void>;
onOk?: (
data: any,
ctx: ReturnType<typeof useProArrayTableContext>,
) => void | Promise<void>;
}
export const ShadowModal: React.FC<
Omit<React.ComponentProps<typeof Modal>, "children" | "onCancel" | "onOk"> & {
onCancel?: (
ctx: ReturnType<typeof useProArrayTableContext>,
) => void | Promise<void>;
onOk?: (
data: any,
ctx: ReturnType<typeof useProArrayTableContext>,
) => void | Promise<void>;
}
Omit<React.ComponentProps<typeof Modal>, "children" | "onCancel" | "onOk"> &
CommonShadowPopup
> = (props) => {
const { SchemaField, form, act, schema } = useContext(ShadowFormContext);
const { SchemaField, form, act, schema } = useShadowForm(
pick(props, "act", "schema", "schemaFieldOptions", "form"),
);
const delegate = useContext(ArrayTableDelegateContext);
const visible = delegate.act === act && delegate.index > -1;
const pending = useRef(false);
Expand Down Expand Up @@ -213,7 +229,7 @@ export const ShadowModal: React.FC<

return (
<Modal
{...props}
{...omit(props, "act", "schema", "schemaFieldOptions", "form")}
open={visible}
onCancel={() => {
if (pending.current) return;
Expand All @@ -238,10 +254,18 @@ export const ShadowModal: React.FC<
</Modal>
);
};

export const DelegateAction: React.FC<{
/** 动作标志, 与 ShadowModal 对应 */
act: string;
/** 当前列所属 index, 默认使用 ArrayBase.useIndex() 获取当前数据对应位置 */
index?: number;
/** 数据初始化加载器, 默认使用 field.record 当前模型所对应 record */
initLoader?: Required<IArrayTableDelegateContext>["initLoader"]["current"];
/**
* 具体元素, 但必须有标签包装, 因为会被追加 data-属性字段标志给事件委托来识别
* 不填写的情况下, 使用 Button 标签包装 field.title
*/
children?: React.ReactElement;
}> = (props) => {
const index = "index" in (props ?? {}) ? props.index : ArrayBase.useIndex();
Expand Down Expand Up @@ -276,24 +300,17 @@ export const DelegateAction: React.FC<{
};

export const ProAddition = ({
schema,
form,
schemaFieldOptions,
popType = "modal",
...props
}: Omit<React.ComponentProps<typeof ShadowForm>, "act"> & {
}: Omit<CommonShadowPopup, "act"> & {
popType: "modal" | "drawer";
}) => {
} & Omit<
React.ComponentProps<typeof Modal>,
"onOk" | "onCancel" | "children"
>) => {
return (
<React.Fragment>
<ShadowForm
act="_pro_addtion"
schema={schema}
form={form}
schemaFieldOptions={schemaFieldOptions}
>
<ShadowModal {...(props as any)}></ShadowModal>
</ShadowForm>
<ShadowModal act="_pro_addition" {...props}></ShadowModal>
<DelegateAction index={Infinity} act={"_pro_addtion"}></DelegateAction>
</React.Fragment>
);
Expand Down
5 changes: 4 additions & 1 deletion src/shadow-form/index.tsx
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
export { ShadowForm, useShadowSchemaField } from "./shadow-form";
export {
ShadowFormProvider as ShadowForm,
useShadowSchemaField,
} from "./shadow-form";
export { ShadowPopconfirm } from "./shadow-popconfirm";
44 changes: 34 additions & 10 deletions src/shadow-form/shadow-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,18 @@ export const useShadowSchemaField = (
return SchemaField;
};

export interface IShadowFormContext {
schema: ISchema;
export interface IShadowFormOptions {
/** 子表单对应动作名称 */
act: string;
form: ReturnType<typeof createForm>;
/** 子表单Schema */
schema: ISchema;
/** createSchemaField 函数配置, components 和 scope */
schemaFieldOptions?: Parameters<typeof useShadowSchemaField>[0];
/** createForm 创建的表单实例, 有自定义 effects 等可以通过自定义一个 form 这个传入 */
form?: ReturnType<typeof createForm>;
}
export interface IShadowFormContext
extends Required<Omit<IShadowFormOptions, "schemaFieldOptions">> {
SchemaField: ReturnType<typeof createSchemaField>;
}
export const ShadowFormContext = createContext<IShadowFormContext>({
Expand All @@ -36,23 +44,39 @@ export const ShadowFormContext = createContext<IShadowFormContext>({
SchemaField: createSchemaField(),
});

export const ShadowForm: React.FC<
export const useShadowForm = (options: {
schema: ISchema;
schemaFieldOptions?: Parameters<typeof useShadowSchemaField>[0];
act?: string;
form?: ReturnType<typeof createForm>;
}) => {
const { schema, schemaFieldOptions, act, form } = options;
const SchemaField = useShadowSchemaField(schemaFieldOptions);
const realForm = form ?? createForm({});
const myField = useFieldSchema();
const name = myField?.name as string;
return {
form: realForm,
schema,
SchemaField,
act: act ?? name,
};
};

export const ShadowFormProvider: React.FC<
React.PropsWithChildren<{
schema: ISchema;
schemaFieldOptions?: Parameters<typeof useShadowSchemaField>[0];
act?: string;
form?: ReturnType<typeof createForm>;
}>
> = ({ children, act, schemaFieldOptions, form, schema }) => {
const SchemaField = useShadowSchemaField(schemaFieldOptions);
const realForm = form ?? createForm({});
const myField = useFieldSchema();
const name = myField?.name as string;
> = ({ children, ...options }) => {
const { SchemaField, act, form, schema } = useShadowForm(options);

return (
<ShadowFormContext.Provider
value={{
form: realForm,
form,
schema,
SchemaField,
act: act ?? name,
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"isolatedModules": true,
"resolveJsonModule": true,
"declaration": true,
"moduleResolution": "node",
"moduleResolution": "Bundler",
"paths": {
"@pro.formily/antd": ["src"]
}
Expand Down

0 comments on commit b2f8a11

Please sign in to comment.