diff --git a/example/storybook-nativewind/src/components/Tooltip/Tooltip.tsx b/example/storybook-nativewind/src/components/Tooltip/Tooltip.tsx index 28a79ac09f..dee82fdb80 100644 --- a/example/storybook-nativewind/src/components/Tooltip/Tooltip.tsx +++ b/example/storybook-nativewind/src/components/Tooltip/Tooltip.tsx @@ -1,16 +1,4 @@ import React from 'react'; -import { - Center, - Text, - Avatar, - AvatarGroup, - AvatarFallbackText, - Box, - Heading, - VStack, - HStack, - Icon, -} from '@gluestack-ui/themed'; import { Tooltip, TooltipContent, TooltipText } from '@/components/ui/tooltip'; import { Button, ButtonText } from '@/components/ui/button'; import { Edit, Command } from 'lucide-react-native'; @@ -42,60 +30,18 @@ const TooltipBasic = ({ ); }; -const FigmaTooltipStory = ({ - showTooltip: _showTooltipProp = true, - _placement = 'bottom', - ...props -}: any) => { - 2; - return ( - { - return ( - - - - ); - }} - > - - Hello world! - - - ); -}; - TooltipBasic.description = 'This is a basic Tooltip component example. A tooltip is a popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.'; export default TooltipBasic; export { - FigmaTooltipStory, TooltipBasic, Tooltip, TooltipContent, TooltipText, - Center, Button, ButtonText, - Text, - Avatar, - AvatarGroup, - AvatarFallbackText, - Box, - Heading, Edit, - VStack, Command, - HStack, - Icon, }; diff --git a/example/storybook-nativewind/src/components/Tooltip/index.nw.stories.mdx b/example/storybook-nativewind/src/components/Tooltip/index.nw.stories.mdx index 0e225322c9..26b2c35ecb 100644 --- a/example/storybook-nativewind/src/components/Tooltip/index.nw.stories.mdx +++ b/example/storybook-nativewind/src/components/Tooltip/index.nw.stories.mdx @@ -7,15 +7,610 @@ pageTitle: Tooltip pageDescription: Whether you need to provide helpful hints to new users or display extra details for power users, the Tooltip component is a simple and effective way. -showHeader: false - -tag: coming soon +showHeader: true --- import { Meta } from '@storybook/addon-docs'; -# Tooltip +import { + Tooltip, + TooltipContent, + TooltipText, + Button, + ButtonText, + Avatar, + AvatarGroup, + AvatarFallbackText, + HStack, + Box, + Heading, + EditIcon, + Center, + VStack, + Icon +} from '../../core-components/nativewind'; +import { transformedCode } from '../../utils'; +import { + AppProvider, + CodePreview, + Table, + TableContainer, + Text, + InlineCode, + CollapsibleCode +} from '@gluestack/design-system'; +import Wrapper from '../../core-components/nativewind/Wrapper'; +; +import {Command} from 'lucide-react-native'; + +This is an illustration of **Tooltip** component. + +<> + { + return ( + + ); + }} + > + + Tooltip + + + `, + transformCode: (code) => { + return transformedCode(code); + }, + scope: { + Wrapper, + Tooltip, + TooltipContent, + TooltipText, + Center, + Button, + ButtonText, + }, + argsType: { + placement: { + control: 'select', + options: [ + 'top left', + 'top', + 'top right', + 'left top', + 'left', + 'left bottom', + 'bottom left', + 'bottom', + 'bottom right', + 'right top', + 'right', + 'right bottom', + ], + default: 'top', + }, + }, + }} + /> + + +
+ +## Installation + +### Step 1: Install the following dependencies: + +```bash + +npm i @gluestack-ui/tooltip + +``` + +### Step 2: Copy and paste the following code into your project. + + + +```jsx +%%-- File: core-components/nativewind/tooltip/index.tsx --%% +``` + + + +### Step 3: Update the import paths to match your project setup. + +## API Reference + +To use this component in your project, include the following import statement in your file. + +```jsx +import { Tooltip } from '@/components/ui/tooltip'; +``` + +```jsx +export default () => ( + + + + + +); +``` +### Component Props + +This section provides a comprehensive reference list for the component props, detailing descriptions, properties, types, and default behavior for easy project integration. + +#### Tooltip + +It inherits all the properties of React Native's [View](https://reactnative.dev/docs/view) component. + +<> + + + + + + Prop + + + Type + + + Default + + + Description + + + + + + + + isOpen + + + + boolean + + + false + + + {`Whether the tooltip is opened. Useful for controlling the open state.`} + + + + + + isDisabled + + + + boolean + + + false + + + {`Whether the tooltip is disabled.`} + + + + + + defaultIsOpen + + + + boolean + + + false + + + {`If true, the popover will be opened by default.`} + + + + + + onOpen + + + + {'() => void'} + + + true + + + {`This function will be invoked when the tooltip is opened.`} + + + + + + onClose + + + + {'() => void'} + + + - + + + {`This function will be invoked when tooltip is closed. It will also be called when the user attempts to close the tooltip via Escape key or backdrop press.`} + + + + + + openDelay + + + + {'number'} + + + 0 + + + {`Duration in ms to wait till displaying the tooltip.`} + + + + + + closeDelay + + + + {'number'} + + + 0 + + + {`Duration in ms to wait till hiding the tooltip.`} + + + + + + placement + + + + {`"bottom" | "top" | "right" | "left" | "top left" | "top right" | "bottom left" | "bottom right" | "right top" | "right bottom" | "left top" | "left bottom"`} + + + bottom left + + + {`Tooltip placement`} + + + + + + children + + + + any + + + - + + + + The content to display inside the tooltip. + + + + + + + closeOnClick + + + + boolean + + + true + + + + Whether tooltip should be closed on Trigger click. + + + + + + + trigger + + + + {`() => any`} + + + - + + + {`Function that returns a React Element. This element will be used as a Trigger for the tooltip.`} + + + + + + offset + + + + number + + + 10 + + + + Distance between the trigger and the tooltip. + + + + + + + crossOffset + + + + number + + + - + + + + The additional offset applied along the cross axis between the + element and its trigger element. + + + + + + + shouldOverlapWithTrigger + + + + boolean + + + false + + + + Determines whether tooltip content should overlap with the + trigger. + + + + + + + shouldFlip + + + + boolean + + + true + + + + Whether the element should flip its orientation (e.g. top to + bottom or left to right) when there is insufficient room for it to + render completely. + + + + + + + closeOnOverlayClick + + + + boolean + + + true + + + {`Closes tooltip when clicked outside.`} + + + +
+
+ + +#### TooltipText + +Contains all text related layout style props and actions. It inherits all the properties of React Native's Text component. + +#### TooltipContent + +Contains all backdrop related layout style props and actions. It inherits all the properties of React Native's [View](https://reactnative.dev/docs/view) component. + +### Accessibility + +We have outlined the various features that ensure the Tooltip component is accessible to all users, including those with disabilities. These features help ensure that your application is inclusive and meets accessibility standards. It adheres to the [ WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/). + +### Examples + +#### Tooltip with Heading + +A tooltip component with an avatar is a user interface element that displays a small pop-up box of additional information when the user hovers over or interacts with an avatar or an icon. + + + + + { + return ( + + + 3 + + ) + }} + > + + + View all members of this channel +
+ Includes John, Sarah, Mike, Emily + and David +
+
+
+
+ + Sandeep Srivastva + + + Arjun Kapoor + + + Ritik Sharma + +
+ + ); + } + `, + transformCode: (code) => { + return transformedCode(code, 'function', 'App'); + }, + scope: { + Avatar, + AvatarGroup, + AvatarFallbackText, + Wrapper, + HStack, + Tooltip, + TooltipContent, + TooltipText, + Text, + Box, + Heading, + VStack, + Center, + }, + argsType: {}, + }} + /> +
+ +#### Tooltip with Icon + +A tooltip component with an icon is a user interface element that provides contextual information or explanatory text when the user hovers over or interacts with an icon. + + + + { + return ( + + + + ) + }} + > + + + New message + + + + + + N + + + + + + + ); + } + `, + transformCode: (code) => { + return transformedCode(code, 'function', 'App'); + }, + scope: { + Avatar, + AvatarFallbackText, + Wrapper, + HStack, + Tooltip, + TooltipContent, + TooltipText, + Text, + Box, + Heading, + EditIcon, + Command, + Icon, + }, + argsType: {}, + }} + /> + + + + + -Coming Soon! \ No newline at end of file diff --git a/example/storybook-nativewind/src/components/Tooltip/index.themed.stories.mdx b/example/storybook-nativewind/src/components/Tooltip/index.themed.stories.mdx index 5d59c00fd2..b0578ea15b 100644 --- a/example/storybook-nativewind/src/components/Tooltip/index.themed.stories.mdx +++ b/example/storybook-nativewind/src/components/Tooltip/index.themed.stories.mdx @@ -613,7 +613,7 @@ A tooltip component with an icon is a user interface element that provides conte New message - + diff --git a/example/storybook-nativewind/src/core-components/nativewind/tooltip/index.tsx b/example/storybook-nativewind/src/core-components/nativewind/tooltip/index.tsx index 6eaf7e6d11..e90006e472 100644 --- a/example/storybook-nativewind/src/core-components/nativewind/tooltip/index.tsx +++ b/example/storybook-nativewind/src/core-components/nativewind/tooltip/index.tsx @@ -1,94 +1,43 @@ +import React, { useEffect } from 'react'; import { createTooltip } from '@gluestack-ui/tooltip'; +import { View, Text, Platform } from 'react-native'; import { - AnimatePresence, - AnimatedView, -} from '@gluestack-style/animation-resolver'; + tva, + withStyleContext, + withStyleContextAndStates, + VariantProps, +} from '@gluestack-ui/nativewind-utils'; +import Animated, { + Easing, + useSharedValue, + withSpring, + withTiming, +} from 'react-native-reanimated'; import { View, Text } from 'react-native'; import { tva } from '@gluestack-ui/nativewind-utils/tva'; import { withStyleContext } from '@gluestack-ui/nativewind-utils/withStyleContext'; import React from 'react'; export const UITooltip = createTooltip({ - Root: withStyleContext(View), - Content: AnimatedView, + Root: + Platform.OS === 'web' + ? withStyleContext(View) + : withStyleContextAndStates(View), + Content: Animated.View, Text: Text, - //@ts-ignore - AnimatePresence: AnimatePresence, + AnimatePresence: React.Fragment, // TODO: Add support for this }); const tooltipStyle = tva({ base: 'w-full h-full web:pointer-events-none', }); -// const StyledRoot = styled( -// View, -// { -// width: '$full', -// height: '$full', -// _web: { -// pointerEvents: 'none', -// }, -// }, -// {} -// ); - const tooltipContentStyle = tva({ - base: 'py-1 px-3 rounded-sm bg-background-900 web:pointer-events-auto shadow', + base: 'py-1 px-3 rounded-sm bg-background-900 web:pointer-events-auto', }); -// const StyledContent = styled( -// AnimatedView, -// { -// ':initial': { -// opacity: 0, -// scale: 0.5, -// }, - -// ':animate': { -// opacity: 1, -// scale: 1, -// }, - -// ':exit': { -// opacity: 0, -// scale: 0.5, -// }, - -// ':transition': { -// type: 'spring', -// damping: 18, -// stiffness: 250, -// opacity: { -// type: 'timing', -// duration: 250, -// }, -// }, - -// 'py': '$1', -// 'px': '$3', -// 'borderRadius': '$sm', -// 'bg': '$background900', - -// '_text': { -// fontSize: '$xs', -// color: '$text50', -// }, - -// '_web': { -// pointerEvents: 'auto', -// }, - -// 'defaultProps': { -// hardShadow: '2', -// }, -// }, -// { -// descendantStyle: ['_text'], -// } -// ); - const tooltipTextStyle = tva({ - base: 'font-normal tracking-normal text-red-400 web:select-none text-xs text-text-50', + base: 'font-normal tracking-normal text-red-400 web:select-none text-xs text-typography-50', variants: { isTruncated: { @@ -96,159 +45,79 @@ const tooltipTextStyle = tva({ props: 'line-clamp-1 truncate', }, }, - }, - bold: { - true: 'font-bold', - }, - underline: { - true: 'underline', - }, - strikeThrough: { - true: 'line-through', - }, - size: { - '2xs': 'text-2xs', - 'xs': 'text-xs', - 'sm': 'text-sm', - 'md': 'text-base', - 'lg': 'text-lg', - 'xl': 'text-xl', - '2xl': 'text-2xl', - '3xl': 'text-3xl', - '4xl': 'text-4xl', - '5xl': 'text-5xl', - '6xl': 'text-6xl', - }, - sub: { - true: 'text-xs', - }, - italic: { - true: 'italic', - }, - highlight: { - true: 'bg-yellow-500', + bold: { + true: 'font-bold', + }, + underline: { + true: 'underline', + }, + strikeThrough: { + true: 'line-through', + }, + size: { + '2xs': 'text-2xs', + 'xs': 'text-xs', + 'sm': 'text-sm', + 'md': 'text-base', + 'lg': 'text-lg', + 'xl': 'text-xl', + '2xl': 'text-2xl', + '3xl': 'text-3xl', + '4xl': 'text-4xl', + '5xl': 'text-5xl', + '6xl': 'text-6xl', + }, + sub: { + true: 'text-xs', + }, + italic: { + true: 'italic', + }, + highlight: { + true: 'bg-yellow-500', + }, }, }); -// const StyledText = styled( -// Text, -// { -// fontWeight: '$normal', -// fontStyle: 'normal', -// letterSpacing: '$md', - -// variants: { -// isTruncated: { -// true: { -// props: { -// // @ts-ignore -// numberOfLines: 1, -// ellipsizeMode: 'tail', -// }, -// }, -// }, -// bold: { -// true: { -// fontWeight: '$bold', -// }, -// }, -// underline: { -// true: { -// textDecorationLine: 'underline', -// }, -// }, -// strikeThrough: { -// true: { -// textDecorationLine: 'line-through', -// }, -// }, -// size: { -// '2xs': { -// fontSize: '$2xs', -// }, -// 'xs': { -// fontSize: '$xs', -// }, - -// 'sm': { -// fontSize: '$sm', -// }, - -// 'md': { -// fontSize: '$md', -// }, - -// 'lg': { -// fontSize: '$lg', -// }, - -// 'xl': { -// fontSize: '$xl', -// }, - -// '2xl': { -// fontSize: '$2xl', -// }, - -// '3xl': { -// fontSize: '$3xl', -// }, - -// '4xl': { -// fontSize: '$4xl', -// }, - -// '5xl': { -// fontSize: '$5xl', -// }, +type ITooltipProps = React.ComponentProps & + VariantProps; +type ITooltipContentProps = React.ComponentProps & + VariantProps; +type ITooltipTextProps = React.ComponentProps & + VariantProps; -// '6xl': { -// fontSize: '$6xl', -// }, -// }, -// sub: { -// true: { -// fontSize: '$xs', -// }, -// }, -// italic: { -// true: { -// fontStyle: 'italic', -// }, -// }, -// highlight: { -// true: { -// bg: '$yellow500', -// }, -// }, -// }, - -// defaultProps: { -// size: 'md', -// }, -// color: '$red400', -// fontFamily: '$body', -// _web: { -// userSelect: 'none', -// }, -// }, -// { -// ancestorStyle: ['_text'], -// } -// ); - -export const Tooltip = React.forwardRef(({ className, ...props }: any, ref) => { - return ( - - ); -}); +export const Tooltip = React.forwardRef( + ({ className, ...props }: { className?: string } & ITooltipProps, ref) => { + return ( + + ); + } +); export const TooltipContent = React.forwardRef( - ({ className, ...props }: any, ref) => { + ( + { className, ...props }: { className?: string } & ITooltipContentProps, + ref + ) => { + const opacity = useSharedValue(0); + const scale = useSharedValue(0.5); + useEffect(() => { + opacity.value = withTiming(1, { + easing: Easing.linear, + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + useEffect(() => { + scale.value = withSpring(1, { + damping: 18, + stiffness: 250, + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); return ( ); } ); export const TooltipText = React.forwardRef( - ({ className, size = 'md', ...props }: any, ref) => { + ( + { + className, + size = 'md', + ...props + }: { className?: string } & ITooltipTextProps, + ref + ) => { return ( ); }