-
} isFixed hasPadding={false}>
- Text Content without padding
+export const FixedStory = () => (
+
);
-export const WithFunctionAsChildren = () => (
+export const WithContentAsFunction = () => (
-
}>
- {(popover: DisclosureFnProps) => (
+
(
<>
There is some content
@@ -73,6 +72,8 @@ export const WithFunctionAsChildren = () => (
>
)}
+ >
+
);
diff --git a/packages/design-system/src/components/Popover/Popover.tsx b/packages/design-system/src/components/Popover/Popover.tsx
index 470d34058a4..30f76d88a16 100644
--- a/packages/design-system/src/components/Popover/Popover.tsx
+++ b/packages/design-system/src/components/Popover/Popover.tsx
@@ -1,69 +1,65 @@
-import { useRef } from 'react';
-import type { ReactNode } from 'react';
+import { useRef, Fragment } from 'react';
+import type { ReactNode, MouseEvent } from 'react';
import tokens from '@talend/design-tokens';
import { Placement, FloatingArrow, FloatingPortal } from '@floating-ui/react';
import { usePopover } from './usePopover';
-import { Disclosure } from '../Disclosure/Disclosure';
import theme from './Popover.module.scss';
+import { renderOrClone, ChildrenOrFn } from '../../renderOrClone';
-interface PopoverOptions {
- disclosure?: ReactNode;
+type PopoverOptions = {
+ popup: ReactNode | ((props: any) => ReactNode);
initialOpen?: boolean;
placement?: Placement;
modal?: boolean;
open?: boolean;
isFixed?: boolean;
onOpenChange?: (open: boolean) => void;
-}
+};
+
+export type PopoverProps = {
+ children: ChildrenOrFn;
+} & PopoverOptions;
export function Popover({
children,
- disclosure,
modal = true,
isFixed = false,
+ popup,
...restOptions
-}: {
- children: ReactNode;
-} & PopoverOptions) {
+}: PopoverProps) {
// This can accept any props as options, e.g. `placement`,
// or other positioning options.
const arrowRef = useRef
(null);
const popover = usePopover({ modal, arrowRef, ...restOptions });
- let childrenRendered = children;
- if (typeof children === 'function') {
- childrenRendered = children(popover);
- }
- let content = (
-
-
- {childrenRendered}
-
- );
- if (isFixed) {
- content = {content};
- }
- const disclosureProps = popover.getReferenceProps({ onClick: e => e.stopPropagation() });
+ const Wrapper = isFixed ? FloatingPortal : Fragment;
+ const onClick = (e: MouseEvent) => {
+ e.preventDefault();
+ };
+ const childrenProps = popover.getReferenceProps({ onClick });
return (
<>
-
- {disclosure}
-
- {content}
+ {renderOrClone(children, { ...childrenProps, ref: popover.refs.setReference })}
+
+
+
+ {typeof popup === 'function' ? popup(popover.getFloatingProps()) : popup}
+
+
>
);
}
diff --git a/packages/design-system/src/components/Popover/index.ts b/packages/design-system/src/components/Popover/index.ts
index e6c2c3dbb49..234ca06ee7e 100644
--- a/packages/design-system/src/components/Popover/index.ts
+++ b/packages/design-system/src/components/Popover/index.ts
@@ -1,3 +1,4 @@
import { Popover } from './Popover';
-
+export type { PopoverProps } from './Popover';
+export type { PopoverTriggerProps } from './usePopover';
export default Popover;
diff --git a/packages/design-system/src/components/Popover/usePopover.tsx b/packages/design-system/src/components/Popover/usePopover.tsx
index af7e654701e..db596ea3cbf 100644
--- a/packages/design-system/src/components/Popover/usePopover.tsx
+++ b/packages/design-system/src/components/Popover/usePopover.tsx
@@ -17,14 +17,36 @@ import {
const ARROW_HEIGHT = 7;
const GAP = 2;
-interface PopoverOptions {
+type PopoverOptions = {
initialOpen?: boolean;
arrowRef?: MutableRefObject;
placement?: Placement;
modal?: boolean;
open?: boolean;
onOpenChange?: (open: boolean) => void;
-}
+};
+
+export type PopoverTriggerProps = {
+ onClick?: (event: any) => void;
+ ref: any;
+};
+
+export type UsePopoverType = {
+ // floating-ui types
+ refs: any;
+ getFloatingProps: (props?: any) => any;
+ floatingStyles: any;
+ context: any;
+ getReferenceProps: (props?: any) => any;
+ // local state
+ open: boolean;
+ setOpen: (open: boolean) => void;
+ modal?: boolean;
+ labelId?: string;
+ descriptionId?: string;
+ setLabelId: (id: string) => void;
+ setDescriptionId: (id: string) => void;
+};
export function usePopover({
initialOpen = false,
@@ -33,7 +55,7 @@ export function usePopover({
modal,
open: controlledOpen,
onOpenChange: setControlledOpen,
-}: PopoverOptions = {}) {
+}: PopoverOptions = {}): UsePopoverType {
const [uncontrolledOpen, setUncontrolledOpen] = useState(initialOpen);
const [labelId, setLabelId] = useState();
const [descriptionId, setDescriptionId] = useState();
diff --git a/packages/design-system/src/components/Tooltip/Tooltip.tsx b/packages/design-system/src/components/Tooltip/Tooltip.tsx
index 3652c250d55..5758163d713 100644
--- a/packages/design-system/src/components/Tooltip/Tooltip.tsx
+++ b/packages/design-system/src/components/Tooltip/Tooltip.tsx
@@ -20,6 +20,7 @@ import {
import { useId } from '../../useId';
import styles from './Tooltip.module.scss';
+import { renderOrClone } from '../../renderOrClone';
export type Placement =
| 'top-start'
@@ -84,13 +85,11 @@ const Tooltip = ({ id, children, title, placement = 'top', ...rest }: TooltipPro
return (
<>
- {children(
- {
- ...getReferenceProps(),
- 'aria-describedby': safeId,
- },
- floating.refs.setReference,
- )}
+ {renderOrClone(children, {
+ ...getReferenceProps(),
+ 'aria-describedby': safeId,
+ ref: floating.refs.setReference,
+ })}
ReactNode);
+
+export function renderOrClone(children: ChildrenOrFn, props: any = {}): ReactNode {
+ if (typeof children === 'function') {
+ return children(props);
+ }
+ return children && props ? React.cloneElement(children, props) : children;
+}