Skip to content

Commit da1adb5

Browse files
authored
feat: container context for tooltip, popout and overlay component (#92)
* feat: container context for tooltip, popout and overlay component * fix: stop exporting container context
1 parent 3e5dd7d commit da1adb5

File tree

3 files changed

+58
-14
lines changed

3 files changed

+58
-14
lines changed

src/components/overlay/Overlay.tsx

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,38 @@
1-
import React, { ReactNode } from "react";
1+
import React, { createContext, ReactNode, useContext } from "react";
22
import classNames from "classnames";
33
import * as css from "./Overlay.css";
44
import { Portal } from "../portal";
55
import { as } from "../as";
66

7+
const OverlayContainerContext = createContext<Element | DocumentFragment | undefined>(undefined);
8+
export const OverlayContainerProvider = OverlayContainerContext.Provider;
9+
export const useOverlayContainer = (): Element | DocumentFragment | undefined => {
10+
const container = useContext(OverlayContainerContext);
11+
12+
return container;
13+
};
14+
715
export type OverlayProps = {
816
open: boolean;
917
container?: Element | DocumentFragment;
1018
backdrop?: ReactNode;
1119
};
1220

1321
export const Overlay = as<"div", OverlayProps>(
14-
({ as: AsOverlay = "div", className, open, container, backdrop, children, ...props }, ref) => (
15-
<Portal container={container}>
16-
{open ? (
17-
<AsOverlay className={classNames(css.Overlay, className)} {...props} ref={ref}>
18-
{backdrop}
19-
{children}
20-
</AsOverlay>
21-
) : null}
22-
</Portal>
23-
)
22+
({ as: AsOverlay = "div", className, open, container, backdrop, children, ...props }, ref) => {
23+
const contextContainer = useOverlayContainer();
24+
25+
return (
26+
<Portal container={container ?? contextContainer}>
27+
{open ? (
28+
<AsOverlay className={classNames(css.Overlay, className)} {...props} ref={ref}>
29+
{backdrop}
30+
{children}
31+
</AsOverlay>
32+
) : null}
33+
</Portal>
34+
);
35+
}
2436
);
2537

2638
export const OverlayBackdrop = as<"div">(

src/components/pop-out/PopOut.tsx

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,34 @@
11
import classNames from "classnames";
2-
import React, { ReactNode, useCallback, useEffect, useLayoutEffect, useRef } from "react";
2+
import React, {
3+
createContext,
4+
ReactNode,
5+
useCallback,
6+
useContext,
7+
useEffect,
8+
useLayoutEffect,
9+
useRef,
10+
} from "react";
311
import { as } from "../as";
412
import { Portal } from "../portal";
513
import { Align, getRelativeFixedPosition, Position, RectCords } from "../util";
614
import * as css from "./PopOut.css";
715

16+
const PopOutContainerContext = createContext<Element | DocumentFragment | undefined>(undefined);
17+
export const PopOutContainerProvider = PopOutContainerContext.Provider;
18+
export const usePopOutContainer = (): Element | DocumentFragment | undefined => {
19+
const container = useContext(PopOutContainerContext);
20+
21+
return container;
22+
};
23+
824
export interface PopOutProps {
925
anchor?: RectCords;
1026
position?: Position;
1127
align?: Align;
1228
offset?: number;
1329
alignOffset?: number;
1430
content: ReactNode;
31+
container?: Element | DocumentFragment;
1532
}
1633
export const PopOut = as<"div", PopOutProps>(
1734
(
@@ -25,11 +42,13 @@ export const PopOut = as<"div", PopOutProps>(
2542
alignOffset = 0,
2643
content,
2744
children,
45+
container,
2846
...props
2947
},
3048
ref
3149
) => {
3250
const baseRef = useRef<HTMLDivElement>(null);
51+
const contextContainer = usePopOutContainer();
3352

3453
const positionPopOut = useCallback(() => {
3554
const baseEl = baseRef.current;
@@ -64,7 +83,7 @@ export const PopOut = as<"div", PopOutProps>(
6483
<>
6584
{children}
6685
{anchor && (
67-
<Portal>
86+
<Portal container={container ?? contextContainer}>
6887
<AsPopOut className={classNames(css.PopOut, className)} {...props} ref={ref}>
6988
<div ref={baseRef} className={css.PopOutContainer}>
7089
{content}

src/components/tooltip/Tooltip.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import classNames from "classnames";
22
import React, {
3+
createContext,
34
MutableRefObject,
45
ReactNode,
56
RefCallback,
67
useCallback,
8+
useContext,
79
useEffect,
810
useLayoutEffect,
911
useRef,
@@ -14,6 +16,14 @@ import { Portal } from "../portal";
1416
import { Align, getRelativeFixedPosition, Position } from "../util";
1517
import * as css from "./Tooltip.css";
1618

19+
const TooltipContainerContext = createContext<Element | DocumentFragment | undefined>(undefined);
20+
export const TooltipContainerProvider = TooltipContainerContext.Provider;
21+
export const useTooltipContainer = (): Element | DocumentFragment | undefined => {
22+
const container = useContext(TooltipContainerContext);
23+
24+
return container;
25+
};
26+
1727
export const Tooltip = as<"div", css.TooltipVariants>(
1828
({ as: AsTooltip = "div", className, variant, radii, ...props }, ref) => (
1929
<AsTooltip
@@ -123,6 +133,7 @@ interface TooltipProviderProps {
123133
delay?: number;
124134
tooltip: ReactNode;
125135
children: (triggerRef: RefCallback<HTMLElement | SVGElement>) => ReactNode;
136+
container?: Element | DocumentFragment;
126137
}
127138
export const TooltipProvider = as<"div", TooltipProviderProps>(
128139
(
@@ -136,17 +147,19 @@ export const TooltipProvider = as<"div", TooltipProviderProps>(
136147
delay = 200,
137148
tooltip,
138149
children,
150+
container,
139151
...props
140152
},
141153
ref
142154
) => {
155+
const contextContainer = useTooltipContainer();
143156
const { open, triggerRef, baseRef } = useTooltip(position, align, offset, alignOffset, delay);
144157

145158
return (
146159
<>
147160
{children(triggerRef)}
148161
{open && (
149-
<Portal>
162+
<Portal container={container ?? contextContainer}>
150163
<AsTooltipProvider
151164
role="tooltip"
152165
className={classNames(css.TooltipProvider, className)}

0 commit comments

Comments
 (0)