@fruits-chain/react-native-xiaoshu
Version:
🌈 React Native UI library
201 lines (199 loc) • 6.86 kB
JavaScript
"use strict";
import { SuccessOutline } from '@fruits-chain/icons-react-native';
import groupBy from 'lodash/groupBy';
import isNil from 'lodash/isNil';
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.js";
import { useControllableValue, usePersistFn, useSafeHeight } from "../hooks/index.js";
import useState from "../hooks/useStateUpdate.js";
import Loading from "../loading/index.js";
import Locale from "../locale/index.js";
import Popup from "../popup/popup.js";
import PopupHeader from "../popup/popup-header.js";
import Theme from "../theme/index.js";
import StepSelectorLine from "./line.js";
import { varCreator, styleCreator } from "./style.js";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const defaultLoading = /*#__PURE__*/_jsx(Loading, {
vertical: true
});
function StepSelector({
theme,
title,
safeAreaInsetTop,
round = true,
onPressClose,
request,
loading = defaultLoading,
...resetProps
}) {
const safeHeight = useSafeHeight({
top: safeAreaInsetTop
});
const locale = Locale.useLocale().StepSelector;
const [CV, STYLES] = Theme.useStyle({
varCreator,
styleCreator,
theme
});
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], 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];
}).filter(v => !isNil(v));
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__*/_jsx(Popup, {
...omit(resetProps, ['value', 'defaultValue', 'onChange']),
position: "bottom",
round: round,
safeAreaInsetBottom: true,
children: /*#__PURE__*/_jsxs(View, {
style: {
height: safeHeight
},
children: [/*#__PURE__*/_jsx(PopupHeader, {
title: title ?? locale.title,
onClose: onPressClose
}), state.selected.map((item, index) => {
return /*#__PURE__*/_jsx(Cell, {
innerStyle: STYLES.selected_cell,
title: item?.label || state.responseData[index].placeholder,
titleExtra: /*#__PURE__*/_jsx(StepSelectorLine, {
index: index,
total: state.selected.length,
active: !!item?.label
}),
titleTextStyle: [STYLES.selected_cell_title_text, index === state.index && item?.label ? STYLES.option_text_active : null],
isLink: true,
disabled: state.loading,
divider: index === state.selected.length - 1,
onPress: () => {
setState({
index
});
optionScrollToTop();
}
}, `${item?.value}`);
}), options.length && placeholder ? /*#__PURE__*/_jsx(Cell, {
titleTextStyle: STYLES.placeholder_text,
title: placeholder,
divider: false
}) : null, state.loading && value.length === 0 ? loading : null, /*#__PURE__*/_jsx(ScrollView, {
bounces: false,
ref: ScrollViewRef,
children: groupOption.map(group => {
return group.map((item, itemIndex) => {
const selected = state.selected[state.index];
const isActive = item.value === selected?.value;
return /*#__PURE__*/_jsx(Cell, {
disabled: state.loading,
titleExtra: /*#__PURE__*/_jsx(Text, {
style: STYLES.option_index_text,
children: itemIndex === 0 ? item.index : null
}),
title: item.label,
titleTextStyle: isActive ? STYLES.option_text_active : null,
valueExtra: isActive ? /*#__PURE__*/_jsx(SuccessOutline, {
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;
}
}, `${item.value}`);
});
})
})]
})
});
}
export default /*#__PURE__*/memo(StepSelector);
//# sourceMappingURL=step-selector.js.map