diff --git a/app/components/Community.tsx b/app/components/Community.tsx index bbecc2bc..9edc580e 100644 --- a/app/components/Community.tsx +++ b/app/components/Community.tsx @@ -1,3 +1,4 @@ +'use client' import Link from 'next/link' import { ArrowLineUpRight } from 'phosphor-react' import { useEffect, useState } from 'react' diff --git a/app/components/ComponentUI.tsx b/app/components/ComponentUI.tsx index d3fc2c24..58723073 100644 --- a/app/components/ComponentUI.tsx +++ b/app/components/ComponentUI.tsx @@ -1,3 +1,4 @@ +'use client' import Link from 'next/link' import { ArrowUpRight } from 'phosphor-react' import { routes } from '../../routes/routes' diff --git a/app/docs/components/tooltip/tooltip.mdx b/app/docs/components/tooltip/tooltip.mdx index e189534e..9acd21bc 100644 --- a/app/docs/components/tooltip/tooltip.mdx +++ b/app/docs/components/tooltip/tooltip.mdx @@ -1,13 +1,10 @@ import { DefaultTooltip, DefaultTooltipCode } from './variant/DefaultTooltip' -import { TooltipStyles, TooltipStylesCode } from './variant/TooltipStyles' import { TooltipWithLargeText, TooltipWithLargeTextCode } from './variant/TooltipWithLargeText' import { TooltipTriggering, TooltipTriggeringCode } from './variant/TooltipTriggering' import { TooltipPlacement, TooltipPlacementCode } from './variant/TooltipPlacement' import { tooltipDataApi } from './tooltipApi' - import CodePreview from '../../../components/CodePreview' - import ComponentApi from '../../../components/ComponentApi' ## Table of Contents @@ -22,36 +19,28 @@ Tooltips appear on hover over an element and help convey concise explanations, t -## Tooltip Styles - -The Keep React offers two distinct styles for tooltips: light and dark. To apply the dark style, simply use the style="dark" attribute when implementing the tooltip. By default, tooltips will adopt the dark style. This flexibility allows you to seamlessly integrate tooltips that align with your design theme. - - - - - ## Tooltip Placement -You can choose from four placement options: top, bottom, left, and right. This flexibility allows you to enhance user interactions by offering relevant information in a visually intuitive manner. To set the placement of a tooltip, use the placement prop with the desired value, such as `placement="top"`. +To set the placement of a tooltip, use the placement prop with the desired value, such as `placement="top"`. -## Tooltip Trigger +## Tooltip With Large Text -Tooltips within the Keep React can be triggered using two different methods: `hover` and `click`. You can choose the trigger that best suits your user experience and interaction design. By default, tooltips are triggered on `hover`, providing users with instant context when they hover over a specific element. Alternatively, you can opt for a `click` trigger. If you want to use the `click` trigger, simply include the `trigger` prop with the value `click` in your tooltip component. For example, `trigger="click"`. +Feel free to adjust the text content and other attributes as needed for your application's context. - - + + -## Tooltip With Large Text +## Tooltip Trigger -The tooltip's `content` prop contains longer text content, and the `title` and other attributes are set as previously specified. Feel free to adjust the text content and other attributes as needed for your application's context. +Tooltips within the Keep React can be triggered using three different methods: `hover`, `click` and `focus`. You can choose the trigger that best suits your user experience and interaction design. - - + + ## API Reference diff --git a/app/docs/components/tooltip/tooltipApi.ts b/app/docs/components/tooltip/tooltipApi.ts index 82f2517a..1838633e 100644 --- a/app/docs/components/tooltip/tooltipApi.ts +++ b/app/docs/components/tooltip/tooltipApi.ts @@ -1,58 +1,29 @@ export const tooltipDataApi = [ { id: 1, - propsName: 'title', - propsType: 'string', - propsDescription: 'Title of the tooltip.', - default: 'Tooltip Text', - }, - { - id: 2, - propsName: 'children', - propsType: 'ReactNode', - propsDescription: 'Child elements to trigger the tooltip.', - default: ' - +
+ + Tooltip + +

Tooltips - Title here

+
+
+
) } const DefaultTooltipCode = ` -"use client"; -import { Button,Tooltip } from "keep-react"; +'use client' +import { Tooltip } from 'keep-react' export const TooltipComponent = () => { return ( - - + + Tooltip + +

Tooltips - Title here

+
- ); + ) } + ` export { DefaultTooltip, DefaultTooltipCode } diff --git a/app/docs/components/tooltip/variant/TooltipPlacement.tsx b/app/docs/components/tooltip/variant/TooltipPlacement.tsx index e4580bf8..b0c7d3a8 100644 --- a/app/docs/components/tooltip/variant/TooltipPlacement.tsx +++ b/app/docs/components/tooltip/variant/TooltipPlacement.tsx @@ -1,79 +1,40 @@ 'use client' -import { Button, Tooltip } from '../../../../src' +import { Tooltip } from '../../../../src' const TooltipPlacement = () => { return ( -
- - - - - - - - - - - - +
+ {['top', 'bottom', 'left', 'right'].map((position) => ( + + Tooltip + +

Tooltips - Title here

+
+
+ ))}
) } const TooltipPlacementCode = ` -"use client"; -import { Button,Tooltip } from "keep-react"; +'use client' +import { Tooltip } from 'keep-react' export const TooltipComponent = () => { return ( <> - - - - - - - - - - - - + {['top', 'bottom', 'left', 'right'].map((position) => ( + + Tooltip + +

Tooltips - Title here

+
+
+ ))} - ); + ) } + ` export { TooltipPlacement, TooltipPlacementCode } diff --git a/app/docs/components/tooltip/variant/TooltipStyles.tsx b/app/docs/components/tooltip/variant/TooltipStyles.tsx deleted file mode 100644 index 7e990015..00000000 --- a/app/docs/components/tooltip/variant/TooltipStyles.tsx +++ /dev/null @@ -1,51 +0,0 @@ -'use client' -import { Button, Tooltip } from '../../../../src' - -const TooltipStyles = () => { - return ( -
- - - - - - -
- ) -} - -const TooltipStylesCode = ` -"use client"; -import { Tooltip,Button } from "keep-react"; - -export const TooltipComponent = () => { - return ( - <> - - - - - - - - ); -} -` - -export { TooltipStyles, TooltipStylesCode } diff --git a/app/docs/components/tooltip/variant/TooltipTriggering.tsx b/app/docs/components/tooltip/variant/TooltipTriggering.tsx index 8f8ab546..1f465f3a 100644 --- a/app/docs/components/tooltip/variant/TooltipTriggering.tsx +++ b/app/docs/components/tooltip/variant/TooltipTriggering.tsx @@ -1,50 +1,38 @@ 'use client' -import { Button, Tooltip } from '../../../../src' +import { Tooltip } from '../../../../src' const TooltipTriggering = () => { return ( -
- - - - - - +
+ {['click', 'hover', 'focus'].map((trigger) => ( + + {trigger} + +

Tooltips - Title here

+
+
+ ))}
) } const TooltipTriggeringCode = ` -"use client"; -import {Tooltip,Button } from "keep-react"; +'use client' +import { Tooltip } from 'keep-react' export const TooltipComponent = () => { return ( <> - - - - - - + {['click', 'hover', 'focus'].map((trigger) => ( + + {trigger} + +

Tooltips - Title here

+
+
+ ))} - ); + ) } ` diff --git a/app/docs/components/tooltip/variant/TooltipWithLargeText.tsx b/app/docs/components/tooltip/variant/TooltipWithLargeText.tsx index a74a3bd5..2939defd 100644 --- a/app/docs/components/tooltip/variant/TooltipWithLargeText.tsx +++ b/app/docs/components/tooltip/variant/TooltipWithLargeText.tsx @@ -1,65 +1,40 @@ 'use client' -import { Button, Tooltip } from '../../../../src' +import { Tooltip } from '../../../../src' const TooltipWithLargeText = () => { return ( -
- - - - - +
+ + Tooltip + +

Tooltips - Title here

+

+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. +

+
) } const TooltipWithLargeTextCode = ` -"use client"; -import { Tooltip,Button } from "keep-react"; +'use client' +import { Tooltip } from 'keep-react' export const TooltipComponent = () => { return ( - <> - - - - - - - - ); + + Tooltip + +

Tooltips - Title here

+

+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. +

+
+
+ ) } + ` export { TooltipWithLargeText, TooltipWithLargeTextCode } diff --git a/app/docs/layout.tsx b/app/docs/layout.tsx index b3e8dacd..ca1d3184 100644 --- a/app/docs/layout.tsx +++ b/app/docs/layout.tsx @@ -139,7 +139,6 @@ const DocsLayout = ({ children }: { children: ReactNode }) => { - diff --git a/app/layout.tsx b/app/layout.tsx index 49da5de3..ce5bd343 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -20,7 +20,7 @@ export const metadata: Metadata = { export default function RootLayout({ children }: { children: ReactNode }) { return ( - + diff --git a/app/new-components/Tooltip/Action.tsx b/app/new-components/Tooltip/Action.tsx new file mode 100644 index 00000000..28443d40 --- /dev/null +++ b/app/new-components/Tooltip/Action.tsx @@ -0,0 +1,19 @@ +import { HTMLAttributes, forwardRef } from 'react' +import { cn } from '~/app/src/helpers/cn' +import { useTooltipContext } from './Context' + +export const Action = forwardRef>( + ({ children, className }, ref) => { + const { refs, getReferenceProps } = useTooltipContext() + return ( + + ) + }, +) + +Action.displayName = 'Tooltip.Action' diff --git a/app/new-components/Tooltip/Content.tsx b/app/new-components/Tooltip/Content.tsx new file mode 100644 index 00000000..66661257 --- /dev/null +++ b/app/new-components/Tooltip/Content.tsx @@ -0,0 +1,53 @@ +'use client' +import { FloatingArrow } from '@floating-ui/react' +import { HTMLAttributes, ReactNode, Ref, forwardRef } from 'react' +import { cn } from '~/app/src/helpers/cn' +import { useTooltipContext } from './Context' + +interface floatingArrow extends HTMLAttributes { + width?: number + height?: number + tipRadius?: number + staticOffset?: number | string | null + d?: string + fill?: string + stroke?: string + strokeWidth?: number + children?: ReactNode + className?: string +} + +export const Content = forwardRef( + ( + { children, className, width, height, tipRadius, staticOffset, fill = '#fff', stroke, strokeWidth, d, ...props }, + ref: Ref, + ) => { + const { refs, floatingStyles, arrowRef, context, getFloatingProps, isOpen } = useTooltipContext() + return ( + isOpen && ( +
+ + {children} +
+ ) + ) + }, +) + +Content.displayName = 'Tooltip.Content' diff --git a/app/new-components/Tooltip/Context.tsx b/app/new-components/Tooltip/Context.tsx new file mode 100644 index 00000000..2526482b --- /dev/null +++ b/app/new-components/Tooltip/Context.tsx @@ -0,0 +1,71 @@ +import { + Placement, + arrow, + autoPlacement, + offset, + safePolygon, + useClick, + useDismiss, + useFloating, + useFocus, + useHover, + useInteractions, + useRole, +} from '@floating-ui/react' +import { createContext, useContext, useMemo, useRef, useState } from 'react' + +export interface TooltipOptions { + initialOpen?: boolean + placement?: Placement + trigger?: 'hover' | 'focus' | 'click' +} + +export function useTooltip({ initialOpen = false, placement = 'top', trigger = 'hover' }: TooltipOptions) { + const arrowRef = useRef(null) + const [isOpen, setIsOpen] = useState(initialOpen) + + const data = useFloating({ + placement: placement, + open: isOpen, + onOpenChange: setIsOpen, + middleware: [ + arrow({ + element: arrowRef, + }), + offset(9 + 2), + autoPlacement({ + alignment: 'start', + allowedPlacements: ['top', 'left', 'bottom', 'right'], + }), + ], + }) + + const context = data.context + + const hover = useHover(context, { + enabled: trigger === 'hover', + handleClose: safePolygon(), + }) + const focus = useFocus(context, { enabled: trigger === 'focus' }) + const click = useClick(context, { enabled: trigger === 'click' }) + const dismiss = useDismiss(context) + const role = useRole(context, { role: 'tooltip' }) + + const interactions = useInteractions([focus, click, hover, role, dismiss]) + + return useMemo(() => ({ ...interactions, ...data, context, isOpen, arrowRef }), [interactions, data, isOpen, context]) +} + +type ContextType = ReturnType | null + +export const TooltipContext = createContext(null) + +export const useTooltipContext = () => { + const context = useContext(TooltipContext) + + if (context == null) { + throw new Error('Tooltip components must be wrapped in ') + } + + return context +} diff --git a/app/new-components/Tooltip/Tooltip.tsx b/app/new-components/Tooltip/Tooltip.tsx new file mode 100644 index 00000000..af8385c4 --- /dev/null +++ b/app/new-components/Tooltip/Tooltip.tsx @@ -0,0 +1,21 @@ +'use client' +import { ReactNode } from 'react' +import { Action } from './Action' +import { Content } from './Content' +import { TooltipContext, TooltipOptions, useTooltip } from './Context' + +const TooltipComponent = ({ + children, + initialOpen, + ...restOptions +}: { + children: ReactNode +} & TooltipOptions) => { + const tooltip = useTooltip({ initialOpen, ...restOptions }) + return {children} +} + +export const Tooltip = Object.assign(TooltipComponent, { + Action, + Content, +}) diff --git a/app/new-components/Tooltip/index.tsx b/app/new-components/Tooltip/index.tsx new file mode 100644 index 00000000..ba15f407 --- /dev/null +++ b/app/new-components/Tooltip/index.tsx @@ -0,0 +1 @@ +export * from './Tooltip' diff --git a/app/new-components/page.tsx b/app/new-components/page.tsx new file mode 100644 index 00000000..93ebce62 --- /dev/null +++ b/app/new-components/page.tsx @@ -0,0 +1,47 @@ +'use client' +import { Tooltip } from './Tooltip' + +const Components = () => { + return ( +
+
+

New Component

+ +
+ + Tooltip + +

Tooltips - Title here

+
+
+ + Tooltip + +

Tooltips - Title here

+
+
+ + Tooltip + +

Tooltips - Title here

+

+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. +

+
+
+ + Tooltip + +

Tooltips - Title here

+

+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. +

+
+
+
+
+
+ ) +} + +export default Components diff --git a/app/page.tsx b/app/page.tsx index 4e7480f2..57bbd24e 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,4 +1,3 @@ -'use client' import Community from './components/Community' import ComponentUI from './components/ComponentUI' import Faq from './components/Faq' diff --git a/app/src/components/Chart/AreaChart.tsx b/app/src/components/Chart/AreaChart.tsx index 52bbd4bf..c655f522 100644 --- a/app/src/components/Chart/AreaChart.tsx +++ b/app/src/components/Chart/AreaChart.tsx @@ -100,7 +100,6 @@ export const AreaChart: FC = ({ {showGridLine && } - {showTooltip && } />} {secondaryDataKey && ( ): ReactElement | null => { @@ -13,22 +11,26 @@ export const CustomTooltip = ({ active, payload }: TooltipProps {payload.length > 1 ? ( - - - +
+ + {payload[0].name} : {payload[0].value} + + + {payload[1].name} : {payload[1].value} + +
) : ( - - - +
+ {payload[0].value} +
)} ) diff --git a/app/src/components/Tooltip/Action.tsx b/app/src/components/Tooltip/Action.tsx new file mode 100644 index 00000000..9a8388bc --- /dev/null +++ b/app/src/components/Tooltip/Action.tsx @@ -0,0 +1,20 @@ +'use client' +import { HTMLAttributes, forwardRef } from 'react' +import { cn } from '../../helpers/cn' +import { useTooltipContext } from './Context' + +export const Action = forwardRef>( + ({ children, className }, ref) => { + const { refs, getReferenceProps } = useTooltipContext() + return ( + + ) + }, +) + +Action.displayName = 'Tooltip.Action' diff --git a/app/src/components/Tooltip/Content.tsx b/app/src/components/Tooltip/Content.tsx new file mode 100644 index 00000000..98bbe214 --- /dev/null +++ b/app/src/components/Tooltip/Content.tsx @@ -0,0 +1,53 @@ +'use client' +import { FloatingArrow } from '@floating-ui/react' +import { HTMLAttributes, ReactNode, Ref, forwardRef } from 'react' +import { cn } from '../../helpers/cn' +import { useTooltipContext } from './Context' + +interface floatingArrow extends HTMLAttributes { + width?: number + height?: number + tipRadius?: number + staticOffset?: number | string | null + d?: string + fill?: string + stroke?: string + strokeWidth?: number + children?: ReactNode + className?: string +} + +export const Content = forwardRef( + ( + { children, className, width, height, tipRadius, staticOffset, fill = '#1C222B', stroke, strokeWidth, d, ...props }, + ref: Ref, + ) => { + const { refs, floatingStyles, arrowRef, context, getFloatingProps, isOpen } = useTooltipContext() + return ( + isOpen && ( +
+ + {children} +
+ ) + ) + }, +) + +Content.displayName = 'Tooltip.Content' diff --git a/app/src/components/Tooltip/Context.tsx b/app/src/components/Tooltip/Context.tsx new file mode 100644 index 00000000..2526482b --- /dev/null +++ b/app/src/components/Tooltip/Context.tsx @@ -0,0 +1,71 @@ +import { + Placement, + arrow, + autoPlacement, + offset, + safePolygon, + useClick, + useDismiss, + useFloating, + useFocus, + useHover, + useInteractions, + useRole, +} from '@floating-ui/react' +import { createContext, useContext, useMemo, useRef, useState } from 'react' + +export interface TooltipOptions { + initialOpen?: boolean + placement?: Placement + trigger?: 'hover' | 'focus' | 'click' +} + +export function useTooltip({ initialOpen = false, placement = 'top', trigger = 'hover' }: TooltipOptions) { + const arrowRef = useRef(null) + const [isOpen, setIsOpen] = useState(initialOpen) + + const data = useFloating({ + placement: placement, + open: isOpen, + onOpenChange: setIsOpen, + middleware: [ + arrow({ + element: arrowRef, + }), + offset(9 + 2), + autoPlacement({ + alignment: 'start', + allowedPlacements: ['top', 'left', 'bottom', 'right'], + }), + ], + }) + + const context = data.context + + const hover = useHover(context, { + enabled: trigger === 'hover', + handleClose: safePolygon(), + }) + const focus = useFocus(context, { enabled: trigger === 'focus' }) + const click = useClick(context, { enabled: trigger === 'click' }) + const dismiss = useDismiss(context) + const role = useRole(context, { role: 'tooltip' }) + + const interactions = useInteractions([focus, click, hover, role, dismiss]) + + return useMemo(() => ({ ...interactions, ...data, context, isOpen, arrowRef }), [interactions, data, isOpen, context]) +} + +type ContextType = ReturnType | null + +export const TooltipContext = createContext(null) + +export const useTooltipContext = () => { + const context = useContext(TooltipContext) + + if (context == null) { + throw new Error('Tooltip components must be wrapped in ') + } + + return context +} diff --git a/app/src/components/Tooltip/Tooltip.tsx b/app/src/components/Tooltip/Tooltip.tsx new file mode 100644 index 00000000..af8385c4 --- /dev/null +++ b/app/src/components/Tooltip/Tooltip.tsx @@ -0,0 +1,21 @@ +'use client' +import { ReactNode } from 'react' +import { Action } from './Action' +import { Content } from './Content' +import { TooltipContext, TooltipOptions, useTooltip } from './Context' + +const TooltipComponent = ({ + children, + initialOpen, + ...restOptions +}: { + children: ReactNode +} & TooltipOptions) => { + const tooltip = useTooltip({ initialOpen, ...restOptions }) + return {children} +} + +export const Tooltip = Object.assign(TooltipComponent, { + Action, + Content, +}) diff --git a/app/src/components/Tooltip/index.tsx b/app/src/components/Tooltip/index.tsx index 30e160d8..ba15f407 100644 --- a/app/src/components/Tooltip/index.tsx +++ b/app/src/components/Tooltip/index.tsx @@ -1,100 +1 @@ -import type { Placement } from '@floating-ui/core' -import type { FC, ReactNode } from 'react' -import { excludeClassName } from '../../helpers/exclude' -import { Floating } from '../Floating' -import { tooltipTheme } from './theme' - -/** - * Props for the Tooltip component. - * @interface TooltipProps - */ -export interface TooltipProps { - /** - * The title of the tooltip. - * @type {string} - * @default '' - */ - title?: string - - /** - * children of the tooltip. - * @type {ReactNode} - * @default '' - */ - children?: ReactNode - - /** - * The content of the tooltip. - * @type {ReactNode} - * @default '' - */ - content: ReactNode - - /** - * The placement of the tooltip. - * @type {'auto' | Placement} - * @default 'auto' - */ - placement?: 'auto' | Placement - - /** - * The trigger event for the tooltip. - * @type {'hover' | 'click'} - * @default 'hover' - */ - trigger?: 'hover' | 'click' - - /** - * The style of the tooltip. - * @type {'dark' | 'light' | 'auto'} - * @default 'dark' - */ - style?: 'dark' | 'light' | 'auto' - - /** - * The animation duration of the tooltip. - * @type {false | `duration-${number}`} - * @default 'duration-300' - */ - animation?: false | `duration-${number}` - - /** - * Whether to show the arrow of the tooltip. - * @type {boolean} - * @default true - */ - arrow?: boolean -} - -/** - * @see https://floating-ui.com/docs/react-dom-interactions - */ -export const Tooltip: FC = ({ - animation = 'duration-300', - arrow = true, - children, - title, - content, - placement = 'top', - style = 'dark', - trigger = 'hover', - ...props -}) => { - const theme = tooltipTheme - const theirProps = excludeClassName(props) - - return ( - - {children} - - ) -} +export * from './Tooltip' diff --git a/app/src/components/Tooltip/theme.ts b/app/src/components/Tooltip/theme.ts deleted file mode 100644 index 45489b2e..00000000 --- a/app/src/components/Tooltip/theme.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { keepFloatingTheme } from '../Floating' - -export const tooltipTheme: keepFloatingTheme = { - target: 'w-fit', - base: 'absolute inline-block rounded-xl py-2 px-3 shadow-small max-w-[300px] z-50', - animation: 'transition-opacity', - hidden: 'invisible opacity-0', - style: { - dark: 'bg-metal-800 text-metal-50', - light: 'bg-metal-100 text-metal-600', - auto: 'bg-metal-100 text-metal-600', - }, - title: 'relative z-20 pb-1 text-body-5 font-semibold', - content: 'relative z-20 text-body-5 font-medium', - arrow: { - base: 'absolute z-10 h-2 w-2 rotate-45', - style: { - dark: 'bg-metal-800', - light: '!bg-metal-100', - auto: 'bg-metal-100', - }, - placement: '-4px', - }, -} diff --git a/public/images/card.jpg b/public/images/card.jpg deleted file mode 100644 index 56e9e63a..00000000 Binary files a/public/images/card.jpg and /dev/null differ diff --git a/public/images/hero.svg b/public/images/hero.svg deleted file mode 100644 index c226b8c1..00000000 --- a/public/images/hero.svg +++ /dev/null @@ -1,350 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -