@canlooks/can-ui 0.0.53 → 0.0.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/curd/curd.d.ts +10 -4
- package/dist/cjs/components/curd/curd.js +16 -1
- package/dist/cjs/components/curd/curd.style.js +5 -0
- package/dist/cjs/components/curd/curdDialog.d.ts +4 -1
- package/dist/cjs/components/curd/curdDialog.js +50 -23
- package/dist/cjs/components/pickerDialog/pickerDialog.js +7 -7
- package/dist/cjs/extensions/curd/curd.d.ts +8 -8
- package/dist/cjs/extensions/curd/curd.js +8 -8
- package/dist/esm/components/curd/curd.d.ts +10 -4
- package/dist/esm/components/curd/curd.js +17 -2
- package/dist/esm/components/curd/curd.style.js +5 -0
- package/dist/esm/components/curd/curdDialog.d.ts +4 -1
- package/dist/esm/components/curd/curdDialog.js +50 -23
- package/dist/esm/components/pickerDialog/pickerDialog.js +7 -7
- package/dist/esm/extensions/curd/curd.d.ts +8 -8
- package/dist/esm/extensions/curd/curd.js +6 -6
- package/documentation/dist/assets/{index-0lpazctB.js → index-GiFWv3kZ.js} +691 -687
- package/documentation/dist/index.html +1 -1
- package/package.json +1 -1
|
@@ -24,7 +24,13 @@ export type LoadRowsReturn<R extends RowType> = {
|
|
|
24
24
|
total: number;
|
|
25
25
|
};
|
|
26
26
|
type EachRowType<R extends RowType, T> = T | ((row: R) => T);
|
|
27
|
-
export
|
|
27
|
+
export type CurdRef<R extends RowType = RowType, F extends FormValue = FormValue> = {
|
|
28
|
+
openCreateDialog(initialValue?: F): Promise<F> | undefined;
|
|
29
|
+
selectSingle(): Promise<R> | undefined;
|
|
30
|
+
selectMultiple(selected?: Id[]): Promise<Id[]> | undefined;
|
|
31
|
+
};
|
|
32
|
+
export interface CurdBaseProps<R extends RowType, F extends FormValue> extends Omit<DataGridBaseProps<R>, 'ref'> {
|
|
33
|
+
ref?: Ref<CurdRef<R, F>>;
|
|
28
34
|
/** 默认属性会传递给DataGrid组件,外层包裹元素的属性使用wrapperProps */
|
|
29
35
|
wrapperProps?: DivProps;
|
|
30
36
|
wrapperRef?: Ref<HTMLDivElement>;
|
|
@@ -82,14 +88,14 @@ export interface CurdBaseProps<R extends RowType, F extends FormValue> extends D
|
|
|
82
88
|
onUpdate?(formValue: F, row: R): any;
|
|
83
89
|
onDelete?(row: R): any;
|
|
84
90
|
/** 行数据转换为表单值的方法,若不指定,行数据会直接填入表单 */
|
|
85
|
-
|
|
91
|
+
rowToForm?(row: R): F | Promise<F>;
|
|
86
92
|
dialogProps?: CurdDialogProps<R, F>;
|
|
87
93
|
formProps?: FormProps<F>;
|
|
88
94
|
formRef?: Ref<FormRef<F>>;
|
|
89
95
|
}
|
|
90
|
-
interface CurdSingleProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> extends Omit<DataGridSingleProps<R, V>, 'columns'>, CurdBaseProps<R, F> {
|
|
96
|
+
interface CurdSingleProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> extends Omit<DataGridSingleProps<R, V>, 'ref' | 'columns'>, CurdBaseProps<R, F> {
|
|
91
97
|
}
|
|
92
|
-
interface CurdMultipleProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> extends Omit<DataGridMultipleProps<R, V>, 'columns'>, CurdBaseProps<R, F> {
|
|
98
|
+
interface CurdMultipleProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> extends Omit<DataGridMultipleProps<R, V>, 'ref' | 'columns'>, CurdBaseProps<R, F> {
|
|
93
99
|
}
|
|
94
100
|
export type CurdProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> = CurdSingleProps<R, F, V> | CurdMultipleProps<R, F, V>;
|
|
95
101
|
export declare const Curd: {
|
|
@@ -23,7 +23,22 @@ const faPenToSquare_1 = require("@fortawesome/free-regular-svg-icons/faPenToSqua
|
|
|
23
23
|
const faPlus_1 = require("@fortawesome/free-solid-svg-icons/faPlus");
|
|
24
24
|
const faRotateRight_1 = require("@fortawesome/free-solid-svg-icons/faRotateRight");
|
|
25
25
|
exports.Curd = (0, react_1.memo)((props) => {
|
|
26
|
-
const { wrapperProps, wrapperRef, variant = 'standard', loadRows, columns, toolbarLeft, toolbarRight, reloadable = true, onReload, resizable = true, columnConfigurable = true, filterProps, filterRef, initialFilterValue, onFilter, renderFilter, copyable, creatable = true, updatable = true, deletable = true, createButtonProps, updateButtonProps, deleteButtonProps, deleteConfirmProps, controlColumnTitle = '操作', renderExtraControl, titleKey, dataName = '', createName = '添加', updateName = '编辑', deleteName = '删除', onCreate, onUpdate, onDelete,
|
|
26
|
+
const { ref, wrapperProps, wrapperRef, variant = 'standard', loadRows, columns, toolbarLeft, toolbarRight, reloadable = true, onReload, resizable = true, columnConfigurable = true, filterProps, filterRef, initialFilterValue, onFilter, renderFilter, copyable, creatable = true, updatable = true, deletable = true, createButtonProps, updateButtonProps, deleteButtonProps, deleteConfirmProps, controlColumnTitle = '操作', renderExtraControl, titleKey, dataName = '', createName = '添加', updateName = '编辑', deleteName = '删除', onCreate, onUpdate, onDelete, rowToForm, dialogProps, formProps, formRef, onChange, ...dataGridProps } = props;
|
|
27
|
+
/**
|
|
28
|
+
* -------------------------------------------------------------
|
|
29
|
+
* ref
|
|
30
|
+
*/
|
|
31
|
+
(0, react_1.useImperativeHandle)(ref, () => ({
|
|
32
|
+
openCreateDialog(initialValue) {
|
|
33
|
+
return curdDialogRef.current?.open(void 0, initialValue);
|
|
34
|
+
},
|
|
35
|
+
selectSingle() {
|
|
36
|
+
return curdDialogRef.current?.selectSingle();
|
|
37
|
+
},
|
|
38
|
+
selectMultiple(selected) {
|
|
39
|
+
return curdDialogRef.current?.selectMultiple(selected);
|
|
40
|
+
}
|
|
41
|
+
}));
|
|
27
42
|
/**
|
|
28
43
|
* -------------------------------------------------------------
|
|
29
44
|
* 筛选部分
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.dialogStyle = exports.style = exports.classes = void 0;
|
|
4
4
|
const react_1 = require("@emotion/react");
|
|
5
5
|
const utils_1 = require("../../utils");
|
|
6
|
+
const button_style_1 = require("../button/button.style");
|
|
6
7
|
exports.classes = (0, utils_1.defineInnerClasses)('curd', [
|
|
7
8
|
'filter',
|
|
8
9
|
'filterGridContainer',
|
|
@@ -94,5 +95,9 @@ exports.dialogStyle = (0, utils_1.defineCss)(({ spacing }) => (0, react_1.css) `
|
|
|
94
95
|
display: flex;
|
|
95
96
|
align-items: center;
|
|
96
97
|
gap: ${spacing[8]}px;
|
|
98
|
+
|
|
99
|
+
.${button_style_1.classes.root} {
|
|
100
|
+
font-size: 1rem;
|
|
101
|
+
}
|
|
97
102
|
}
|
|
98
103
|
`);
|
|
@@ -3,8 +3,11 @@ import { DialogProps } from '../dialog';
|
|
|
3
3
|
import { RowType } from '../dataGrid';
|
|
4
4
|
import { FormValue } from '../form';
|
|
5
5
|
import { CurdBaseProps } from './curd';
|
|
6
|
+
import { Id } from '../../types';
|
|
6
7
|
export type CurdDialogRef<R extends RowType = RowType, F extends FormValue = FormValue> = {
|
|
7
|
-
open(activeRow?: R): Promise<F>;
|
|
8
|
+
open(activeRow?: R, initialFormValue?: F): Promise<F>;
|
|
9
|
+
selectSingle(): Promise<R>;
|
|
10
|
+
selectMultiple(selected?: Id[]): Promise<Id[]>;
|
|
8
11
|
};
|
|
9
12
|
export interface CurdDialogProps<R extends RowType, F extends FormValue = FormValue> extends Omit<DialogProps, 'ref'> {
|
|
10
13
|
ref?: Ref<CurdDialogRef<R, F>>;
|
|
@@ -14,35 +14,49 @@ const curd_style_1 = require("./curd.style");
|
|
|
14
14
|
const pickerDialog_1 = require("../pickerDialog");
|
|
15
15
|
const __1 = require("../..");
|
|
16
16
|
const faCopy_1 = require("@fortawesome/free-regular-svg-icons/faCopy");
|
|
17
|
-
exports.CurdDialog = (0, react_2.memo)(({ ref, onFinish,
|
|
18
|
-
|
|
19
|
-
curdProps, ...props }) => {
|
|
20
|
-
const { columns, postData, copyable, titleKey, formProps, formRef, dataName = '', createName = '添加', updateName = '编辑' } = curdProps;
|
|
17
|
+
exports.CurdDialog = (0, react_2.memo)(({ ref, onFinish, curdProps, ...props }) => {
|
|
18
|
+
const { columns, rowToForm, copyable, titleKey, formProps, formRef, dataName = '', createName = '添加', updateName = '编辑' } = curdProps;
|
|
21
19
|
/**
|
|
22
20
|
* ----------------------------------------------------------------
|
|
23
21
|
* ref与promise部分
|
|
24
22
|
*/
|
|
25
23
|
const innerFormRef = (0, react_2.useRef)(null);
|
|
26
|
-
const
|
|
24
|
+
const openResolvers = (0, react_2.useRef)(void 0);
|
|
27
25
|
const [innerOpen, setInnerOpen] = (0, utils_1.useControlled)(props.defaultOpen, props.open);
|
|
28
26
|
const closeHandler = (reason) => {
|
|
29
27
|
if (reason === 'confirmed') {
|
|
30
28
|
return;
|
|
31
29
|
}
|
|
32
30
|
props.onClose?.(reason);
|
|
33
|
-
|
|
31
|
+
openResolvers.current?.reject({
|
|
34
32
|
type: 'canceled',
|
|
35
33
|
value: innerFormRef.current.getFormValue()
|
|
36
34
|
});
|
|
37
35
|
setInnerOpen(false);
|
|
38
36
|
};
|
|
37
|
+
const [selectMode, setSelectMode] = (0, react_2.useState)('single');
|
|
38
|
+
const selectResolvers = (0, react_2.useRef)(void 0);
|
|
39
39
|
(0, react_2.useImperativeHandle)(ref, () => ({
|
|
40
|
-
open(row) {
|
|
40
|
+
open(row, initialFormValue) {
|
|
41
41
|
innerFormRef.current?.resetForm();
|
|
42
|
-
|
|
42
|
+
suppressTransform.current = !!initialFormValue;
|
|
43
|
+
initialFormValue && innerFormRef.current?.setFormValue(initialFormValue);
|
|
43
44
|
setActiveRow(row);
|
|
44
|
-
|
|
45
|
+
setInnerOpen(true);
|
|
46
|
+
const { promise } = openResolvers.current = Promise.withResolvers();
|
|
47
|
+
return promise;
|
|
48
|
+
},
|
|
49
|
+
selectSingle() {
|
|
50
|
+
isCopying.current = false;
|
|
51
|
+
setSelectMode('single');
|
|
52
|
+
pickerDialogRef.current.open().then();
|
|
53
|
+
const { promise } = selectResolvers.current = Promise.withResolvers();
|
|
45
54
|
return promise;
|
|
55
|
+
},
|
|
56
|
+
selectMultiple(selected) {
|
|
57
|
+
isCopying.current = false;
|
|
58
|
+
setSelectMode('multiple');
|
|
59
|
+
return pickerDialogRef.current.open(selected);
|
|
46
60
|
}
|
|
47
61
|
}));
|
|
48
62
|
/**
|
|
@@ -50,13 +64,14 @@ curdProps, ...props }) => {
|
|
|
50
64
|
* 表单项
|
|
51
65
|
*/
|
|
52
66
|
const [activeRow, setActiveRow] = (0, react_2.useState)();
|
|
67
|
+
const suppressTransform = (0, react_2.useRef)(false);
|
|
53
68
|
const [transforming, setFormValue] = (0, utils_1.useLoading)(async (row) => {
|
|
54
|
-
const formValue =
|
|
69
|
+
const formValue = rowToForm && row ? await rowToForm(row) : row;
|
|
55
70
|
formValue && innerFormRef.current?.setFormValue(formValue);
|
|
56
71
|
});
|
|
57
72
|
(0, react_2.useEffect)(() => {
|
|
58
|
-
innerOpen.current && setFormValue(activeRow);
|
|
59
|
-
}, [innerOpen.current]);
|
|
73
|
+
innerOpen.current && !suppressTransform.current && setFormValue(activeRow);
|
|
74
|
+
}, [innerOpen.current, activeRow]);
|
|
60
75
|
const renderedFormItems = (0, react_2.useMemo)(() => {
|
|
61
76
|
return (0, utils_1.columnsToFormItem)(columns, activeRow)?.map(col => {
|
|
62
77
|
if ((0, react_2.isValidElement)(col)) {
|
|
@@ -75,7 +90,7 @@ curdProps, ...props }) => {
|
|
|
75
90
|
};
|
|
76
91
|
const [innerLoading, finishHandler] = (0, utils_1.useLoading)(async (value) => {
|
|
77
92
|
formProps?.onFinish?.(value);
|
|
78
|
-
|
|
93
|
+
openResolvers.current?.resolve(value);
|
|
79
94
|
await onFinish?.(value);
|
|
80
95
|
setInnerOpen(false);
|
|
81
96
|
}, props.confirmLoading);
|
|
@@ -83,20 +98,32 @@ curdProps, ...props }) => {
|
|
|
83
98
|
* ----------------------------------------------------------------
|
|
84
99
|
* 复制
|
|
85
100
|
*/
|
|
101
|
+
const isCopying = (0, react_2.useRef)(false);
|
|
86
102
|
const pickerDialogRef = (0, react_2.useRef)(null);
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
103
|
+
const onCopyButtonClick = () => {
|
|
104
|
+
isCopying.current = true;
|
|
105
|
+
setSelectMode('single');
|
|
106
|
+
pickerDialogRef.current.open().then();
|
|
107
|
+
};
|
|
108
|
+
const toggleHandler = (checked, value, row) => {
|
|
109
|
+
if (isCopying.current) {
|
|
110
|
+
const title = !(0, utils_1.isUnset)(titleKey) ? row[titleKey] : void 0;
|
|
111
|
+
typeof title === 'string'
|
|
112
|
+
? setFormValue({
|
|
113
|
+
...row,
|
|
114
|
+
[titleKey]: `${title} - 副本`
|
|
115
|
+
})
|
|
116
|
+
: setFormValue(row);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
// 处理selectSingle
|
|
120
|
+
selectResolvers.current?.resolve(row);
|
|
121
|
+
}
|
|
95
122
|
};
|
|
96
123
|
const rowTitle = activeRow && !(0, utils_1.isUnset)(titleKey) ? activeRow[titleKey] : void 0;
|
|
97
124
|
return ((0, jsx_runtime_1.jsxs)(dialog_1.Dialog, { css: curd_style_1.dialogStyle, width: 600, title: activeRow
|
|
98
125
|
? `${updateName}${dataName}${rowTitle ? ' - ' + rowTitle : ''}`
|
|
99
126
|
: (0, jsx_runtime_1.jsxs)("div", { className: curd_style_1.classes.dialogTitle, children: [(0, jsx_runtime_1.jsxs)("span", { children: [createName, dataName] }), copyable &&
|
|
100
|
-
(0, jsx_runtime_1.jsxs)(button_1.Button, { variant: "plain", prefix: (0, jsx_runtime_1.jsx)(__1.Icon, { icon: faCopy_1.faCopy }), onClick:
|
|
101
|
-
(0, jsx_runtime_1.jsx)(pickerDialog_1.PickerDialog, { ref: pickerDialogRef, onToggle:
|
|
127
|
+
(0, jsx_runtime_1.jsxs)(button_1.Button, { variant: "plain", prefix: (0, jsx_runtime_1.jsx)(__1.Icon, { icon: faCopy_1.faCopy }), onClick: onCopyButtonClick, children: ["\u4ECE\u5DF2\u6709", dataName || '数据', "\u590D\u5236"] })] }), ...props, open: innerOpen.current, onClose: closeHandler, onConfirm: confirmHandler, confirmLoading: innerLoading.current, children: [(0, jsx_runtime_1.jsx)(loading_1.Loading, { open: transforming.current, children: (0, jsx_runtime_1.jsx)(form_1.Form, { labelWidth: "20%", ...formProps, ref: (0, utils_1.cloneRef)(formRef, innerFormRef), onFinish: finishHandler, children: renderedFormItems }) }), copyable &&
|
|
128
|
+
(0, jsx_runtime_1.jsx)(pickerDialog_1.PickerDialog, { ref: pickerDialogRef, multiple: selectMode === 'multiple', onToggle: toggleHandler, children: (0, jsx_runtime_1.jsx)(curd_1.Curd, { ...curdProps, variant: "embeded", copyable: false, creatable: false, updatable: false, deletable: false }) })] }));
|
|
102
129
|
});
|
|
@@ -16,13 +16,6 @@ exports.PickerDialog = (({ ref, dialogRef, multiple, children, showSelectedList
|
|
|
16
16
|
// 以下属性从SelectionContextBaseProps继承
|
|
17
17
|
options = rows ?? nodes, primaryKey = 'id', childrenKey = 'children', relation = 'dependent', integration = 'shallowest', disabled, clearable = !!multiple, onToggle, ...props }) => {
|
|
18
18
|
const resolvers = (0, react_1.useRef)(void 0);
|
|
19
|
-
const [innerValue, _setInnerValue] = (0, react_1.useState)(multiple ? [] : null);
|
|
20
|
-
const setInnerValue = (value) => {
|
|
21
|
-
_setInnerValue(value);
|
|
22
|
-
// 单选模式,值每次改变都触发确认
|
|
23
|
-
!multiple && confirmHandler(value);
|
|
24
|
-
};
|
|
25
|
-
const [innerOpen, setInnerOpen] = (0, utils_1.useControlled)(props.defaultOpen, props.open);
|
|
26
19
|
(0, react_1.useImperativeHandle)(ref, () => ({
|
|
27
20
|
open(value) {
|
|
28
21
|
_setInnerValue(value ?? null);
|
|
@@ -31,6 +24,13 @@ options = rows ?? nodes, primaryKey = 'id', childrenKey = 'children', relation =
|
|
|
31
24
|
return promise;
|
|
32
25
|
}
|
|
33
26
|
}));
|
|
27
|
+
const [innerValue, _setInnerValue] = (0, react_1.useState)(multiple ? [] : null);
|
|
28
|
+
const setInnerValue = (value) => {
|
|
29
|
+
_setInnerValue(value);
|
|
30
|
+
// 单选模式,值每次改变都触发确认
|
|
31
|
+
!multiple && confirmHandler(value);
|
|
32
|
+
};
|
|
33
|
+
const [innerOpen, setInnerOpen] = (0, utils_1.useControlled)(props.defaultOpen, props.open);
|
|
34
34
|
const onCloseHandler = (reason) => {
|
|
35
35
|
if (reason === 'confirmed') {
|
|
36
36
|
return;
|
|
@@ -10,24 +10,24 @@ import { Id } from '../../types';
|
|
|
10
10
|
export declare function CURD<R extends RowType, F extends FormValue = FormValue>(props?: CurdBaseProps<R, F>): <T extends ComponentClass>(target: T) => T;
|
|
11
11
|
export declare namespace CURD {
|
|
12
12
|
var Column: typeof import("./curd").Column;
|
|
13
|
-
var
|
|
13
|
+
var LoadRows: typeof import("./curd").LoadRows;
|
|
14
14
|
var OnReload: typeof import("./curd").OnReload;
|
|
15
15
|
var OnFilter: typeof import("./curd").OnFilter;
|
|
16
16
|
var OnCreate: typeof import("./curd").OnCreate;
|
|
17
17
|
var OnUpdate: typeof import("./curd").OnUpdate;
|
|
18
18
|
var OnDelete: typeof import("./curd").OnDelete;
|
|
19
|
-
var
|
|
19
|
+
var RowToForm: typeof import("./curd").RowToForm;
|
|
20
20
|
}
|
|
21
21
|
export declare function DATA_GRID<R extends RowType, V extends Id = Id>(props?: DataGridProps<R, V>): <T extends ComponentClass>(target: T) => T;
|
|
22
22
|
export declare namespace DATA_GRID {
|
|
23
23
|
var Column: typeof import("./curd").Column;
|
|
24
|
-
var
|
|
24
|
+
var LoadRows: typeof import("./curd").LoadRows;
|
|
25
25
|
var OnReload: typeof import("./curd").OnReload;
|
|
26
26
|
var OnFilter: typeof import("./curd").OnFilter;
|
|
27
27
|
var OnCreate: typeof import("./curd").OnCreate;
|
|
28
28
|
var OnUpdate: typeof import("./curd").OnUpdate;
|
|
29
29
|
var OnDelete: typeof import("./curd").OnDelete;
|
|
30
|
-
var
|
|
30
|
+
var RowToForm: typeof import("./curd").RowToForm;
|
|
31
31
|
}
|
|
32
32
|
type ColumnDecorator = (prototype: Object, property: string, descriptor?: TypedPropertyDescriptor<any>) => void;
|
|
33
33
|
export declare function Column(title: ReactNode): ColumnDecorator;
|
|
@@ -51,8 +51,8 @@ export declare function Form(prototype: Object, property: string, descriptor?: T
|
|
|
51
51
|
* 方法修饰器
|
|
52
52
|
*/
|
|
53
53
|
type MethodDecorator = (prototype: Object, property: string, descriptor: TypedPropertyDescriptor<any>) => void;
|
|
54
|
-
export declare function
|
|
55
|
-
export declare function
|
|
54
|
+
export declare function LoadRows(): MethodDecorator;
|
|
55
|
+
export declare function LoadRows(prototype: Object, property: string, descriptor: TypedPropertyDescriptor<any>): void;
|
|
56
56
|
export declare function OnReload(): MethodDecorator;
|
|
57
57
|
export declare function OnReload(prototype: Object, property: string, descriptor: TypedPropertyDescriptor<any>): void;
|
|
58
58
|
export declare function OnFilter(): MethodDecorator;
|
|
@@ -63,6 +63,6 @@ export declare function OnUpdate(): MethodDecorator;
|
|
|
63
63
|
export declare function OnUpdate(prototype: Object, property: string, descriptor: TypedPropertyDescriptor<any>): void;
|
|
64
64
|
export declare function OnDelete(): MethodDecorator;
|
|
65
65
|
export declare function OnDelete(prototype: Object, property: string, descriptor: TypedPropertyDescriptor<any>): void;
|
|
66
|
-
export declare function
|
|
67
|
-
export declare function
|
|
66
|
+
export declare function RowToForm(): MethodDecorator;
|
|
67
|
+
export declare function RowToForm(prototype: Object, property: string, descriptor: TypedPropertyDescriptor<any>): void;
|
|
68
68
|
export {};
|
|
@@ -7,13 +7,13 @@ exports.Hide = Hide;
|
|
|
7
7
|
exports.Sort = Sort;
|
|
8
8
|
exports.Filter = Filter;
|
|
9
9
|
exports.Form = Form;
|
|
10
|
-
exports.
|
|
10
|
+
exports.LoadRows = LoadRows;
|
|
11
11
|
exports.OnReload = OnReload;
|
|
12
12
|
exports.OnFilter = OnFilter;
|
|
13
13
|
exports.OnCreate = OnCreate;
|
|
14
14
|
exports.OnUpdate = OnUpdate;
|
|
15
15
|
exports.OnDelete = OnDelete;
|
|
16
|
-
exports.
|
|
16
|
+
exports.RowToForm = RowToForm;
|
|
17
17
|
const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
|
|
18
18
|
const curd_1 = require("../../components/curd");
|
|
19
19
|
const dataGrid_1 = require("../../components/dataGrid");
|
|
@@ -119,8 +119,8 @@ function setColumnConfigValue(key, value = true) {
|
|
|
119
119
|
};
|
|
120
120
|
}
|
|
121
121
|
const prototype_methods = new WeakMap();
|
|
122
|
-
CURD.
|
|
123
|
-
function
|
|
122
|
+
CURD.LoadRows = DATA_GRID.LoadRows = LoadRows;
|
|
123
|
+
function LoadRows(a, b, c) {
|
|
124
124
|
return typeof c === 'undefined'
|
|
125
125
|
? setMethods('loadRows')
|
|
126
126
|
: setMethods('loadRows')(a, b, c);
|
|
@@ -155,11 +155,11 @@ function OnDelete(a, b, c) {
|
|
|
155
155
|
? setMethods('onDelete')
|
|
156
156
|
: setMethods('onDelete')(a, b, c);
|
|
157
157
|
}
|
|
158
|
-
CURD.
|
|
159
|
-
function
|
|
158
|
+
CURD.RowToForm = DATA_GRID.RowToForm = RowToForm;
|
|
159
|
+
function RowToForm(a, b, c) {
|
|
160
160
|
return typeof c === 'undefined'
|
|
161
|
-
? setMethods('
|
|
162
|
-
: setMethods('
|
|
161
|
+
? setMethods('rowToForm')
|
|
162
|
+
: setMethods('rowToForm')(a, b, c);
|
|
163
163
|
}
|
|
164
164
|
/**
|
|
165
165
|
* 通用设置prototype_methods的方法
|
|
@@ -24,7 +24,13 @@ export type LoadRowsReturn<R extends RowType> = {
|
|
|
24
24
|
total: number;
|
|
25
25
|
};
|
|
26
26
|
type EachRowType<R extends RowType, T> = T | ((row: R) => T);
|
|
27
|
-
export
|
|
27
|
+
export type CurdRef<R extends RowType = RowType, F extends FormValue = FormValue> = {
|
|
28
|
+
openCreateDialog(initialValue?: F): Promise<F> | undefined;
|
|
29
|
+
selectSingle(): Promise<R> | undefined;
|
|
30
|
+
selectMultiple(selected?: Id[]): Promise<Id[]> | undefined;
|
|
31
|
+
};
|
|
32
|
+
export interface CurdBaseProps<R extends RowType, F extends FormValue> extends Omit<DataGridBaseProps<R>, 'ref'> {
|
|
33
|
+
ref?: Ref<CurdRef<R, F>>;
|
|
28
34
|
/** 默认属性会传递给DataGrid组件,外层包裹元素的属性使用wrapperProps */
|
|
29
35
|
wrapperProps?: DivProps;
|
|
30
36
|
wrapperRef?: Ref<HTMLDivElement>;
|
|
@@ -82,14 +88,14 @@ export interface CurdBaseProps<R extends RowType, F extends FormValue> extends D
|
|
|
82
88
|
onUpdate?(formValue: F, row: R): any;
|
|
83
89
|
onDelete?(row: R): any;
|
|
84
90
|
/** 行数据转换为表单值的方法,若不指定,行数据会直接填入表单 */
|
|
85
|
-
|
|
91
|
+
rowToForm?(row: R): F | Promise<F>;
|
|
86
92
|
dialogProps?: CurdDialogProps<R, F>;
|
|
87
93
|
formProps?: FormProps<F>;
|
|
88
94
|
formRef?: Ref<FormRef<F>>;
|
|
89
95
|
}
|
|
90
|
-
interface CurdSingleProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> extends Omit<DataGridSingleProps<R, V>, 'columns'>, CurdBaseProps<R, F> {
|
|
96
|
+
interface CurdSingleProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> extends Omit<DataGridSingleProps<R, V>, 'ref' | 'columns'>, CurdBaseProps<R, F> {
|
|
91
97
|
}
|
|
92
|
-
interface CurdMultipleProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> extends Omit<DataGridMultipleProps<R, V>, 'columns'>, CurdBaseProps<R, F> {
|
|
98
|
+
interface CurdMultipleProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> extends Omit<DataGridMultipleProps<R, V>, 'ref' | 'columns'>, CurdBaseProps<R, F> {
|
|
93
99
|
}
|
|
94
100
|
export type CurdProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> = CurdSingleProps<R, F, V> | CurdMultipleProps<R, F, V>;
|
|
95
101
|
export declare const Curd: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@emotion/react/jsx-runtime";
|
|
2
|
-
import { memo, useCallback, useEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import { memo, useCallback, useEffect, useMemo, useRef, useImperativeHandle } from 'react';
|
|
3
3
|
import { DataGrid } from '../dataGrid';
|
|
4
4
|
import { CurdFilter } from './curdFilter';
|
|
5
5
|
import { classes, style } from './curd.style';
|
|
@@ -20,7 +20,22 @@ import { faPenToSquare } from '@fortawesome/free-regular-svg-icons/faPenToSquare
|
|
|
20
20
|
import { faPlus } from '@fortawesome/free-solid-svg-icons/faPlus';
|
|
21
21
|
import { faRotateRight } from '@fortawesome/free-solid-svg-icons/faRotateRight';
|
|
22
22
|
export const Curd = memo((props) => {
|
|
23
|
-
const { wrapperProps, wrapperRef, variant = 'standard', loadRows, columns, toolbarLeft, toolbarRight, reloadable = true, onReload, resizable = true, columnConfigurable = true, filterProps, filterRef, initialFilterValue, onFilter, renderFilter, copyable, creatable = true, updatable = true, deletable = true, createButtonProps, updateButtonProps, deleteButtonProps, deleteConfirmProps, controlColumnTitle = '操作', renderExtraControl, titleKey, dataName = '', createName = '添加', updateName = '编辑', deleteName = '删除', onCreate, onUpdate, onDelete,
|
|
23
|
+
const { ref, wrapperProps, wrapperRef, variant = 'standard', loadRows, columns, toolbarLeft, toolbarRight, reloadable = true, onReload, resizable = true, columnConfigurable = true, filterProps, filterRef, initialFilterValue, onFilter, renderFilter, copyable, creatable = true, updatable = true, deletable = true, createButtonProps, updateButtonProps, deleteButtonProps, deleteConfirmProps, controlColumnTitle = '操作', renderExtraControl, titleKey, dataName = '', createName = '添加', updateName = '编辑', deleteName = '删除', onCreate, onUpdate, onDelete, rowToForm, dialogProps, formProps, formRef, onChange, ...dataGridProps } = props;
|
|
24
|
+
/**
|
|
25
|
+
* -------------------------------------------------------------
|
|
26
|
+
* ref
|
|
27
|
+
*/
|
|
28
|
+
useImperativeHandle(ref, () => ({
|
|
29
|
+
openCreateDialog(initialValue) {
|
|
30
|
+
return curdDialogRef.current?.open(void 0, initialValue);
|
|
31
|
+
},
|
|
32
|
+
selectSingle() {
|
|
33
|
+
return curdDialogRef.current?.selectSingle();
|
|
34
|
+
},
|
|
35
|
+
selectMultiple(selected) {
|
|
36
|
+
return curdDialogRef.current?.selectMultiple(selected);
|
|
37
|
+
}
|
|
38
|
+
}));
|
|
24
39
|
/**
|
|
25
40
|
* -------------------------------------------------------------
|
|
26
41
|
* 筛选部分
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { css } from '@emotion/react';
|
|
2
2
|
import { defineInnerClasses, defineCss } from '../../utils';
|
|
3
|
+
import { classes as buttonClasses } from '../button/button.style';
|
|
3
4
|
export const classes = defineInnerClasses('curd', [
|
|
4
5
|
'filter',
|
|
5
6
|
'filterGridContainer',
|
|
@@ -91,5 +92,9 @@ export const dialogStyle = defineCss(({ spacing }) => css `
|
|
|
91
92
|
display: flex;
|
|
92
93
|
align-items: center;
|
|
93
94
|
gap: ${spacing[8]}px;
|
|
95
|
+
|
|
96
|
+
.${buttonClasses.root} {
|
|
97
|
+
font-size: 1rem;
|
|
98
|
+
}
|
|
94
99
|
}
|
|
95
100
|
`);
|
|
@@ -3,8 +3,11 @@ import { DialogProps } from '../dialog';
|
|
|
3
3
|
import { RowType } from '../dataGrid';
|
|
4
4
|
import { FormValue } from '../form';
|
|
5
5
|
import { CurdBaseProps } from './curd';
|
|
6
|
+
import { Id } from '../../types';
|
|
6
7
|
export type CurdDialogRef<R extends RowType = RowType, F extends FormValue = FormValue> = {
|
|
7
|
-
open(activeRow?: R): Promise<F>;
|
|
8
|
+
open(activeRow?: R, initialFormValue?: F): Promise<F>;
|
|
9
|
+
selectSingle(): Promise<R>;
|
|
10
|
+
selectMultiple(selected?: Id[]): Promise<Id[]>;
|
|
8
11
|
};
|
|
9
12
|
export interface CurdDialogProps<R extends RowType, F extends FormValue = FormValue> extends Omit<DialogProps, 'ref'> {
|
|
10
13
|
ref?: Ref<CurdDialogRef<R, F>>;
|
|
@@ -11,35 +11,49 @@ import { classes, dialogStyle } from './curd.style';
|
|
|
11
11
|
import { PickerDialog } from '../pickerDialog';
|
|
12
12
|
import { Icon } from '../..';
|
|
13
13
|
import { faCopy } from '@fortawesome/free-regular-svg-icons/faCopy';
|
|
14
|
-
export const CurdDialog = memo(({ ref, onFinish,
|
|
15
|
-
|
|
16
|
-
curdProps, ...props }) => {
|
|
17
|
-
const { columns, postData, copyable, titleKey, formProps, formRef, dataName = '', createName = '添加', updateName = '编辑' } = curdProps;
|
|
14
|
+
export const CurdDialog = memo(({ ref, onFinish, curdProps, ...props }) => {
|
|
15
|
+
const { columns, rowToForm, copyable, titleKey, formProps, formRef, dataName = '', createName = '添加', updateName = '编辑' } = curdProps;
|
|
18
16
|
/**
|
|
19
17
|
* ----------------------------------------------------------------
|
|
20
18
|
* ref与promise部分
|
|
21
19
|
*/
|
|
22
20
|
const innerFormRef = useRef(null);
|
|
23
|
-
const
|
|
21
|
+
const openResolvers = useRef(void 0);
|
|
24
22
|
const [innerOpen, setInnerOpen] = useControlled(props.defaultOpen, props.open);
|
|
25
23
|
const closeHandler = (reason) => {
|
|
26
24
|
if (reason === 'confirmed') {
|
|
27
25
|
return;
|
|
28
26
|
}
|
|
29
27
|
props.onClose?.(reason);
|
|
30
|
-
|
|
28
|
+
openResolvers.current?.reject({
|
|
31
29
|
type: 'canceled',
|
|
32
30
|
value: innerFormRef.current.getFormValue()
|
|
33
31
|
});
|
|
34
32
|
setInnerOpen(false);
|
|
35
33
|
};
|
|
34
|
+
const [selectMode, setSelectMode] = useState('single');
|
|
35
|
+
const selectResolvers = useRef(void 0);
|
|
36
36
|
useImperativeHandle(ref, () => ({
|
|
37
|
-
open(row) {
|
|
37
|
+
open(row, initialFormValue) {
|
|
38
38
|
innerFormRef.current?.resetForm();
|
|
39
|
-
|
|
39
|
+
suppressTransform.current = !!initialFormValue;
|
|
40
|
+
initialFormValue && innerFormRef.current?.setFormValue(initialFormValue);
|
|
40
41
|
setActiveRow(row);
|
|
41
|
-
|
|
42
|
+
setInnerOpen(true);
|
|
43
|
+
const { promise } = openResolvers.current = Promise.withResolvers();
|
|
44
|
+
return promise;
|
|
45
|
+
},
|
|
46
|
+
selectSingle() {
|
|
47
|
+
isCopying.current = false;
|
|
48
|
+
setSelectMode('single');
|
|
49
|
+
pickerDialogRef.current.open().then();
|
|
50
|
+
const { promise } = selectResolvers.current = Promise.withResolvers();
|
|
42
51
|
return promise;
|
|
52
|
+
},
|
|
53
|
+
selectMultiple(selected) {
|
|
54
|
+
isCopying.current = false;
|
|
55
|
+
setSelectMode('multiple');
|
|
56
|
+
return pickerDialogRef.current.open(selected);
|
|
43
57
|
}
|
|
44
58
|
}));
|
|
45
59
|
/**
|
|
@@ -47,13 +61,14 @@ curdProps, ...props }) => {
|
|
|
47
61
|
* 表单项
|
|
48
62
|
*/
|
|
49
63
|
const [activeRow, setActiveRow] = useState();
|
|
64
|
+
const suppressTransform = useRef(false);
|
|
50
65
|
const [transforming, setFormValue] = useLoading(async (row) => {
|
|
51
|
-
const formValue =
|
|
66
|
+
const formValue = rowToForm && row ? await rowToForm(row) : row;
|
|
52
67
|
formValue && innerFormRef.current?.setFormValue(formValue);
|
|
53
68
|
});
|
|
54
69
|
useEffect(() => {
|
|
55
|
-
innerOpen.current && setFormValue(activeRow);
|
|
56
|
-
}, [innerOpen.current]);
|
|
70
|
+
innerOpen.current && !suppressTransform.current && setFormValue(activeRow);
|
|
71
|
+
}, [innerOpen.current, activeRow]);
|
|
57
72
|
const renderedFormItems = useMemo(() => {
|
|
58
73
|
return columnsToFormItem(columns, activeRow)?.map(col => {
|
|
59
74
|
if (isValidElement(col)) {
|
|
@@ -72,7 +87,7 @@ curdProps, ...props }) => {
|
|
|
72
87
|
};
|
|
73
88
|
const [innerLoading, finishHandler] = useLoading(async (value) => {
|
|
74
89
|
formProps?.onFinish?.(value);
|
|
75
|
-
|
|
90
|
+
openResolvers.current?.resolve(value);
|
|
76
91
|
await onFinish?.(value);
|
|
77
92
|
setInnerOpen(false);
|
|
78
93
|
}, props.confirmLoading);
|
|
@@ -80,20 +95,32 @@ curdProps, ...props }) => {
|
|
|
80
95
|
* ----------------------------------------------------------------
|
|
81
96
|
* 复制
|
|
82
97
|
*/
|
|
98
|
+
const isCopying = useRef(false);
|
|
83
99
|
const pickerDialogRef = useRef(null);
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
100
|
+
const onCopyButtonClick = () => {
|
|
101
|
+
isCopying.current = true;
|
|
102
|
+
setSelectMode('single');
|
|
103
|
+
pickerDialogRef.current.open().then();
|
|
104
|
+
};
|
|
105
|
+
const toggleHandler = (checked, value, row) => {
|
|
106
|
+
if (isCopying.current) {
|
|
107
|
+
const title = !isUnset(titleKey) ? row[titleKey] : void 0;
|
|
108
|
+
typeof title === 'string'
|
|
109
|
+
? setFormValue({
|
|
110
|
+
...row,
|
|
111
|
+
[titleKey]: `${title} - 副本`
|
|
112
|
+
})
|
|
113
|
+
: setFormValue(row);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
// 处理selectSingle
|
|
117
|
+
selectResolvers.current?.resolve(row);
|
|
118
|
+
}
|
|
92
119
|
};
|
|
93
120
|
const rowTitle = activeRow && !isUnset(titleKey) ? activeRow[titleKey] : void 0;
|
|
94
121
|
return (_jsxs(Dialog, { css: dialogStyle, width: 600, title: activeRow
|
|
95
122
|
? `${updateName}${dataName}${rowTitle ? ' - ' + rowTitle : ''}`
|
|
96
123
|
: _jsxs("div", { className: classes.dialogTitle, children: [_jsxs("span", { children: [createName, dataName] }), copyable &&
|
|
97
|
-
_jsxs(Button, { variant: "plain", prefix: _jsx(Icon, { icon: faCopy }), onClick:
|
|
98
|
-
_jsx(PickerDialog, { ref: pickerDialogRef, onToggle:
|
|
124
|
+
_jsxs(Button, { variant: "plain", prefix: _jsx(Icon, { icon: faCopy }), onClick: onCopyButtonClick, children: ["\u4ECE\u5DF2\u6709", dataName || '数据', "\u590D\u5236"] })] }), ...props, open: innerOpen.current, onClose: closeHandler, onConfirm: confirmHandler, confirmLoading: innerLoading.current, children: [_jsx(Loading, { open: transforming.current, children: _jsx(Form, { labelWidth: "20%", ...formProps, ref: cloneRef(formRef, innerFormRef), onFinish: finishHandler, children: renderedFormItems }) }), copyable &&
|
|
125
|
+
_jsx(PickerDialog, { ref: pickerDialogRef, multiple: selectMode === 'multiple', onToggle: toggleHandler, children: _jsx(Curd, { ...curdProps, variant: "embeded", copyable: false, creatable: false, updatable: false, deletable: false }) })] }));
|
|
99
126
|
});
|
|
@@ -13,13 +13,6 @@ export const PickerDialog = (({ ref, dialogRef, multiple, children, showSelected
|
|
|
13
13
|
// 以下属性从SelectionContextBaseProps继承
|
|
14
14
|
options = rows ?? nodes, primaryKey = 'id', childrenKey = 'children', relation = 'dependent', integration = 'shallowest', disabled, clearable = !!multiple, onToggle, ...props }) => {
|
|
15
15
|
const resolvers = useRef(void 0);
|
|
16
|
-
const [innerValue, _setInnerValue] = useState(multiple ? [] : null);
|
|
17
|
-
const setInnerValue = (value) => {
|
|
18
|
-
_setInnerValue(value);
|
|
19
|
-
// 单选模式,值每次改变都触发确认
|
|
20
|
-
!multiple && confirmHandler(value);
|
|
21
|
-
};
|
|
22
|
-
const [innerOpen, setInnerOpen] = useControlled(props.defaultOpen, props.open);
|
|
23
16
|
useImperativeHandle(ref, () => ({
|
|
24
17
|
open(value) {
|
|
25
18
|
_setInnerValue(value ?? null);
|
|
@@ -28,6 +21,13 @@ options = rows ?? nodes, primaryKey = 'id', childrenKey = 'children', relation =
|
|
|
28
21
|
return promise;
|
|
29
22
|
}
|
|
30
23
|
}));
|
|
24
|
+
const [innerValue, _setInnerValue] = useState(multiple ? [] : null);
|
|
25
|
+
const setInnerValue = (value) => {
|
|
26
|
+
_setInnerValue(value);
|
|
27
|
+
// 单选模式,值每次改变都触发确认
|
|
28
|
+
!multiple && confirmHandler(value);
|
|
29
|
+
};
|
|
30
|
+
const [innerOpen, setInnerOpen] = useControlled(props.defaultOpen, props.open);
|
|
31
31
|
const onCloseHandler = (reason) => {
|
|
32
32
|
if (reason === 'confirmed') {
|
|
33
33
|
return;
|