Skip to content

Commit

Permalink
feat: add hover card
Browse files Browse the repository at this point in the history
  • Loading branch information
ht-lovrozagar committed Aug 21, 2024
1 parent 8994ce8 commit be9718a
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 14 deletions.
2 changes: 1 addition & 1 deletion app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const App = () => {
<PopoverTrigger>Trigger</PopoverTrigger>
<PopoverContent>Content</PopoverContent>
</Popover>
<HoverCard>
<HoverCard shouldTriggerToggleOpen>
<HoverCardTrigger>Trigger</HoverCardTrigger>
<HoverCardContent>
<div className='max-w-[100px]'>
Expand Down
2 changes: 1 addition & 1 deletion lefthook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pre-commit:
glob: "*.{json,js,ts,tsx}"
run: yarn tsc --noEmit -p ./tsconfig.json
3_build:
run: yarn next build
run: yarn build

pre-push:
commands:
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "@renderui/core",
"version": "1.5.8",
"private": false,
"sideEffects": false,
"description": "React UI library with highly modular and ready-out-of-the-box components",
"license": "MIT",
"author": "Lovro Žagar",
Expand All @@ -27,7 +28,7 @@
"type:coverage": "typescript-coverage-report",
"lint": "npx @biomejs/biome lint ./src",
"lint:check": "npx @biomejs/biome check ./src",
"lint:format": "npx @biomejs/biome format ./src",
"lint:format": "npx @biomejs/biome format --write ./src",
"lint:fix": "npx @biomejs/biome lint --write ./src"
},
"dependencies": {
Expand Down Expand Up @@ -67,11 +68,11 @@
"postcss": "^8.4.35",
"react": "19.0.0-rc-a960b92c-20240819",
"react-dom": "19.0.0-rc-a960b92c-20240819",
"tailwindcss": "^3.4.1",
"types-react": "^19.0.0-rc.1",
"types-react-dom": "^19.0.0-rc.1",
"typescript": "^5.5.4",
"typescript-coverage-report": "^1.0.0",
"tailwindcss": "^3.4.1",
"vite": "^5.1.4"
},
"peerDependencies": {
Expand Down
6 changes: 3 additions & 3 deletions src/components/hover-card/components/hover-card-content.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DEFAULT_HOVER_CARD_CONTENT_CLASSNAME } from '@/components/hover-card/constants/constants'
import type { HoverCardContentProps } from '@/components/hover-card/types/hover-card-content'
import {
HoverCardArrow as HoverCardArrowPrimitive,
Expand All @@ -12,6 +13,7 @@ const HoverCardContent = (props: HoverCardContentProps) => {
sideOffset = 4,
side = 'bottom',
children,
className,
style,
animationDuration,
animationInDuration,
Expand All @@ -27,9 +29,7 @@ const HoverCardContent = (props: HoverCardContentProps) => {
align={align}
sideOffset={sideOffset}
side={side}
className={cn(
'render-ui-popover-content data-[state=closed]:data-[side=bottom]:animate-popover-exit-from-top-and-fade-out data-[state=closed]:data-[side=top]:animate-popover-exit-from-bottom-and-fade-out data-[state=closed]:data-[side=right]:animate-popover-exit-from-left-and-fade-out data-[state=closed]:data-[side=left]:animate-popover-exit-from-right-and-fade-out data-[state=open]:data-[side=bottom]:animate-popover-enter-to-top-and-fade-in data-[state=open]:data-[side=left]:animate-popover-enter-to-right-and-fade-in data-[state=open]:data-[side=right]:animate-popover-enter-to-left-and-fade-in data-[state=open]:data-[side=top]:animate-popover-enter-to-bottom-and-fade-in z-50 box-border w-fit rounded-md border bg-background border-mode-accent text-mode-contrast p-4 shadow-md outline-none will-change-[transform,opacity] data-[side=bottom]:origin-top data-[side=left]:origin-right data-[side=right]:origin-left data-[side=top]:origin-bottom',
)}
className={cn(DEFAULT_HOVER_CARD_CONTENT_CLASSNAME, className)}
style={{
...getAnimationStyleVariables({
animationDuration,
Expand Down
15 changes: 13 additions & 2 deletions src/components/hover-card/components/hover-card-trigger.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import { Button } from '@/components/button'
import { useHoverCardContext } from '@/components/hover-card/contexts/hover-card-context'
import type { HoverCardTriggerProps } from '@/components/hover-card/types/hover-card-trigger'
import { HoverCardTrigger as HoverCardTriggerPrimitive } from '@radix-ui/react-hover-card'
import { chain } from '@renderui/utils'
import React from 'react'

const HoverCardTrigger = (props: HoverCardTriggerProps) => {
const { variant = 'plain', ...restProps } = props
const { variant = 'plain', onPress, ...restProps } = props

const { shouldTriggerToggleOpen, setOpen } = useHoverCardContext()

return (
<HoverCardTriggerPrimitive asChild>
<Button variant={variant} {...restProps} />
<Button
variant={variant}
{...restProps}
onPress={chain(
shouldTriggerToggleOpen ? () => setOpen((prev) => !prev) : undefined,
onPress,
)}
/>
</HoverCardTriggerPrimitive>
)
}
Expand Down
31 changes: 27 additions & 4 deletions src/components/hover-card/components/hover-card.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,36 @@
import { useControllableState } from '@/components/_shared/hooks/use-controllable-state'
import { HoverCardProvider } from '@/components/hover-card/contexts/hover-card-context'
import type { HoverCardProps } from '@/components/hover-card/types/hover-card'
import { HoverCard as HoverCardPrimitive } from '@radix-ui/react-hover-card'
import React from 'react'

// @TODO add controllable state and and manipulation for open close on trigger

const HoverCard = (props: HoverCardProps) => {
const { openDelay = 300, closeDelay = 300, ...restProps } = props
const {
defaultOpen,
open: openProp,
onOpenChange,
children,
shouldTriggerToggleOpen = false,
openDelay = 0,
closeDelay = 300,
} = props

const [open, setOpen] = useControllableState({
defaultProp: defaultOpen,
prop: openProp,
onChange: onOpenChange,
})

return <HoverCardPrimitive openDelay={openDelay} closeDelay={closeDelay} {...restProps} />
return (
<HoverCardPrimitive
open={open}
onOpenChange={setOpen}
openDelay={openDelay}
closeDelay={closeDelay}
>
<HoverCardProvider value={{ shouldTriggerToggleOpen, setOpen }}>{children}</HoverCardProvider>
</HoverCardPrimitive>
)
}

export { HoverCard }
4 changes: 4 additions & 0 deletions src/components/hover-card/constants/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const DEFAULT_HOVER_CARD_CONTENT_CLASSNAME =
'render-ui-hover-card-content data-[state=closed]:data-[side=bottom]:animate-popover-exit-from-top-and-fade-out data-[state=closed]:data-[side=top]:animate-popover-exit-from-bottom-and-fade-out data-[state=closed]:data-[side=right]:animate-popover-exit-from-left-and-fade-out data-[state=closed]:data-[side=left]:animate-popover-exit-from-right-and-fade-out data-[state=open]:data-[side=bottom]:animate-popover-enter-to-top-and-fade-in data-[state=open]:data-[side=left]:animate-popover-enter-to-right-and-fade-in data-[state=open]:data-[side=right]:animate-popover-enter-to-left-and-fade-in data-[state=open]:data-[side=top]:animate-popover-enter-to-bottom-and-fade-in z-50 box-border w-fit rounded-md border bg-background border-mode-accent text-mode-contrast p-4 shadow-md outline-none will-change-[transform,opacity] data-[side=bottom]:origin-top data-[side=left]:origin-right data-[side=right]:origin-left data-[side=top]:origin-bottom'

export { DEFAULT_HOVER_CARD_CONTENT_CLASSNAME }
12 changes: 12 additions & 0 deletions src/components/hover-card/contexts/hover-card-context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { initializeContext } from '@renderui/utils'

import type { HoverCardContext } from '@/components/hover-card/types/hover-card-context'

const [HoverCardProvider, useHoverCardContext] = initializeContext<HoverCardContext>({
errorMessage: 'Components using hoverCard context must be wrapped in a <HoverCard />.',
providerName: 'HoverCardProvider',
hookName: 'useHoverCardContext',
name: 'HoverCardContext',
})

export { HoverCardProvider, useHoverCardContext }
6 changes: 6 additions & 0 deletions src/components/hover-card/types/hover-card-context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type HoverCardContext = {
shouldTriggerToggleOpen: boolean
setOpen: React.Dispatch<React.SetStateAction<boolean>>
}

export type { HoverCardContext }
8 changes: 7 additions & 1 deletion src/components/hover-card/types/hover-card.ts
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
export type { HoverCardProps } from '@radix-ui/react-hover-card'
import type { Simplify } from '@/components/_shared/types/simplify'

import type { HoverCardProps as HoverCardPrimitiveProps } from '@radix-ui/react-hover-card'

type HoverCardProps = Simplify<HoverCardPrimitiveProps & { shouldTriggerToggleOpen?: boolean }>

export type { HoverCardProps }

0 comments on commit be9718a

Please sign in to comment.