UNPKG

@td-design/react-native

Version:

react-native UI组件库

183 lines 4.91 kB
import React, { memo, useMemo, useReducer, useRef } from 'react'; import { Dimensions, Modal, Pressable } from 'react-native'; import Box from '../box'; import helpers from '../helpers'; import Text from '../text'; import getTooltipCoordinate from './getTooltipCoordinate'; import Triangle from './Triangle'; const { width: ScreenWidth, height: ScreenHeight } = Dimensions.get('window'); const { px } = helpers; const reducer = (prevState, action) => { switch (action.type) { case 'toggle': return { ...prevState, visible: !prevState.visible }; case 'computePosition': return { ...prevState, ...action.payload }; } }; const Tooltip = props => { const { content, withOverlay = true, withCaret = true, actionType = 'onPress', height = px(40), width = px(150), backgroundColor = '#617080', overlayColor = 'rgba(250, 250, 250, 0.70)', children, containerStyle, onClose } = props; const [{ visible, elementWidth, elementHeight, offsetX, offsetY }, dispatch] = useReducer(reducer, { visible: false, elementWidth: 0, elementHeight: 0, offsetX: 0, offsetY: 0 }); const boxRef = useRef(null); const handleLayout = e => { dispatch({ type: 'computePosition', payload: { elementWidth: e.nativeEvent.layout.width, elementHeight: e.nativeEvent.layout.height, offsetX: e.nativeEvent.layout.x, offsetY: e.nativeEvent.layout.y } }); }; const toggleTooltip = () => { if (boxRef.current) { boxRef.current.measureInWindow((pageOffsetX, pageOffsetY, width, height) => { dispatch({ type: 'computePosition', payload: { offsetX: pageOffsetX, offsetY: pageOffsetY, elementWidth: width, elementHeight: height } }); }); } if (visible) { onClose === null || onClose === void 0 ? void 0 : onClose(); } dispatch({ type: 'toggle' }); }; const Content = useMemo(() => { const { x, y } = getTooltipCoordinate(offsetX, offsetY, elementWidth, elementHeight, ScreenWidth, ScreenHeight, width, withCaret); const tooltipStyle = { position: 'absolute', left: x, width, height, backgroundColor, display: 'flex', alignItems: 'center', justifyContent: 'center', borderRadius: px(4) }; const pastCenterLine = offsetX > x; const pastMiddleLine = offsetY > y; if (pastMiddleLine) { tooltipStyle.top = y - height; } else { tooltipStyle.top = y; } return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Box, { style: { position: 'absolute', left: offsetX, top: offsetY, overflow: 'visible', width: elementWidth, height: elementHeight } }, children), /*#__PURE__*/React.createElement(Pointer, { withCaret, pastCenterLine, pastMiddleLine, offsetY, offsetX, elementHeight, elementWidth, backgroundColor }), /*#__PURE__*/React.createElement(Box, { style: [tooltipStyle, containerStyle] }, typeof content === 'string' ? /*#__PURE__*/React.createElement(Text, { variant: 'p1', color: "text_active" }, content) : content)); }, [offsetX, offsetY, elementWidth, elementHeight, ScreenWidth, ScreenHeight, width, withCaret, backgroundColor]); const pressableProps = { [actionType]: toggleTooltip }; return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Pressable, pressableProps, /*#__PURE__*/React.createElement(Box, { alignSelf: 'flex-start', ref: boxRef, onLayout: handleLayout }, children)), /*#__PURE__*/React.createElement(Modal, { animationType: "fade", visible: visible, transparent: true, onDismiss: onClose }, /*#__PURE__*/React.createElement(Pressable, { style: { backgroundColor: withOverlay ? overlayColor : 'transparent', flex: 1 }, onPress: toggleTooltip }, Content))); }; export default Tooltip; const Pointer = /*#__PURE__*/memo(_ref => { let { withCaret, pastCenterLine, pastMiddleLine, offsetY, offsetX, elementHeight, elementWidth, backgroundColor } = _ref; if (!withCaret) return null; return /*#__PURE__*/React.createElement(Box, { style: { position: 'absolute', top: pastMiddleLine ? offsetY - 13 : offsetY + elementHeight, left: pastCenterLine ? offsetX + elementWidth / 2 - 20 : offsetX + elementWidth / 2 } }, /*#__PURE__*/React.createElement(Triangle, { style: { borderBottomColor: backgroundColor }, isDown: pastMiddleLine })); }); //# sourceMappingURL=index.js.map