@td-design/react-native
Version:
react-native UI组件库
183 lines • 4.91 kB
JavaScript
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