@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 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.6.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.6.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="flex flex-col gap-2">
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"
@@ -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 };