-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* refactor: Prevent tooltip overflow * chore: update changeset * refactor: Update Tooltip component to use @floating-ui/react library * feat: Refactor CopyToClipboard component * chore: Remove comment in CopyToClipboard component * chore: Add padding to tooltip * chore: Update npm dependencies to include @floating-ui/react library * Update .changeset/tricky-actors-worry.md Co-authored-by: elessar.eth <[email protected]> * chore: Remove @floating-ui/react library from npm dependencies * chore: Update npm dependencies to include @floating-ui/react library * refactor: Improve error handling in CopyToClipboard component * fix: Tooltip component styling --------- Co-authored-by: elessar.eth <[email protected]>
- Loading branch information
1 parent
2ded4f9
commit 7cd9a73
Showing
5 changed files
with
209 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@blobscan/web": patch | ||
--- | ||
|
||
Added additional logic to the `Tooltip` component to prevent overflow. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,173 @@ | ||
import { | ||
cloneElement, | ||
createContext, | ||
forwardRef, | ||
isValidElement, | ||
useContext, | ||
useEffect, | ||
useMemo, | ||
useRef, | ||
useState, | ||
} from "react"; | ||
import type { ReactNode } from "react"; | ||
import { | ||
useFloating, | ||
autoUpdate, | ||
offset, | ||
flip, | ||
shift, | ||
useHover, | ||
useFocus, | ||
useDismiss, | ||
useRole, | ||
useInteractions, | ||
FloatingPortal, | ||
FloatingArrow, | ||
arrow, | ||
useMergeRefs, | ||
} from "@floating-ui/react"; | ||
|
||
type TooltipProps = { | ||
show: boolean; | ||
type TooltipOptions = { | ||
children: ReactNode; | ||
onChange?: (isOpen: boolean) => void; | ||
}; | ||
|
||
export function Tooltip({ show, children }: TooltipProps) { | ||
function useTooltip({ onChange }: TooltipOptions) { | ||
const [isOpen, setIsOpen] = useState(false); | ||
|
||
const arrowRef = useRef(null); | ||
|
||
const data = useFloating({ | ||
placement: "top", | ||
open: isOpen, | ||
onOpenChange: setIsOpen, | ||
whileElementsMounted: autoUpdate, | ||
middleware: [ | ||
shift(), | ||
offset(10), | ||
flip({ fallbackAxisSideDirection: "start" }), | ||
arrow({ element: arrowRef }), | ||
], | ||
}); | ||
|
||
const context = data.context; | ||
|
||
const hover = useHover(context, { move: false }); | ||
const focus = useFocus(context); | ||
const dismiss = useDismiss(context); | ||
const role = useRole(context, { role: "tooltip" }); | ||
|
||
const interactions = useInteractions([hover, focus, dismiss, role]); | ||
|
||
useEffect(() => { | ||
if (onChange) { | ||
onChange(isOpen); | ||
} | ||
}, [isOpen, onChange]); | ||
|
||
return useMemo( | ||
() => ({ | ||
isOpen, | ||
setIsOpen, | ||
...interactions, | ||
...data, | ||
arrowRef, | ||
}), | ||
[isOpen, setIsOpen, interactions, data, arrowRef] | ||
); | ||
} | ||
|
||
type ContextType = ReturnType<typeof useTooltip> | null; | ||
|
||
const TooltipContext = createContext<ContextType>(null); | ||
|
||
export const useTooltipContext = () => { | ||
const context = useContext(TooltipContext); | ||
|
||
if (context == null) { | ||
throw new Error("Tooltip components must be wrapped in <Tooltip />"); | ||
} | ||
|
||
return context; | ||
}; | ||
|
||
export function Tooltip(options: TooltipOptions) { | ||
const tooltip = useTooltip(options); | ||
|
||
return ( | ||
<TooltipContext.Provider value={tooltip}> | ||
{options.children} | ||
</TooltipContext.Provider> | ||
); | ||
} | ||
|
||
export const TooltipTrigger = forwardRef< | ||
HTMLElement, | ||
React.HTMLProps<HTMLElement> & { asChild?: boolean } | ||
>(function TooltipTrigger({ children, asChild = false, ...props }, propRef) { | ||
const context = useTooltipContext(); | ||
|
||
const childrenRef = | ||
isValidElement(children) && "ref" in children | ||
? (children.ref as React.Ref<HTMLElement>) | ||
: null; | ||
|
||
const ref = useMergeRefs([context.refs.setReference, propRef, childrenRef]); | ||
|
||
if (asChild && isValidElement(children)) { | ||
return cloneElement( | ||
children, | ||
context.getReferenceProps({ | ||
ref, | ||
...props, | ||
...children.props, | ||
"data-state": context.isOpen ? "open" : "closed", | ||
}) | ||
); | ||
} | ||
|
||
return ( | ||
<div | ||
className={`pointer-events-none absolute -top-2 left-[50%] z-10 -translate-x-[50%] translate-y-[-100%] ${ | ||
show ? "opacity-100" : "opacity-0" | ||
}`} | ||
<button | ||
ref={ref} | ||
data-state={context.isOpen ? "open" : "closed"} | ||
{...context.getReferenceProps(props)} | ||
> | ||
<div className="rounded-full bg-accent-light px-3 py-1.5 text-xs text-white dark:bg-primary-500"> | ||
{children} | ||
{children} | ||
</button> | ||
); | ||
}); | ||
|
||
export const TooltipContent = forwardRef< | ||
HTMLDivElement, | ||
React.HTMLProps<HTMLDivElement> | ||
>(function TooltipContent({ style, children, ...props }, propRef) { | ||
const context = useTooltipContext(); | ||
const ref = useMergeRefs([context.refs.setFloating, propRef]); | ||
|
||
if (!context.isOpen) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<FloatingPortal> | ||
<div | ||
ref={ref} | ||
style={{ | ||
...context.floatingStyles, | ||
...style, | ||
}} | ||
{...context.getFloatingProps(props)} | ||
> | ||
<div className="rounded-lg bg-accent-light px-2 py-1 text-xs font-normal text-white dark:bg-primary-500"> | ||
{children} | ||
</div> | ||
|
||
<FloatingArrow | ||
ref={context.arrowRef} | ||
context={context.context} | ||
className="fill-accent-light dark:fill-primary-500" | ||
/> | ||
</div> | ||
<div className="absolute bottom-0 left-[50%] h-2 w-2 -translate-x-[50%] translate-y-[50%] rotate-45 bg-accent-light dark:bg-primary-500" /> | ||
</div> | ||
</FloatingPortal> | ||
); | ||
} | ||
}); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.