Skip to content

Commit 830adf1

Browse files
committed
refactor(picker): reafactor picker component sync vue version
1 parent dd24b46 commit 830adf1

File tree

7 files changed

+715
-252
lines changed

7 files changed

+715
-252
lines changed

src/picker/Picker.tsx

+117-52
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,133 @@
1-
import React, { FC, useMemo } from 'react';
1+
import React, { FC, useState, MouseEvent, useEffect } from 'react';
2+
import useDefaultProps from 'tdesign-mobile-react/hooks/useDefaultProps';
3+
import isBoolean from 'lodash/isBoolean';
4+
import isString from 'lodash/isString';
25
import useConfig from '../_util/useConfig';
36
import useDefault from '../_util/useDefault';
4-
import withNativeProps, { NativeProps } from '../_util/withNativeProps';
5-
import PickerView, { getPickerViewDefaultValue } from './PickerView';
7+
import { NativeProps } from '../_util/withNativeProps';
68
import { pickerDefaultProps } from './defaultProps';
7-
import { TdPickerProps } from './type';
8-
import Button from '../button';
9-
import Popup from '../popup';
9+
import { TdPickerProps, PickerColumnItem, PickerValue } from './type';
10+
import { PickerColumn } from '.';
11+
12+
import PickerItem, { type PickerItemExposeRef } from './PickerItem';
1013

1114
export interface PickerProps extends TdPickerProps, NativeProps {}
1215

16+
function getDefaultText(prop: unknown, defaultText: string): string {
17+
if (isString(prop)) return prop;
18+
if (isBoolean(prop)) return defaultText;
19+
return;
20+
}
21+
22+
const getIndexFromColumns = (column: PickerColumn, value: PickerValue) => {
23+
if (!value) return 0;
24+
return column?.findIndex((item: PickerColumnItem) => item.value === value);
25+
};
26+
1327
const Picker: FC<PickerProps> = (props) => {
14-
const {
15-
visible,
16-
value,
17-
defaultValue,
18-
cancelBtn,
19-
confirmBtn,
20-
title,
21-
header,
22-
footer,
23-
children,
24-
onCancel,
25-
onConfirm,
26-
onChange,
27-
} = props;
28+
const { value, onChange, defaultValue, columns, onConfirm, onCancel, onPick, title, header } = useDefaultProps(
29+
props,
30+
pickerDefaultProps,
31+
);
32+
2833
const { classPrefix } = useConfig();
2934
const name = `${classPrefix}-picker`;
3035

31-
const internalDefaultValue = useMemo(
32-
() => getPickerViewDefaultValue(defaultValue, children),
33-
[defaultValue, children],
34-
);
36+
const [pickerValue, setPickerValue] = useDefault(value, defaultValue, onChange);
37+
const confirmButtonText = getDefaultText(props.confirmBtn, undefined);
38+
const cancelButtonText = getDefaultText(props.cancelBtn, undefined);
39+
const [curValueArray, setCurValueArray] = useState(pickerValue.map((item) => item) || []);
40+
41+
const realColumns = typeof columns === 'function' ? columns(curValueArray) : columns;
42+
const curIndexArray = realColumns.map((item: PickerColumn, index: number) => getIndexFromColumns(item, index));
43+
const [pickerItemInstanceArray, setPickerItemInstanceArray] = useState<PickerItemExposeRef[]>([]);
44+
45+
const setPickerItemRef = (instance: PickerItemExposeRef, idx: number) => {
46+
setPickerItemInstanceArray((prev) => {
47+
const copy = [...prev];
48+
copy[idx] = instance;
49+
return copy;
50+
});
51+
};
3552

36-
const [internalValue, setInternalValue] = useDefault(value, internalDefaultValue, onChange);
53+
function handleConfirm(e: MouseEvent<HTMLDivElement>) {
54+
const target = realColumns.map((item, idx) => item[curIndexArray[idx]]);
55+
const label = target.map((item) => item.label);
56+
const value = target.map((item) => item.value);
57+
setPickerValue(value, {
58+
columns: [],
59+
e,
60+
});
61+
onConfirm(value, { index: curIndexArray, e, label });
62+
}
63+
function handleCancel(e: MouseEvent<HTMLDivElement>) {
64+
pickerItemInstanceArray.forEach((item, idx) => {
65+
item?.setIndex(curIndexArray[idx]);
66+
});
67+
onCancel({ e });
68+
}
69+
70+
function handlePick(context: any, column: number) {
71+
const { index } = context;
72+
73+
curIndexArray[column] = index;
74+
curValueArray[column] = realColumns[column][index]?.value;
75+
76+
onPick(curValueArray, { index, column });
77+
}
78+
79+
useEffect(() => {
80+
setCurValueArray(pickerValue.map((item) => item));
81+
}, [pickerValue]);
82+
83+
useEffect(() => {
84+
realColumns.forEach((col: PickerColumn, idx: number) => {
85+
const index = col.findIndex((item) => item.value === curValueArray[idx]);
86+
curIndexArray[idx] = index > -1 ? index : 0;
87+
pickerItemInstanceArray[idx]?.setIndex(curIndexArray[idx]);
88+
});
89+
// eslint-disable-next-line react-hooks/exhaustive-deps
90+
}, [realColumns, curIndexArray]);
3791

3892
return (
39-
<Popup visible={visible} placement="bottom">
40-
{withNativeProps(
41-
props,
42-
<div className={name}>
43-
{header === true ? (
44-
<div className={`${name}__toolbar`}>
45-
<Button className={`${name}__cancel`} variant="text" onClick={(e) => onCancel?.({ e })}>
46-
{cancelBtn}
47-
</Button>
48-
<div className={`${name}__title`}>{title}</div>
49-
<Button className={`${name}__confirm`} variant="text" onClick={(e) => onConfirm?.(internalValue, { e })}>
50-
{confirmBtn}
51-
</Button>
52-
</div>
53-
) : (
54-
header
55-
)}
56-
{/* TODO:popup集成惰性加载后可移除条件渲染 */}
57-
{visible && (
58-
<PickerView value={internalValue} onChange={setInternalValue}>
59-
{children}
60-
</PickerView>
61-
)}
62-
{footer}
63-
</div>,
64-
)}
65-
</Popup>
93+
<div className={name}>
94+
<div className={`${name}__toolbar`}>
95+
{cancelButtonText ? (
96+
<div className={`${name}__cancel`} onClick={handleCancel}>
97+
{cancelButtonText}
98+
</div>
99+
) : null}
100+
101+
<div className={`${name}__title`}>{title}</div>
102+
103+
{confirmButtonText ? (
104+
<div className={`${name}__confirm`} onClick={handleConfirm}>
105+
{confirmButtonText}
106+
</div>
107+
) : null}
108+
</div>
109+
{header}
110+
111+
<div className={`${name}__main`}>
112+
{realColumns.map((item, idx) => (
113+
<div key={idx} className={`${name}-item__group`}>
114+
<PickerItem
115+
ref={(instance) => {
116+
setPickerItemRef(instance, idx);
117+
}}
118+
options={item}
119+
value={pickerValue[idx]}
120+
renderLabel={props.renderLabel}
121+
onPick={(context: any) => handlePick(context, idx)}
122+
/>
123+
</div>
124+
))}
125+
126+
<div className={`${name}__mask ${name}__mask--top`}></div>
127+
<div className={`${name}__mask ${name}__mask--bottom`}></div>
128+
<div className={`${name}__indicator`}></div>
129+
</div>
130+
</div>
66131
);
67132
};
68133

0 commit comments

Comments
 (0)