@fruits-chain/react-native-xiaoshu
Version:
🌈 React Native UI library
199 lines (184 loc) • 6.9 kB
JavaScript
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import groupBy from 'lodash/groupBy';
import omit from 'lodash/omit';
import React, { useMemo, useEffect, memo, useRef, useCallback } from 'react';
import { View, Text, ScrollView } from 'react-native';
import Cell from '../cell/cell';
import { useControllableValue, usePersistFn, useSafeHeight } from '../hooks';
import useState from '../hooks/useStateUpdate';
import IconSuccessOutline from '../icon/success';
import Locale from '../locale';
import Popup from '../popup/popup';
import PopupHeader from '../popup/popup-header';
import Theme from '../theme';
import StepSelectorLine from './line';
import { varCreator, styleCreator } from './style';
function StepSelector(_ref) {
let {
title,
safeAreaInsetTop,
round = true,
onPressClose,
request,
...resetProps
} = _ref;
const safeHeight = useSafeHeight({
top: safeAreaInsetTop
});
const locale = Locale.useLocale().StepSelector;
const TOKENS = Theme.useThemeTokens();
const CV = Theme.createVar(TOKENS, varCreator);
const STYLES = Theme.createStyle(CV, styleCreator);
const requestPersistFn = usePersistFn(request);
const ScrollViewRef = useRef(null);
const [value, onChange] = useControllableValue(resetProps, {
defaultValue: []
});
const [state, setState] = useState({
index: 0,
selected: [],
loading: false,
responseData: []
});
const responseDataRef = useRef({});
const onPressRef = useRef(false);
const fetchOption = useCallback(async (parentId, index) => {
const c = responseDataRef.current[`${parentId}`];
if (c) {
return c;
} // 请求
const data = await requestPersistFn(parentId, index);
responseDataRef.current[`${parentId}`] = data;
return data;
}, [requestPersistFn]);
const optionScrollToTop = useCallback(() => {
ScrollViewRef.current.scrollTo({
x: 0,
y: 0,
animated: false
});
}, []);
useEffect(() => {
// 构建已选的数据
if (resetProps.visible) {
setState({
loading: true
});
const _value = [...value, null];
Promise.all(_value.map((_, index) => {
return fetchOption(value[index - 1] || null, index);
})).then(datas => {
const isEnd = !datas[datas.length - 1].options.length;
const __value = isEnd ? [...value] : _value;
const selected = __value.map((v, index) => {
const opts = datas[index].options; // eslint-disable-next-line max-nested-callbacks
const vIndex = opts.findIndex(op => op.value === v);
return opts[vIndex];
});
setState({
loading: false,
index: __value.length - 1,
responseData: datas,
selected: selected
});
if (datas[datas.length - 1].options.length) {
optionScrollToTop();
}
if (isEnd && onPressRef.current) {
onPressRef.current = false;
onChange(value, selected, true);
}
});
}
}, [resetProps.visible, fetchOption, value, optionScrollToTop, onChange]);
const {
placeholder,
options,
groupOption
} = useMemo(() => {
const d = state.responseData[state.index] || {
options: [],
placeholder: ''
};
const _groupOption = groupBy(d.options, item => item.index);
return {
placeholder: d.placeholder,
options: d.options,
groupOption: Object.keys(_groupOption).sort().map(key => {
return _groupOption[key];
})
};
}, [state.index, state.responseData]);
return /*#__PURE__*/React.createElement(Popup, _extends({}, omit(resetProps, ['value', 'defaultValue', 'onChange']), {
position: "bottom",
round: round,
safeAreaInsetBottom: true
}), /*#__PURE__*/React.createElement(View, {
style: {
height: safeHeight
}
}, /*#__PURE__*/React.createElement(PopupHeader, {
title: title || locale.title,
onClose: onPressClose
}), state.selected.length > 1 && state.selected.map((item, index) => {
return /*#__PURE__*/React.createElement(Cell, {
key: `${item === null || item === void 0 ? void 0 : item.value}`,
innerStyle: STYLES.selected_cell,
title: (item === null || item === void 0 ? void 0 : item.label) || state.responseData[index].placeholder,
titleExtra: /*#__PURE__*/React.createElement(StepSelectorLine, {
index: index,
total: state.selected.length,
active: !!(item !== null && item !== void 0 && item.label)
}),
titleTextStyle: [STYLES.selected_cell_title_text, index === state.index && item !== null && item !== void 0 && item.label ? STYLES.option_text_active : null],
isLink: true,
disabled: state.loading,
divider: index === state.selected.length - 1,
onPress: () => {
setState({
index
});
optionScrollToTop();
}
});
}), options.length && placeholder ? /*#__PURE__*/React.createElement(Cell, {
titleTextStyle: STYLES.placeholder_text,
title: placeholder,
divider: false
}) : null, /*#__PURE__*/React.createElement(ScrollView, {
bounces: false,
ref: ScrollViewRef
}, groupOption.map(group => {
return group.map((item, itemIndex) => {
const selected = state.selected[state.index];
const isActive = item.value === (selected === null || selected === void 0 ? void 0 : selected.value);
return /*#__PURE__*/React.createElement(Cell, {
key: `${item.value}`,
disabled: state.loading,
titleExtra: /*#__PURE__*/React.createElement(Text, {
style: STYLES.option_index_text
}, itemIndex === 0 ? item.index : null),
title: item.label,
titleTextStyle: isActive ? STYLES.option_text_active : null,
valueExtra: isActive ? /*#__PURE__*/React.createElement(IconSuccessOutline, {
color: CV.step_selector_active_color
}) : null,
divider: false,
onPress: () => {
// 根据当前的 index 处理数据
const sliceEnd = state.index;
const newValue = value.slice(0, sliceEnd);
const option = newValue.map((v, index) => {
const opts = state.responseData[index].options; // eslint-disable-next-line max-nested-callbacks
const vIndex = opts.findIndex(op => op.value === v);
return opts[vIndex];
});
onChange([...newValue, item.value], [...option, item]);
onPressRef.current = true;
}
});
});
}))));
}
export default /*#__PURE__*/memo(StepSelector);
//# sourceMappingURL=step-selector.js.map