UNPKG

@quidone/react-native-wheel-picker

Version:

Picker is a UI component for selecting an item from a list of options.

194 lines (191 loc) 5.58 kB
"use strict"; import React, { useCallback, useEffect, useMemo, useRef } from 'react'; import { Animated, Platform, StyleSheet, View } from 'react-native'; import PickerItemComponent from '../item/PickerItem'; import { ScrollContentOffsetContext } from '../contexts/ScrollContentOffsetContext'; import { PickerItemHeightContext } from '../contexts/PickerItemHeightContext'; import useValueEventsEffect from './hooks/useValueEventsEffect'; import useSyncScrollEffect from './hooks/useSyncScrollEffect'; import Overlay from '../overlay/Overlay'; import { calcPickerHeight, createFaces } from '../item/faces'; import PickerItemContainer from '../item/PickerItemContainer'; import { useBoolean } from '../../utils/react'; import { useInit, useStableCallback } from '@rozhkov/react-useful-hooks'; import List from '../list/List'; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; const defaultKeyExtractor = (_, index) => index.toString(); const defaultRenderItem = ({ item: { value, label }, itemTextStyle }) => /*#__PURE__*/_jsx(PickerItemComponent, { value: value, label: label, itemTextStyle: itemTextStyle }); const defaultRenderItemContainer = ({ key, ...props }) => /*#__PURE__*/_jsx(PickerItemContainer, { ...props }, key); const defaultRenderOverlay = props => /*#__PURE__*/_jsx(Overlay, { ...props }); const defaultRenderList = props => { return /*#__PURE__*/_jsx(List, { ...props }); }; export const useValueIndex = (data, value) => { return useMemo(() => { const index = data.findIndex(x => x.value === value); return index >= 0 ? index : 0; }, [data, value]); }; const Picker = ({ data, value, extraValues = [], width = 'auto', itemHeight = 48, visibleItemCount = 5, readOnly = false, enableScrollByTapOnItem, testID, onValueChanged, onValueChanging, keyExtractor = defaultKeyExtractor, renderItem = defaultRenderItem, renderItemContainer = defaultRenderItemContainer, renderOverlay = defaultRenderOverlay, renderList = defaultRenderList, style, itemTextStyle, overlayItemStyle, contentContainerStyle, _enableSyncScrollAfterScrollEnd = true, _onScrollStart, _onScrollEnd, ...restProps }) => { const valueIndex = useValueIndex(data, value); const initialIndex = useInit(() => valueIndex); const offsetY = useMemo(() => new Animated.Value(valueIndex * itemHeight), // eslint-disable-next-line react-hooks/exhaustive-deps [readOnly] // when scrollEnabled changes, the events stop coming. Re-creating ); const listRef = useRef(null); const touching = useBoolean(false); const [faces, pickerHeight] = useMemo(() => { const items = createFaces(itemHeight, visibleItemCount); const height = calcPickerHeight(items, itemHeight); return [items, height]; }, [itemHeight, visibleItemCount]); const renderPickerItem = useCallback(({ item, index, key }) => renderItemContainer({ listRef, key, item, index, faces, renderItem, itemTextStyle, enableScrollByTapOnItem, readOnly }), [enableScrollByTapOnItem, faces, itemTextStyle, readOnly, renderItem, renderItemContainer]); const { activeIndexRef, onScrollEnd: onScrollEndForValueEvents } = useValueEventsEffect({ data, valueIndex, itemHeight, offsetYAv: offsetY }, { onValueChanging, onValueChanged }); const { onScrollStart: onScrollStartForSyncScroll, onScrollEnd: onScrollEndForSyncScroll } = useSyncScrollEffect({ listRef, value, valueIndex, extraValues, activeIndexRef, touching: touching.value, enableSyncScrollAfterScrollEnd: _enableSyncScrollAfterScrollEnd }); const onScrollStart = useStableCallback(() => { onScrollStartForSyncScroll(); _onScrollStart?.(); }); const onScrollEnd = useStableCallback(() => { // consistency matters _onScrollEnd?.(); onScrollEndForValueEvents(); onScrollEndForSyncScroll(); }); // iOS can mount the picker list with a wrong initial contentOffset, so re-apply it after mount. // See https://github.com/quidone/react-native-wheel-picker/issues/67. useEffect(() => { if (Platform.OS === 'ios') { listRef.current?.scrollToIndex({ index: initialIndex, animated: false }); } }, []); // eslint-disable-line react-hooks/exhaustive-deps return /*#__PURE__*/_jsx(ScrollContentOffsetContext.Provider, { value: offsetY, children: /*#__PURE__*/_jsx(PickerItemHeightContext.Provider, { value: itemHeight, children: /*#__PURE__*/_jsxs(View, { testID: testID, style: [styles.root, style, { height: pickerHeight, width }], children: [renderList({ ...restProps, ref: listRef, data, initialIndex, itemHeight, pickerHeight, visibleItemCount, readOnly, keyExtractor, renderItem: renderPickerItem, scrollOffset: offsetY, onTouchStart: touching.setTrue, onTouchEnd: touching.setFalse, onTouchCancel: touching.setFalse, onScrollStart, onScrollEnd, contentContainerStyle }), renderOverlay && renderOverlay({ itemHeight, pickerWidth: width, pickerHeight, overlayItemStyle })] }) }) }); }; const styles = StyleSheet.create({ root: { justifyContent: 'center', alignItems: 'center' } }); export default Picker; //# sourceMappingURL=Picker.js.map