From 463a947e9c6c5e40476525e9226749e14c4520ba Mon Sep 17 00:00:00 2001 From: Shane Stratton Date: Mon, 8 Nov 2021 15:00:32 -0500 Subject: [PATCH 1/3] ui/Tooltip - basic implementation of tooltip overlay --- packages/ui/src/components/Button.tsx | 103 ++++--- .../ui/src/components/ReviewButtonBar.tsx | 3 + .../ui/src/components/Tooltip.stories.tsx | 93 ++++++ packages/ui/src/components/Tooltip.tsx | 275 ++++++++++++++++++ .../__fixtures__/generateReviewItem.ts | 11 + 5 files changed, 439 insertions(+), 46 deletions(-) create mode 100644 packages/ui/src/components/Tooltip.stories.tsx create mode 100644 packages/ui/src/components/Tooltip.tsx diff --git a/packages/ui/src/components/Button.tsx b/packages/ui/src/components/Button.tsx index d303e6786..aa43bcedf 100644 --- a/packages/ui/src/components/Button.tsx +++ b/packages/ui/src/components/Button.tsx @@ -19,6 +19,8 @@ import usePrevious from "./hooks/usePrevious"; import Hoverable from "./Hoverable"; import Icon from "./Icon"; import { IconName, IconPosition } from "./IconShared"; +import Tooltip from "./Tooltip"; + export type ButtonPendingActivationState = "hover" | "pressed" | null; @@ -50,6 +52,7 @@ export type ButtonProps = ButtonContents & numberOfLines?: number; ellipsizeMode?: TextProps["ellipsizeMode"]; focusOnMount?: boolean; + tooltipText?: string; }; const pressedButtonOpacity = 0.2; @@ -196,7 +199,7 @@ const styles = StyleSheet.create({ }); export default React.memo(function Button(props: ButtonProps) { - const { onPendingInteractionStateDidChange, style } = props; + const { onPendingInteractionStateDidChange, style, tooltipText } = props; const ref = React.useRef(null); const href = "href" in props ? props.href : null; const onPress = "onPress" in props ? props.onPress : null; @@ -242,51 +245,59 @@ export default React.memo(function Button(props: ButtonProps) { }} > {(isHovered) => ( - { - isPressed.current = false; - dispatchPendingInteractionState(); - onPress(); - } - : () => { - Linking.openURL(href!).catch(() => { - Alert.alert( - "Couldn't open link", - `You may need to install an app to open this URL: ${href}`, - ); - }); - } - } - onPressIn={() => { - isPressed.current = true; - dispatchPendingInteractionState(); - }} - onPressOut={() => { - isPressed.current = false; - dispatchPendingInteractionState(); - }} - // @ts-ignore react-native-web adds this prop - delayPressOut={1} // HACK: When a press is completed, we handle onPressOut within onPress so that React batches all updates into a single re-render. - disabled={props.disabled} - // @ts-ignore react-native-web adds this prop. - href={href} - hitSlop={props.hitSlop} - style={[isSoloIcon && styles.soloIcon, style]} - > - {({ pressed }) => ( - - )} - + { + isPressed.current = false; + dispatchPendingInteractionState(); + onPress(); + } + : () => { + Linking.openURL(href!).catch(() => { + Alert.alert( + "Couldn't open link", + `You may need to install an app to open this URL: ${href}`, + ); + }); + } + } + onPressIn={() => { + isPressed.current = true; + dispatchPendingInteractionState(); + }} + onPressOut={() => { + isPressed.current = false; + dispatchPendingInteractionState(); + }} + // @ts-ignore react-native-web adds this prop + delayPressOut={1} // HACK: When a press is completed, we handle onPressOut within onPress so that React batches all updates into a single re-render. + disabled={props.disabled} + // @ts-ignore react-native-web adds this prop. + href={href} + hitSlop={props.hitSlop} + style={[isSoloIcon && styles.soloIcon, style]} + > + {({ pressed }) => ( + + {tooltipText && ()} + + + )} + )} ); diff --git a/packages/ui/src/components/ReviewButtonBar.tsx b/packages/ui/src/components/ReviewButtonBar.tsx index f35d0ea7d..64a73ba41 100644 --- a/packages/ui/src/components/ReviewButtonBar.tsx +++ b/packages/ui/src/components/ReviewButtonBar.tsx @@ -168,6 +168,7 @@ const ReviewButtonBar = React.memo(function ReviewButtonArea({ dispatchPendingMarkingInteraction(); }} hitSlop={firstButtonSlop} + tooltipText={"Shortcut: 1"} /> {spacer}