@lingxiteam/ebe-utils 0.4.0 → 0.4.3
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Select as AntdSelect, Tag } from 'antd';
|
|
2
|
-
import type { SelectProps } from 'antd/es/select';
|
|
2
|
+
import type { SelectProps, DefaultOptionType } from 'antd/es/select';
|
|
3
3
|
import { CheckOutlined } from '@lingxiteam/icons';
|
|
4
|
-
import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
5
5
|
import { renderCommonList } from '../utils/renderReadOnly';
|
|
6
6
|
import { useFuncExpExecute } from '../utils/hooks/useFuncExpExecute';
|
|
7
7
|
import { FormFields, getFieldsProps, useCommonImperativeHandle, useForm } from '../utils';
|
|
@@ -14,6 +14,7 @@ import { CHECK_ALL_VALUE, handleFormValue, isLabelInValue, localFilterOption, ge
|
|
|
14
14
|
import CustomModule from '../utils/CustomModule';
|
|
15
15
|
import { EngineBaseProps } from '@lingxiteam/types';
|
|
16
16
|
import { isEqual } from 'lodash';
|
|
17
|
+
import useDoubleClick from '../utils/hooks/useDoubleClick';
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
export interface MySelectProps extends EngineBaseProps {
|
|
@@ -71,6 +72,7 @@ export interface MySelectProps extends EngineBaseProps {
|
|
|
71
72
|
* 是否输入触发,默认fasel,也就是回车键触发, 为true的时候表示实时搜索
|
|
72
73
|
*/
|
|
73
74
|
isInputSearch?: boolean;
|
|
75
|
+
localFilterType?: 'default' | 'label' | 'value';
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
interface WrapperSelectProps {
|
|
@@ -85,6 +87,7 @@ const WrapperSelect: React.FC<WrapperSelectProps> = ({ children }) =>
|
|
|
85
87
|
|
|
86
88
|
|
|
87
89
|
const Select = React.forwardRef<any, MySelectProps>((props, ref) => {
|
|
90
|
+
console.log('Select', props);
|
|
88
91
|
const {
|
|
89
92
|
value: originValue,
|
|
90
93
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -134,10 +137,10 @@ const Select = React.forwardRef<any, MySelectProps>((props, ref) => {
|
|
|
134
137
|
labelKey = 'label',
|
|
135
138
|
valueKey = 'value',
|
|
136
139
|
mode,
|
|
140
|
+
localFilterType,
|
|
137
141
|
$$componentItem,
|
|
138
142
|
...restProps
|
|
139
143
|
} = props;
|
|
140
|
-
|
|
141
144
|
const defaultValue = useMemo(() => {
|
|
142
145
|
if ((_defaultValue === null || _defaultValue === '') && mode === 'multiple') {
|
|
143
146
|
return undefined;
|
|
@@ -190,7 +193,7 @@ const Select = React.forwardRef<any, MySelectProps>((props, ref) => {
|
|
|
190
193
|
formFieldsRef,
|
|
191
194
|
readOnly,
|
|
192
195
|
} = useCommonImperativeHandle(ref, props, {
|
|
193
|
-
clearValue: [],
|
|
196
|
+
clearValue: mode === 'multiple' ? [] : undefined,
|
|
194
197
|
getSelectedData: () => {
|
|
195
198
|
return getChangeSelectData(dataSource, value, mode);
|
|
196
199
|
},
|
|
@@ -267,7 +270,7 @@ const Select = React.forwardRef<any, MySelectProps>((props, ref) => {
|
|
|
267
270
|
defaultActiveFirstOption: false,
|
|
268
271
|
showSearch: true,
|
|
269
272
|
optionFilterProp: 'children',
|
|
270
|
-
filterOption: localFilterOption,
|
|
273
|
+
filterOption: (inputValue, option) => localFilterOption(inputValue, option, localFilterType),
|
|
271
274
|
onSearch: handleLocalSearch,
|
|
272
275
|
};
|
|
273
276
|
}
|
|
@@ -304,7 +307,29 @@ const Select = React.forwardRef<any, MySelectProps>((props, ref) => {
|
|
|
304
307
|
};
|
|
305
308
|
}
|
|
306
309
|
return {};
|
|
307
|
-
}, [filter, dataState]);
|
|
310
|
+
}, [filter, dataState, localFilterType]);
|
|
311
|
+
|
|
312
|
+
const filterSort = useCallback((optionA: DefaultOptionType, optionB: DefaultOptionType) => {
|
|
313
|
+
const getScore = (option: any) => {
|
|
314
|
+
const label = String(option?.children || option?.label || '').toLowerCase();
|
|
315
|
+
const value = String(option?.value || '').toLowerCase();
|
|
316
|
+
const search = searchTextRef.current?.toLowerCase() || '';
|
|
317
|
+
|
|
318
|
+
// 匹配位置越靠前,排名越前
|
|
319
|
+
if (localFilterType === 'label') {
|
|
320
|
+
return label.indexOf(search);
|
|
321
|
+
} if (localFilterType === 'value') {
|
|
322
|
+
return value.indexOf(search);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return Math.min(
|
|
326
|
+
label.includes(search) ? label.indexOf(search) : Infinity,
|
|
327
|
+
value.includes(search) ? value.indexOf(search) : Infinity
|
|
328
|
+
);
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
return getScore(optionA) - getScore(optionB);
|
|
332
|
+
}, [localFilterType]);
|
|
308
333
|
|
|
309
334
|
const renderGengelContent = (c: any, data: any) => {
|
|
310
335
|
const {
|
|
@@ -597,7 +622,15 @@ const Select = React.forwardRef<any, MySelectProps>((props, ref) => {
|
|
|
597
622
|
|
|
598
623
|
const tagRender = (props: any) => {
|
|
599
624
|
const { label, closable, onClose } = props;
|
|
600
|
-
const { color, backgroundColor
|
|
625
|
+
const { color, backgroundColor, isBaseText, isShallowPrimary, isPrimary } =
|
|
626
|
+
customRenderLabel?.options || {};
|
|
627
|
+
const style: React.CSSProperties = {};
|
|
628
|
+
if (!isBaseText) {
|
|
629
|
+
style.color = color;
|
|
630
|
+
}
|
|
631
|
+
if (!isShallowPrimary && !isPrimary) {
|
|
632
|
+
style.backgroundColor = backgroundColor;
|
|
633
|
+
}
|
|
601
634
|
return (
|
|
602
635
|
<Tag
|
|
603
636
|
className={classNames({
|
|
@@ -606,7 +639,7 @@ const Select = React.forwardRef<any, MySelectProps>((props, ref) => {
|
|
|
606
639
|
darkBackground: customRenderLabel?.type === 'darkBackground',
|
|
607
640
|
jsx: customRenderLabel?.jsx,
|
|
608
641
|
})}
|
|
609
|
-
style={
|
|
642
|
+
style={style}
|
|
610
643
|
// color={value}
|
|
611
644
|
// onMouseDown={onPreventMouseDown}
|
|
612
645
|
closable={closable}
|
|
@@ -617,6 +650,32 @@ const Select = React.forwardRef<any, MySelectProps>((props, ref) => {
|
|
|
617
650
|
);
|
|
618
651
|
};
|
|
619
652
|
|
|
653
|
+
const selectOnClick = (e: any) => {
|
|
654
|
+
let targetParent = (e?.target as HTMLBaseElement)?.parentNode;
|
|
655
|
+
const curretTarget = e?.currentTarget;
|
|
656
|
+
while (targetParent && targetParent !== curretTarget) {
|
|
657
|
+
targetParent = targetParent.parentNode;
|
|
658
|
+
}
|
|
659
|
+
if (targetParent === curretTarget) {
|
|
660
|
+
setOpen(!open);
|
|
661
|
+
if (open) {
|
|
662
|
+
handleAfterClose();
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
// @ts-ignore
|
|
666
|
+
restProps?.onClick?.(e);
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
// 改造兼容双击事件
|
|
670
|
+
const selectClickEvents = useDoubleClick({
|
|
671
|
+
clickName: 'onClick',
|
|
672
|
+
doubleClickName: 'onDoubleClick',
|
|
673
|
+
type: 'Button',
|
|
674
|
+
events: {
|
|
675
|
+
onClick: selectOnClick,
|
|
676
|
+
},
|
|
677
|
+
});
|
|
678
|
+
|
|
620
679
|
return (
|
|
621
680
|
<FormFields
|
|
622
681
|
{...getFieldsProps(props)}
|
|
@@ -645,6 +704,8 @@ const Select = React.forwardRef<any, MySelectProps>((props, ref) => {
|
|
|
645
704
|
tagRender={tagRender}
|
|
646
705
|
optionLabelProp="label"
|
|
647
706
|
notFoundContent={searching ? <SpinComp dataState={dataState} /> : renderEmpty}
|
|
707
|
+
filterSort={filterSort}
|
|
708
|
+
{...selectClickEvents}
|
|
648
709
|
onChange={(v) => {
|
|
649
710
|
if (filter === 'local' && searchTextRef.current) {
|
|
650
711
|
// 点击时需要重置过滤条件
|
|
@@ -658,21 +719,22 @@ const Select = React.forwardRef<any, MySelectProps>((props, ref) => {
|
|
|
658
719
|
|
|
659
720
|
handleOnChange(v);
|
|
660
721
|
}}
|
|
661
|
-
onClick={(e) => {
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
722
|
+
// onClick={(e) => {
|
|
723
|
+
// console.log('单击:', e);
|
|
724
|
+
// let targetParent = (e?.target as HTMLBaseElement)?.parentNode;
|
|
725
|
+
// const curretTarget = e?.currentTarget;
|
|
726
|
+
// while (targetParent && targetParent !== curretTarget) {
|
|
727
|
+
// targetParent = targetParent.parentNode;
|
|
728
|
+
// }
|
|
729
|
+
// if (targetParent === curretTarget) {
|
|
730
|
+
// setOpen(!open);
|
|
731
|
+
// if (open) {
|
|
732
|
+
// handleAfterClose();
|
|
733
|
+
// }
|
|
734
|
+
// }
|
|
735
|
+
// // @ts-ignore
|
|
736
|
+
// restProps?.onClick?.(e);
|
|
737
|
+
// }}
|
|
676
738
|
onBlur={() => {
|
|
677
739
|
setOpen(false);
|
|
678
740
|
handleAfterClose();
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
1
3
|
export const CHECK_ALL_VALUE = 'LING_XI_CHECK_ALL';
|
|
2
4
|
|
|
5
|
+
|
|
3
6
|
const typeFn: any = {
|
|
4
7
|
string: String,
|
|
5
8
|
number: Number,
|
|
@@ -12,33 +15,70 @@ const typeFn: any = {
|
|
|
12
15
|
* @param option
|
|
13
16
|
* @returns
|
|
14
17
|
*/
|
|
15
|
-
export const localFilterOption = (input: string = '', option: any) => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
// export const localFilterOption = (input: string = '', option: any) => {
|
|
19
|
+
// // 本地支持value和label过滤
|
|
20
|
+
// let valueFilter = false;
|
|
21
|
+
// if (option?.value === CHECK_ALL_VALUE) {
|
|
22
|
+
// // 存在全选项时,永远展示
|
|
23
|
+
// return true;
|
|
24
|
+
// }
|
|
25
|
+
// if (option?.value && typeof option?.value === 'string') {
|
|
26
|
+
// valueFilter = option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
|
27
|
+
// }
|
|
28
|
+
// if (option?.children && typeof option.children === 'string') {
|
|
29
|
+
// return option?.children?.toLowerCase?.().indexOf(input.toLowerCase()) >= 0 || valueFilter;
|
|
30
|
+
// }
|
|
31
|
+
|
|
32
|
+
// return option?.label?.toLowerCase?.().indexOf(input.toLowerCase()) >= 0 || valueFilter;
|
|
33
|
+
// };
|
|
34
|
+
|
|
35
|
+
const checkInputValue = (input: string = '', value: any) => {
|
|
36
|
+
if (value !== null && value !== undefined) {
|
|
37
|
+
return String(value).toLowerCase().includes(input);
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const localFilterOption = (input: string = '', option: any, localFilterType?: 'default' | 'label' | 'value') => {
|
|
18
43
|
if (option?.value === CHECK_ALL_VALUE) {
|
|
19
44
|
// 存在全选项时,永远展示
|
|
20
45
|
return true;
|
|
21
46
|
}
|
|
22
|
-
if (option?.value && typeof option?.value === 'string') {
|
|
23
|
-
valueFilter = option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
|
24
|
-
}
|
|
25
|
-
if (option?.children && typeof option.children === 'string') {
|
|
26
|
-
return option?.children?.toLowerCase?.().indexOf(input.toLowerCase()) >= 0 || valueFilter;
|
|
27
|
-
}
|
|
28
47
|
|
|
29
|
-
|
|
48
|
+
const inputLower = input.toLowerCase();
|
|
49
|
+
|
|
50
|
+
// 处理 value 过滤
|
|
51
|
+
const valueFilter = checkInputValue(inputLower, option.value);
|
|
52
|
+
|
|
53
|
+
// 处理 label 或 children 过滤
|
|
54
|
+
const childernFilter = option?.children && typeof option.children === 'string' ? checkInputValue(inputLower, option.children) : false;
|
|
55
|
+
const labelFilter = checkInputValue(inputLower, option.label);
|
|
56
|
+
|
|
57
|
+
// 根据 localFilterType 决定返回值
|
|
58
|
+
switch (localFilterType) {
|
|
59
|
+
case 'value':
|
|
60
|
+
return valueFilter;
|
|
61
|
+
case 'label':
|
|
62
|
+
return labelFilter || childernFilter;
|
|
63
|
+
default:
|
|
64
|
+
return labelFilter || childernFilter || valueFilter;
|
|
65
|
+
}
|
|
30
66
|
};
|
|
31
67
|
|
|
32
68
|
// 判断data类型是不是是labelInValue格式
|
|
33
69
|
export const isLabelInValue = (data: any) => {
|
|
34
70
|
if (Object.prototype.toString.call(data) === '[object Object]') {
|
|
35
|
-
if (Object.keys(data).includes('label') &&
|
|
71
|
+
if (Object.keys(data).includes('label') &&
|
|
72
|
+
(Object.keys(data).includes('value') || Object.keys(data).includes('key'))) {
|
|
36
73
|
return true;
|
|
37
74
|
}
|
|
38
75
|
} else if (Object.prototype.toString.call(data) === '[object Array]' && data.length) {
|
|
39
76
|
let isLabelInValueCount = 0;
|
|
40
77
|
data.forEach((v: any) => {
|
|
41
|
-
if (
|
|
78
|
+
if (
|
|
79
|
+
Object.keys(v).includes('label') &&
|
|
80
|
+
(Object.keys(v).includes('value') || Object.keys(v).includes('key'))
|
|
81
|
+
) {
|
|
42
82
|
isLabelInValueCount += 1;
|
|
43
83
|
}
|
|
44
84
|
});
|
|
@@ -83,6 +123,7 @@ export const transformValueType = (v: any, curVal: any) => {
|
|
|
83
123
|
return v;
|
|
84
124
|
};
|
|
85
125
|
|
|
126
|
+
|
|
86
127
|
export const getRules = (min?: number, max?: number, getLocale?: any) => {
|
|
87
128
|
if (!min && !max) {
|
|
88
129
|
return [];
|
|
@@ -112,7 +153,7 @@ export const getChangeSelectData = (dataSource: any[], val: string[] | Object, m
|
|
|
112
153
|
return undefined;
|
|
113
154
|
}
|
|
114
155
|
const sltData = dataSource.find((c: any) => c.value?.toString() === v?.toString());
|
|
115
|
-
return sltData ? [sltData] : undefined;
|
|
156
|
+
return (sltData ? [sltData] : undefined);
|
|
116
157
|
};
|
|
117
158
|
|
|
118
159
|
export const getSelectedAllData = (checked: boolean, dataSource: any[], value: any[], max?: number) => {
|
|
@@ -157,7 +198,7 @@ export const getSelectedAllData = (checked: boolean, dataSource: any[], value: a
|
|
|
157
198
|
|
|
158
199
|
// 获取当前列表数据下的全选状态
|
|
159
200
|
export const checkIfSelectedAll = (dataSource: any[], value: any[], filterValue: string = '') => {
|
|
160
|
-
const localFilterData = dataSource.filter(
|
|
201
|
+
const localFilterData = dataSource.filter(d => localFilterOption(filterValue, d));
|
|
161
202
|
if (localFilterData?.length && Array.isArray(value)) {
|
|
162
203
|
// 如果是多选,value肯定是字符串类型的数组
|
|
163
204
|
const checkData = localFilterData.filter((f: any) => value.includes(f.value));
|
|
@@ -174,7 +215,7 @@ export const checkIfSelectedAll = (dataSource: any[], value: any[], filterValue:
|
|
|
174
215
|
* @param labelKey
|
|
175
216
|
* @returns
|
|
176
217
|
*/
|
|
177
|
-
export const handleDataSource = (dataSource: any[], appendDataSoure?: any[] | Object, valueKey?: string, labelKey?: string) => {
|
|
218
|
+
export const handleDataSource = (dataSource: any[], appendDataSoure?: any[] | Object, valueKey?: string, labelKey?: string,) => {
|
|
178
219
|
const valueKeys: any = [];
|
|
179
220
|
let newDataSoure: any[] = [];
|
|
180
221
|
if (Array.isArray(dataSource)) {
|
|
@@ -182,7 +223,7 @@ export const handleDataSource = (dataSource: any[], appendDataSoure?: any[] | Ob
|
|
|
182
223
|
const label = v?.[labelKey || 'label'];
|
|
183
224
|
const value = v?.[valueKey || 'value'] || v?.key;
|
|
184
225
|
if (value) {
|
|
185
|
-
//
|
|
226
|
+
// 兼容源码逻辑
|
|
186
227
|
valueKeys.push(`${value}`);
|
|
187
228
|
newDataSoure.push({
|
|
188
229
|
...v,
|
|
@@ -194,7 +235,7 @@ export const handleDataSource = (dataSource: any[], appendDataSoure?: any[] | Ob
|
|
|
194
235
|
}
|
|
195
236
|
let newAppednDataSoure = [];
|
|
196
237
|
if (Array.isArray(appendDataSoure) && appendDataSoure.length > 0) {
|
|
197
|
-
newAppednDataSoure = appendDataSoure.filter(
|
|
238
|
+
newAppednDataSoure = appendDataSoure.filter(item => !valueKeys?.includes(item?.[valueKey || 'value'] || item?.key));
|
|
198
239
|
}
|
|
199
240
|
if (Object.prototype.toString.call(appendDataSoure) === '[object Object]') {
|
|
200
241
|
newAppednDataSoure = [appendDataSoure].filter((item: any) => !valueKeys?.includes(item?.[valueKey || 'value'] || item?.key));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lingxiteam/ebe-utils",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"author": "",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"@babel/types": "^7.12.12",
|
|
20
20
|
"cac": "^6.7.14",
|
|
21
21
|
"fs-extra": "9.x",
|
|
22
|
-
"@lingxiteam/ebe": "0.4.
|
|
22
|
+
"@lingxiteam/ebe": "0.4.3"
|
|
23
23
|
},
|
|
24
24
|
"publishConfig": {
|
|
25
25
|
"access": "public"
|