@fe-free/core 2.6.2 → 2.7.1
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/CHANGELOG.md +17 -0
- package/package.json +2 -2
- package/src/form/form.stories.tsx +46 -0
- package/src/form/form_list/form_list_helper.tsx +7 -3
- package/src/form/index.tsx +1 -0
- package/src/form/pro_form_record.tsx +56 -0
- package/src/index.ts +3 -0
- package/src/record/index.tsx +150 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @fe-free/core
|
|
2
2
|
|
|
3
|
+
## 2.7.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- feat: record
|
|
8
|
+
- @fe-free/tool@2.7.1
|
|
9
|
+
|
|
10
|
+
## 2.7.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- feat: record
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- @fe-free/tool@2.7.0
|
|
19
|
+
|
|
3
20
|
## 2.6.2
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fe-free/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"author": "",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"remark-gfm": "^4.0.1",
|
|
42
42
|
"vanilla-jsoneditor": "^0.23.1",
|
|
43
43
|
"zustand": "^4.5.4",
|
|
44
|
-
"@fe-free/tool": "2.
|
|
44
|
+
"@fe-free/tool": "2.7.1"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"@ant-design/pro-components": "2.8.9",
|
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
ProFormJavascript,
|
|
8
8
|
ProFormListNumber,
|
|
9
9
|
ProFormListText,
|
|
10
|
+
ProFormRecord,
|
|
11
|
+
ProFormRecordArray,
|
|
10
12
|
ProFormSwitchNumber,
|
|
11
13
|
ProFormUpload,
|
|
12
14
|
ProFormUploadDragger,
|
|
@@ -234,3 +236,47 @@ export const ProFormImageUploadComponent: Story = {
|
|
|
234
236
|
</ProFormBase>
|
|
235
237
|
),
|
|
236
238
|
};
|
|
239
|
+
|
|
240
|
+
export const ProFormRecordComponent: Story = {
|
|
241
|
+
render: () => (
|
|
242
|
+
<ProFormBase>
|
|
243
|
+
<ProFormRecord
|
|
244
|
+
name="record1"
|
|
245
|
+
label="record1"
|
|
246
|
+
fieldProps={{
|
|
247
|
+
labels: [
|
|
248
|
+
{ key: 'username', label: '用户名' },
|
|
249
|
+
{ key: 'password', label: '密码' },
|
|
250
|
+
],
|
|
251
|
+
}}
|
|
252
|
+
initialValue={{
|
|
253
|
+
username: '',
|
|
254
|
+
password: '',
|
|
255
|
+
}}
|
|
256
|
+
/>
|
|
257
|
+
<ProFormRecord name="record2" label="record2" />
|
|
258
|
+
</ProFormBase>
|
|
259
|
+
),
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
export const ProFormRecordArrayComponent: Story = {
|
|
263
|
+
render: () => (
|
|
264
|
+
<ProFormBase>
|
|
265
|
+
<ProFormRecordArray
|
|
266
|
+
name="recordArray1"
|
|
267
|
+
label="recordArray1"
|
|
268
|
+
fieldProps={{
|
|
269
|
+
labels: [
|
|
270
|
+
{ key: 'username', label: '用户名' },
|
|
271
|
+
{ key: 'password', label: '密码' },
|
|
272
|
+
],
|
|
273
|
+
}}
|
|
274
|
+
initialValue={[
|
|
275
|
+
{ key: 'username', value: undefined },
|
|
276
|
+
{ key: 'password', value: undefined },
|
|
277
|
+
]}
|
|
278
|
+
/>
|
|
279
|
+
<ProFormRecordArray name="recordArray2" label="recordArray2" />
|
|
280
|
+
</ProFormBase>
|
|
281
|
+
),
|
|
282
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
|
|
2
2
|
import { Button } from 'antd';
|
|
3
|
+
import classNames from 'classnames';
|
|
3
4
|
|
|
4
5
|
interface ProFormListHelperProps<T> {
|
|
5
6
|
value?: T[];
|
|
@@ -12,7 +13,10 @@ interface ProFormListHelperProps<T> {
|
|
|
12
13
|
}) => React.ReactNode;
|
|
13
14
|
addText?: string;
|
|
14
15
|
getAdd: () => T;
|
|
16
|
+
disabledAdd?: boolean;
|
|
17
|
+
disabledDelete?: boolean;
|
|
15
18
|
readOnly?: boolean;
|
|
19
|
+
className?: string;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
const emptyArr = [];
|
|
@@ -20,7 +24,7 @@ function ProFormListHelper<T = any>(props: ProFormListHelperProps<T>) {
|
|
|
20
24
|
const options = props.value || emptyArr;
|
|
21
25
|
|
|
22
26
|
return (
|
|
23
|
-
<div className=
|
|
27
|
+
<div className={classNames('flex flex-col gap-2', props.className)}>
|
|
24
28
|
<div className="flex flex-col gap-2">
|
|
25
29
|
{options.map((item, index) => {
|
|
26
30
|
return (
|
|
@@ -37,7 +41,7 @@ function ProFormListHelper<T = any>(props: ProFormListHelperProps<T>) {
|
|
|
37
41
|
},
|
|
38
42
|
})}
|
|
39
43
|
</div>
|
|
40
|
-
{!props.readOnly && (
|
|
44
|
+
{!props.readOnly && !props.disabledDelete && (
|
|
41
45
|
<Button
|
|
42
46
|
icon={<DeleteOutlined />}
|
|
43
47
|
type="text"
|
|
@@ -52,7 +56,7 @@ function ProFormListHelper<T = any>(props: ProFormListHelperProps<T>) {
|
|
|
52
56
|
);
|
|
53
57
|
})}
|
|
54
58
|
</div>
|
|
55
|
-
{!props.readOnly && (
|
|
59
|
+
{!props.readOnly && !props.disabledAdd && (
|
|
56
60
|
<div className="flex justify-center">
|
|
57
61
|
<Button
|
|
58
62
|
size="small"
|
package/src/form/index.tsx
CHANGED
|
@@ -4,6 +4,7 @@ export { ProFormListModalHelper } from './form_list/form_list_modal_helper';
|
|
|
4
4
|
export { ProFormEditor } from './pro_form_editor';
|
|
5
5
|
export { ProFormJavascript } from './pro_form_javascript';
|
|
6
6
|
export { ProFormJSON } from './pro_form_json';
|
|
7
|
+
export { ProFormRecord, ProFormRecordArray } from './pro_form_record';
|
|
7
8
|
export {
|
|
8
9
|
ProFormSwitchNumber,
|
|
9
10
|
SwitchNumber,
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ProFormItemProps } from '@ant-design/pro-components';
|
|
2
|
+
import { ProForm } from '@ant-design/pro-components';
|
|
3
|
+
import type { RecordArrayProps, RecordProps } from '../record';
|
|
4
|
+
import { Record, RecordArray } from '../record';
|
|
5
|
+
|
|
6
|
+
function ProFormRecord(props: ProFormItemProps<RecordProps>) {
|
|
7
|
+
const { fieldProps, ...rest } = props;
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<ProForm.Item
|
|
11
|
+
{...rest}
|
|
12
|
+
rules={[
|
|
13
|
+
...(props.rules || []),
|
|
14
|
+
{
|
|
15
|
+
validator: async (_, value) => {
|
|
16
|
+
const values = Object.values(value || {});
|
|
17
|
+
if (values.length && values.filter(Boolean).length !== values.length) {
|
|
18
|
+
return Promise.reject('选项不能为空');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return Promise.resolve();
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
]}
|
|
25
|
+
>
|
|
26
|
+
<Record {...(fieldProps as RecordProps)} />
|
|
27
|
+
</ProForm.Item>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function ProFormRecordArray(props: ProFormItemProps<RecordArrayProps>) {
|
|
32
|
+
const { fieldProps, ...rest } = props;
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<ProForm.Item
|
|
36
|
+
{...rest}
|
|
37
|
+
rules={[
|
|
38
|
+
...(props.rules || []),
|
|
39
|
+
{
|
|
40
|
+
validator: async (_, value) => {
|
|
41
|
+
console.log('value', value);
|
|
42
|
+
if (value?.some((item) => item.value === undefined || item.key === undefined)) {
|
|
43
|
+
return Promise.reject('选项不能为空');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return Promise.resolve();
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
]}
|
|
50
|
+
>
|
|
51
|
+
<RecordArray {...(fieldProps as RecordArrayProps)} />
|
|
52
|
+
</ProForm.Item>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export { ProFormRecord, ProFormRecordArray };
|
package/src/index.ts
CHANGED
|
@@ -31,6 +31,8 @@ export {
|
|
|
31
31
|
ProFormListModalHelper,
|
|
32
32
|
ProFormListNumber,
|
|
33
33
|
ProFormListText,
|
|
34
|
+
ProFormRecord,
|
|
35
|
+
ProFormRecordArray,
|
|
34
36
|
ProFormSwitchNumber,
|
|
35
37
|
ProFormUpload,
|
|
36
38
|
ProFormUploadDragger,
|
|
@@ -43,6 +45,7 @@ export type { InfiniteListProps } from './infinite_list';
|
|
|
43
45
|
export { Markdown } from './markdown';
|
|
44
46
|
export { PageLayout, PageLayoutTabs } from './page_layout';
|
|
45
47
|
export type { PageLayoutProps, PageLayoutTabsProps } from './page_layout';
|
|
48
|
+
export type { RecordArrayProps, RecordProps } from './record';
|
|
46
49
|
export { routeTool } from './route';
|
|
47
50
|
export { NumberSlider, PercentageSlider } from './slider';
|
|
48
51
|
export type { NumberSliderProps, PercentageSliderProps } from './slider';
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { Divider, Input } from 'antd';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import { useCallback, useMemo } from 'react';
|
|
4
|
+
import { ProFormListHelper } from '../form';
|
|
5
|
+
|
|
6
|
+
function Item({
|
|
7
|
+
value,
|
|
8
|
+
label,
|
|
9
|
+
onChange,
|
|
10
|
+
}: {
|
|
11
|
+
value?: string;
|
|
12
|
+
label?: string;
|
|
13
|
+
onChange: (value: string) => void;
|
|
14
|
+
}) {
|
|
15
|
+
return (
|
|
16
|
+
<div className="flex flex-col gap-2">
|
|
17
|
+
<div className="flex items-center gap-1">
|
|
18
|
+
<span className="text-red-500">*</span>
|
|
19
|
+
{label}
|
|
20
|
+
</div>
|
|
21
|
+
<Input
|
|
22
|
+
value={value}
|
|
23
|
+
placeholder={'请输入'}
|
|
24
|
+
onChange={(e) => {
|
|
25
|
+
onChange(e.target.value);
|
|
26
|
+
}}
|
|
27
|
+
/>
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface RecordItem {
|
|
33
|
+
value?: { key?: string; value?: string };
|
|
34
|
+
onChange: (value: { key?: string; value?: string }) => void;
|
|
35
|
+
label?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function RecordItem(props: RecordItem) {
|
|
39
|
+
const { value, onChange, label } = props;
|
|
40
|
+
|
|
41
|
+
// 如果提供了 label
|
|
42
|
+
if (label) {
|
|
43
|
+
return (
|
|
44
|
+
<Item
|
|
45
|
+
value={value?.value}
|
|
46
|
+
label={label || value?.key}
|
|
47
|
+
onChange={(v) => {
|
|
48
|
+
onChange({ key: value?.key, value: v });
|
|
49
|
+
}}
|
|
50
|
+
/>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<div className="flex flex-col gap-1">
|
|
56
|
+
<Item
|
|
57
|
+
value={value?.key}
|
|
58
|
+
onChange={(v) => {
|
|
59
|
+
onChange({ key: v, value: value?.value });
|
|
60
|
+
}}
|
|
61
|
+
label="Key"
|
|
62
|
+
/>
|
|
63
|
+
<Item
|
|
64
|
+
value={value?.value}
|
|
65
|
+
onChange={(v) => {
|
|
66
|
+
onChange({ key: value?.key, value: v });
|
|
67
|
+
}}
|
|
68
|
+
label="Value"
|
|
69
|
+
/>
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface RecordArrayProps {
|
|
75
|
+
value?: { key?: string; value?: string }[];
|
|
76
|
+
onChange: (value: { key?: string; value?: string }[]) => void;
|
|
77
|
+
labels?: { key?: string; label?: string }[];
|
|
78
|
+
className?: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function RecordArray(props: RecordArrayProps) {
|
|
82
|
+
const { value, onChange, labels, className } = props;
|
|
83
|
+
|
|
84
|
+
const isFixed = !!labels?.length;
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<ProFormListHelper
|
|
88
|
+
className={classNames('c-bg rounded p-2', className)}
|
|
89
|
+
value={value}
|
|
90
|
+
onChange={onChange}
|
|
91
|
+
getAdd={() => ({
|
|
92
|
+
key: undefined,
|
|
93
|
+
value: undefined,
|
|
94
|
+
})}
|
|
95
|
+
disabledDelete={isFixed}
|
|
96
|
+
disabledAdd={isFixed}
|
|
97
|
+
>
|
|
98
|
+
{({ item, index, onItemChange }) => {
|
|
99
|
+
return (
|
|
100
|
+
<>
|
|
101
|
+
<RecordItem
|
|
102
|
+
value={item}
|
|
103
|
+
label={labels?.[index]?.label}
|
|
104
|
+
onChange={(v) => {
|
|
105
|
+
onItemChange(v);
|
|
106
|
+
}}
|
|
107
|
+
/>
|
|
108
|
+
{!isFixed && <Divider className="mb-2" />}
|
|
109
|
+
</>
|
|
110
|
+
);
|
|
111
|
+
}}
|
|
112
|
+
</ProFormListHelper>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
interface RecordProps extends Omit<RecordArrayProps, 'value' | 'onChange'> {
|
|
117
|
+
value?: Record<string, any>;
|
|
118
|
+
onChange: (value?: Record<string, any>) => void;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function Record(props: RecordProps) {
|
|
122
|
+
const { value, onChange, ...rest } = props;
|
|
123
|
+
|
|
124
|
+
// obj 和 arr 的转换
|
|
125
|
+
const newValue = useMemo(() => {
|
|
126
|
+
return Object.keys(value || {}).map((key) => ({
|
|
127
|
+
key,
|
|
128
|
+
value: value?.[key],
|
|
129
|
+
}));
|
|
130
|
+
}, [value]);
|
|
131
|
+
|
|
132
|
+
// obj 和 arr 的转换
|
|
133
|
+
const newOnChange = useCallback(
|
|
134
|
+
(newV: { key?: string; value?: string }[]) => {
|
|
135
|
+
const newValues = {};
|
|
136
|
+
newV.forEach((item, index) => {
|
|
137
|
+
// 确保有值
|
|
138
|
+
newValues[item.key || index] = item.value;
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
onChange(newValues);
|
|
142
|
+
},
|
|
143
|
+
[onChange],
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
return <RecordArray value={newValue} onChange={newOnChange} {...rest} />;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export { Record, RecordArray };
|
|
150
|
+
export type { RecordArrayProps, RecordProps };
|