feat(popover): component created, a11y passing, tests passing

This commit is contained in:
Junior Garcia 2023-04-07 00:44:52 -03:00
parent f51d19b09b
commit fdaaad4210
8 changed files with 471 additions and 126 deletions

View File

@ -1,11 +1,21 @@
import * as React from "react"; import * as React from "react";
import {render} from "@testing-library/react"; import {render, fireEvent, act} from "@testing-library/react";
import {Button} from "@nextui-org/button";
import {Popover} from "../src"; import {Popover, PopoverContent, PopoverTrigger} from "../src";
describe("Popover", () => { describe("Popover", () => {
it("should render correctly", () => { it("should render correctly", () => {
const wrapper = render(<Popover />); const wrapper = render(
<Popover>
<PopoverTrigger>
<button>Open popover</button>
</PopoverTrigger>
<PopoverContent>
<p>This is the content of the popover.</p>
</PopoverContent>
</Popover>,
);
expect(() => wrapper.unmount()).not.toThrow(); expect(() => wrapper.unmount()).not.toThrow();
}); });
@ -13,7 +23,105 @@ describe("Popover", () => {
it("ref should be forwarded", () => { it("ref should be forwarded", () => {
const ref = React.createRef<HTMLDivElement>(); const ref = React.createRef<HTMLDivElement>();
render(<Popover ref={ref} />); render(
<Popover ref={ref}>
<PopoverTrigger>
<button>Open popover</button>
</PopoverTrigger>
<PopoverContent>
<p>This is the content of the popover.</p>
</PopoverContent>
</Popover>,
);
expect(ref.current).not.toBeNull(); expect(ref.current).not.toBeNull();
}); });
it("should hide the popover when pressing the escape key", () => {
const onClose = jest.fn();
const wrapper = render(
<Popover isOpen onOpenChange={(isOpen) => (!isOpen ? onClose() : undefined)}>
<PopoverTrigger>
<button>Open popover</button>
</PopoverTrigger>
<PopoverContent data-testid="content-test">
<p>This is the content of the popover.</p>
</PopoverContent>
</Popover>,
);
const content = wrapper.getByTestId("content-test");
fireEvent.keyDown(content, {key: "Escape"});
expect(onClose).toHaveBeenCalledTimes(1);
});
it("should still hide the popover when pressing the escape key ", () => {
const onClose = jest.fn();
const wrapper = render(
<Popover isOpen onOpenChange={(isOpen) => (!isOpen ? onClose() : undefined)}>
<PopoverTrigger>
<button>Open popover</button>
</PopoverTrigger>
<PopoverContent data-testid="content-test">
<p>This is the content of the popover.</p>
</PopoverContent>
</Popover>,
);
const content = wrapper.getByTestId("content-test");
fireEvent.keyDown(content, {key: "Escape"});
expect(onClose).toHaveBeenCalledTimes(1);
});
it("should hide the popover on blur ", () => {
const onClose = jest.fn();
const wrapper = render(
<Popover isOpen onOpenChange={(isOpen) => (!isOpen ? onClose() : undefined)}>
<PopoverTrigger>
<button>Open popover</button>
</PopoverTrigger>
<PopoverContent data-testid="content-test">
<p>This is the content of the popover.</p>
</PopoverContent>
</Popover>,
);
const content = wrapper.getByTestId("content-test");
fireEvent.blur(content);
expect(onClose).toHaveBeenCalledTimes(1);
});
it("should work with NextUI button", () => {
const onClose = jest.fn();
const wrapper = render(
<Popover onOpenChange={(isOpen) => (!isOpen ? onClose() : undefined)}>
<PopoverTrigger>
<Button data-testid="trigger-test">Open popover</Button>
</PopoverTrigger>
<PopoverContent>
<p>This is the content of the popover.</p>
</PopoverContent>
</Popover>,
);
const trigger = wrapper.getByTestId("trigger-test");
// open popover
act(() => {
trigger.click();
});
expect(onClose).toHaveBeenCalledTimes(0);
// close popover
act(() => {
trigger.click();
});
expect(onClose).toHaveBeenCalledTimes(1);
});
}); });

View File

@ -10,5 +10,8 @@ export type {PopoverContentProps} from "./popover-content";
// export hooks // export hooks
export {usePopover} from "./use-popover"; export {usePopover} from "./use-popover";
// export context
export * from "./popover-context";
// export components // export components
export {Popover, PopoverTrigger, PopoverContent}; export {Popover, PopoverTrigger, PopoverContent};

View File

@ -1,14 +1,17 @@
import {ReactNode, useMemo, useCallback} from "react"; import type {AriaDialogProps} from "@react-aria/dialog";
import {ReactNode, useMemo, useRef} from "react";
import {forwardRef} from "@nextui-org/system"; import {forwardRef} from "@nextui-org/system";
import {DismissButton} from "@react-aria/overlays"; import {DismissButton} from "@react-aria/overlays";
import {TRANSITION_VARIANTS} from "@nextui-org/framer-transitions"; import {TRANSITION_VARIANTS} from "@nextui-org/framer-transitions";
import {FocusScope} from "@react-aria/focus";
import {motion} from "framer-motion"; import {motion} from "framer-motion";
import {getTransformOrigins} from "@nextui-org/aria-utils"; import {getTransformOrigins} from "@nextui-org/aria-utils";
import {useDialog} from "@react-aria/dialog";
import {mergeProps} from "@react-aria/utils";
import {usePopoverContext} from "./popover-context"; import {usePopoverContext} from "./popover-context";
export interface PopoverContentProps { export interface PopoverContentProps extends AriaDialogProps {
children: ReactNode; children: ReactNode;
} }
@ -17,19 +20,25 @@ const PopoverContent = forwardRef<PopoverContentProps, "section">((props, _) =>
const { const {
Component: OverlayComponent, Component: OverlayComponent,
isOpen,
placement, placement,
showArrow, showArrow,
motionProps, motionProps,
disableAnimation, disableAnimation,
getPopoverProps, getPopoverProps,
getArrowProps, getArrowProps,
getDialogProps,
onClose, onClose,
} = usePopoverContext(); } = usePopoverContext();
const Component = as || OverlayComponent || "div"; const Component = as || OverlayComponent || "div";
const {style, className, ...otherPopoverProps} = getPopoverProps(otherProps); const dialogRef = useRef(null);
const {dialogProps} = useDialog(
{
role: "dialog",
},
dialogRef,
);
const arrowContent = useMemo(() => { const arrowContent = useMemo(() => {
if (!showArrow) return null; if (!showArrow) return null;
@ -37,42 +46,24 @@ const PopoverContent = forwardRef<PopoverContentProps, "section">((props, _) =>
return <span {...getArrowProps()} />; return <span {...getArrowProps()} />;
}, [showArrow, getArrowProps]); }, [showArrow, getArrowProps]);
const ContentWrapper = useCallback( const content = (
({children}: {children: ReactNode}) => { <>
return ( <DismissButton onDismiss={onClose} />
<FocusScope restoreFocus> <Component {...getDialogProps(mergeProps(dialogProps, otherProps))} ref={dialogRef}>
<Component className={className}> {children}
<DismissButton onDismiss={onClose} /> {arrowContent}
{children} </Component>
{arrowContent} <DismissButton onDismiss={onClose} />
<DismissButton onDismiss={onClose} /> </>
</Component>
</FocusScope>
);
},
[Component, className, onClose, arrowContent],
); );
const visibility = useMemo(() => {
if (disableAnimation) return isOpen ? "visible" : "hidden";
return "visible";
}, [disableAnimation, isOpen]);
return ( return (
<div <div {...getPopoverProps()}>
{...otherPopoverProps}
style={{
...style,
visibility,
outline: "none",
}}
>
{disableAnimation ? ( {disableAnimation ? (
<ContentWrapper>{children}</ContentWrapper> content
) : ( ) : (
<motion.div <motion.div
animate={isOpen ? "enter" : "exit"} animate="enter"
exit="exit" exit="exit"
initial="exit" initial="exit"
style={{ style={{
@ -81,7 +72,7 @@ const PopoverContent = forwardRef<PopoverContentProps, "section">((props, _) =>
variants={TRANSITION_VARIANTS.scaleSpring} variants={TRANSITION_VARIANTS.scaleSpring}
{...motionProps} {...motionProps}
> >
<ContentWrapper>{children}</ContentWrapper> {content}
</motion.div> </motion.div>
)} )}
</div> </div>

View File

@ -1,6 +1,7 @@
import {forwardRef} from "@nextui-org/system"; import {forwardRef} from "@nextui-org/system";
import {OverlayContainer} from "@react-aria/overlays";
import {Children, ReactNode} from "react"; import {Children, ReactNode} from "react";
import {AnimatePresence} from "framer-motion";
import {Overlay} from "@react-aria/overlays";
import {UsePopoverProps, usePopover} from "./use-popover"; import {UsePopoverProps, usePopover} from "./use-popover";
import {PopoverProvider} from "./popover-context"; import {PopoverProvider} from "./popover-context";
@ -19,12 +20,16 @@ const Popover = forwardRef<PopoverProps, "div">((props, ref) => {
const [trigger, content] = Children.toArray(children); const [trigger, content] = Children.toArray(children);
const mountOverlay = context.isOpen;
return ( return (
<PopoverProvider value={context}> <PopoverProvider value={context}>
{trigger} {trigger}
{mountOverlay && <OverlayContainer>{content}</OverlayContainer>} {context.disableAnimation && context.isOpen ? (
<Overlay>{content}</Overlay>
) : (
<AnimatePresence initial={false}>
{context.isOpen ? <Overlay>{content}</Overlay> : null}
</AnimatePresence>
)}
</PopoverProvider> </PopoverProvider>
); );
}); });

View File

@ -1,35 +1,32 @@
import type {PopoverVariantProps, SlotsToClasses, PopoverSlots} from "@nextui-org/theme"; import type {PopoverVariantProps, SlotsToClasses, PopoverSlots} from "@nextui-org/theme";
import type {HTMLMotionProps} from "framer-motion"; import type {HTMLMotionProps} from "framer-motion";
import type {OverlayPlacement, OverlayOptions} from "@nextui-org/aria-utils"; import type {OverlayPlacement} from "@nextui-org/aria-utils";
import type {RefObject, Ref} from "react"; import type {RefObject, Ref} from "react";
import {useOverlayTriggerState} from "@react-stately/overlays"; import {useOverlayTriggerState} from "@react-stately/overlays";
import {useFocusRing} from "@react-aria/focus"; import {useFocusRing} from "@react-aria/focus";
import { import {
AriaOverlayProps, AriaPopoverProps,
useOverlayTrigger, useOverlayTrigger,
useOverlayPosition, usePopover as useReactAriaPopover,
useOverlay,
useModal,
} from "@react-aria/overlays"; } from "@react-aria/overlays";
import {useDialog} from "@react-aria/dialog";
import {OverlayTriggerProps} from "@react-types/overlays"; import {OverlayTriggerProps} from "@react-types/overlays";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system"; import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {toReactAriaPlacement, getArrowPlacement} from "@nextui-org/aria-utils"; import {toReactAriaPlacement, getArrowPlacement} from "@nextui-org/aria-utils";
import {popover} from "@nextui-org/theme"; import {popover} from "@nextui-org/theme";
import {chain, mergeProps, mergeRefs} from "@react-aria/utils"; import {mergeProps, mergeRefs} from "@react-aria/utils";
import {createDOMRef} from "@nextui-org/dom-utils"; import {createDOMRef} from "@nextui-org/dom-utils";
import {ReactRef, clsx} from "@nextui-org/shared-utils"; import {ReactRef, clsx} from "@nextui-org/shared-utils";
import {useId, useMemo, useCallback, useImperativeHandle, useRef} from "react"; import {useId, useMemo, useCallback, useImperativeHandle, useRef} from "react";
export interface Props extends HTMLNextUIProps<"div", PopoverVariantProps> { export interface Props extends HTMLNextUIProps<"div"> {
/** /**
* Ref to the DOM node. * Ref to the DOM node.
*/ */
ref?: ReactRef<HTMLElement | null>; ref?: ReactRef<HTMLElement | null>;
/** /**
* A ref for the scrollable region within the overlay. * A ref for the scrollable region within the overlay.
* @default overlayRef * @default popoverRef
*/ */
scrollRef?: RefObject<HTMLElement>; scrollRef?: RefObject<HTMLElement>;
/** /**
@ -41,6 +38,11 @@ export interface Props extends HTMLNextUIProps<"div", PopoverVariantProps> {
* @default 'top' * @default 'top'
*/ */
placement?: OverlayPlacement; placement?: OverlayPlacement;
/**
* Whether the element should render an arrow.
* @default false
*/
showArrow?: boolean;
/** /**
* Type of overlay that is opened by the trigger. * Type of overlay that is opened by the trigger.
*/ */
@ -62,11 +64,12 @@ export interface Props extends HTMLNextUIProps<"div", PopoverVariantProps> {
* ``` * ```
*/ */
styles?: SlotsToClasses<PopoverSlots>; styles?: SlotsToClasses<PopoverSlots>;
/** Handler that is called when the overlay should close. */
onClose?: () => void;
} }
export type UsePopoverProps = Props & AriaOverlayProps & OverlayTriggerProps & OverlayOptions; export type UsePopoverProps = Props &
Omit<AriaPopoverProps, "placement" | "triggerRef" | "popoverRef"> &
OverlayTriggerProps &
PopoverVariantProps;
export function usePopover(originalProps: UsePopoverProps) { export function usePopover(originalProps: UsePopoverProps) {
const [props, variantProps] = mapPropsVariants(originalProps, popover.variantKeys); const [props, variantProps] = mapPropsVariants(originalProps, popover.variantKeys);
@ -87,29 +90,25 @@ export function usePopover(originalProps: UsePopoverProps) {
showArrow = false, showArrow = false,
offset = 7, offset = 7,
crossOffset = 0, crossOffset = 0,
isDismissable = true, isKeyboardDismissDisabled,
shouldCloseOnBlur = true,
isKeyboardDismissDisabled = true,
shouldCloseOnInteractOutside,
motionProps, motionProps,
className, className,
styles, styles,
onClose,
...otherProps ...otherProps
} = props; } = props;
const Component = as || "div"; const Component = as || "div";
const popoverId = useId(); const popoverId = useId();
const overlayRef = useRef<HTMLDivElement>(null); const popoverRef = useRef<HTMLDivElement>(null);
const domTriggerRef = useRef<HTMLElement>(null); const domTriggerRef = useRef<HTMLElement>(null);
const triggerRef = triggerRefProp || domTriggerRef; const triggerRef = triggerRefProp || domTriggerRef;
// Sync ref with overlayRef from passed ref. // Sync ref with popoverRef from passed ref.
useImperativeHandle(ref, () => useImperativeHandle(ref, () =>
// @ts-ignore // @ts-ignore
createDOMRef(overlayRef), createDOMRef(popoverRef),
); );
const state = useOverlayTriggerState({ const state = useOverlayTriggerState({
@ -118,47 +117,25 @@ export function usePopover(originalProps: UsePopoverProps) {
onOpenChange, onOpenChange,
}); });
const {triggerProps, overlayProps: overlayTriggerProps} = useOverlayTrigger( const {popoverProps, arrowProps, placement} = useReactAriaPopover(
{type: triggerType},
state,
triggerRef,
);
const {overlayProps: positionProps, arrowProps, placement} = useOverlayPosition({
overlayRef,
scrollRef,
isOpen: isOpen,
targetRef: triggerRef,
placement: toReactAriaPlacement(placementProp),
offset: showArrow ? offset + 3 : offset,
crossOffset,
shouldFlip,
containerPadding,
});
const {overlayProps} = useOverlay(
{ {
isOpen: state.isOpen, triggerRef,
onClose: chain(state.close, onClose), popoverRef,
isDismissable, placement: toReactAriaPlacement(placementProp),
shouldCloseOnBlur, offset: showArrow ? offset + 3 : offset,
scrollRef,
crossOffset,
shouldFlip,
containerPadding,
isKeyboardDismissDisabled, isKeyboardDismissDisabled,
shouldCloseOnInteractOutside,
}, },
overlayRef, state,
); );
const {triggerProps} = useOverlayTrigger({type: triggerType}, state, triggerRef);
const {isFocusVisible, focusProps} = useFocusRing(); const {isFocusVisible, focusProps} = useFocusRing();
const {modalProps} = useModal({isDisabled: true});
const {dialogProps} = useDialog(
{
role: "dialog",
},
overlayRef,
);
const slots = useMemo( const slots = useMemo(
() => () =>
popover({ popover({
@ -171,21 +148,20 @@ export function usePopover(originalProps: UsePopoverProps) {
const baseStyles = clsx(styles?.base, className); const baseStyles = clsx(styles?.base, className);
const getPopoverProps: PropGetter = (props = {}) => ({ const getPopoverProps: PropGetter = (props = {}) => ({
ref: overlayRef, ref: popoverRef,
...mergeProps( ...mergeProps(popoverProps, otherProps, props),
overlayTriggerProps,
overlayProps,
modalProps,
dialogProps,
positionProps,
focusProps,
otherProps,
props,
),
className: slots.base({class: clsx(baseStyles, props.className)}),
id: popoverId, id: popoverId,
}); });
const getDialogProps: PropGetter = (props = {}) => ({
className: slots.base({class: clsx(baseStyles, props.className)}),
...mergeProps(focusProps, props),
style: {
// this prevent the dialog to have a default outline
outline: "none",
},
});
const getTriggerProps = useCallback<PropGetter>( const getTriggerProps = useCallback<PropGetter>(
(props = {}, _ref: Ref<any> | null | undefined = null) => { (props = {}, _ref: Ref<any> | null | undefined = null) => {
return { return {
@ -218,9 +194,11 @@ export function usePopover(originalProps: UsePopoverProps) {
onClose: state.close, onClose: state.close,
disableAnimation: originalProps.disableAnimation ?? false, disableAnimation: originalProps.disableAnimation ?? false,
motionProps, motionProps,
focusProps,
getPopoverProps, getPopoverProps,
getTriggerProps, getTriggerProps,
getArrowProps, getArrowProps,
getDialogProps,
}; };
} }

View File

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
import {ComponentStory, ComponentMeta} from "@storybook/react"; import {ComponentStory, ComponentMeta} from "@storybook/react";
import {popover} from "@nextui-org/theme"; import {popover, ButtonVariantProps} from "@nextui-org/theme";
import {Button} from "@nextui-org/button"; import {Button} from "@nextui-org/button";
import {Popover, PopoverTrigger, PopoverContent, PopoverProps} from "../src"; import {Popover, PopoverTrigger, PopoverContent, PopoverProps} from "../src";
@ -56,11 +56,6 @@ export default {
type: "boolean", type: "boolean",
}, },
}, },
isDisabled: {
control: {
type: "boolean",
},
},
showArrow: { showArrow: {
control: { control: {
type: "boolean", type: "boolean",
@ -91,35 +86,295 @@ const defaultProps = {
placement: "top", placement: "top",
offset: 7, offset: 7,
defaultOpen: false, defaultOpen: false,
isDisabled: false,
disableAnimation: false, disableAnimation: false,
}; };
const content = (
<PopoverContent>
<div className="px-1 py-2">
<div className="text-sm font-bold">Popover Content</div>
<div className="text-xs">This is a content of the popover</div>
</div>
</PopoverContent>
);
const Template: ComponentStory<typeof Popover> = (args: PopoverProps) => { const Template: ComponentStory<typeof Popover> = (args: PopoverProps) => {
return ( return (
<Popover {...args}> <Popover {...args}>
<PopoverTrigger> <PopoverTrigger>
<Button>Open popover</Button> <Button>Open popover</Button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent> {content}
<div className="px-1 py-2">
<div className="text-sm font-bold">Popover Content</div>
<div className="text-xs">This is a content of the popover</div>
</div>
</PopoverContent>
</Popover> </Popover>
); );
}; };
const OpenChangeTemplate: ComponentStory<typeof Popover> = (args: PopoverProps) => {
const [isOpen, setIsOpen] = React.useState(false);
return (
<div className="flex flex-col gap-2">
<Popover {...args} onOpenChange={(open) => setIsOpen(open)}>
<PopoverTrigger>
<Button>Open popover</Button>
</PopoverTrigger>
<PopoverContent>
<div className="px-1 py-2">
<div className="text-sm font-bold">Popover Content</div>
<div className="text-xs">This is a content of the popover</div>
</div>
</PopoverContent>
</Popover>
<p className="text-sm">isOpen: {isOpen ? "true" : "false"}</p>
</div>
);
};
const VariantsTemplate: ComponentStory<typeof Popover> = (args: PopoverProps) => {
const buttonColor = args.color as ButtonVariantProps["color"];
const content = (
<PopoverContent>
<div className="px-1 py-2">
<div className="text-sm font-bold">Popover Content</div>
<div className="text-xs">This is a content of the popover</div>
</div>
</PopoverContent>
);
return (
<div className="flex gap-2">
<Popover {...args} variant="solid">
<PopoverTrigger>
<Button color={buttonColor}>Solid</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} variant="bordered">
<PopoverTrigger>
<Button color={buttonColor} variant="bordered">
Bordered
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} variant="light">
<PopoverTrigger>
<Button color={buttonColor} variant="light">
Light
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} variant="flat">
<PopoverTrigger>
<Button color={buttonColor} variant="flat">
Flat
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} variant="faded">
<PopoverTrigger>
<Button color={buttonColor} variant="faded">
Faded
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} variant="shadow">
<PopoverTrigger>
<Button color={buttonColor} variant="shadow">
Shadow
</Button>
</PopoverTrigger>
{content}
</Popover>
</div>
);
};
const PlacementsTemplate: ComponentStory<typeof Popover> = (args: PopoverProps) => {
const buttonColor = args.color as ButtonVariantProps["color"];
return (
<div className="inline-grid grid-cols-3 gap-4">
<Popover {...args} placement="top-start">
<PopoverTrigger>
<Button color={buttonColor} variant="flat">
Top Start
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args}>
<PopoverTrigger>
<Button color={buttonColor} variant="flat">
Top
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} placement="top-end">
<PopoverTrigger>
<Button color={buttonColor} variant="flat">
Top End
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} placement="bottom-start">
<PopoverTrigger>
<Button color={buttonColor} variant="flat">
Bottom Start
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} placement="bottom">
<PopoverTrigger>
<Button color={buttonColor} variant="flat">
Bottom
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} placement="bottom-end">
<PopoverTrigger>
<Button color={buttonColor} variant="flat">
Bottom End
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} placement="right-start">
<PopoverTrigger>
<Button color={buttonColor} variant="flat">
Right Start
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} placement="right">
<PopoverTrigger>
<Button color={buttonColor} variant="flat">
Right
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} placement="right-end">
<PopoverTrigger>
<Button color={buttonColor} variant="flat">
Right End
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} placement="left-start">
<PopoverTrigger>
<Button color={buttonColor} variant="flat">
Left Start
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} placement="left">
<PopoverTrigger>
<Button color={buttonColor} variant="flat">
Left
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} placement="left-end">
<PopoverTrigger>
<Button color={buttonColor} variant="flat">
Left End
</Button>
</PopoverTrigger>
{content}
</Popover>
</div>
);
};
const OffsetTemplate: ComponentStory<typeof Popover> = (args: PopoverProps) => (
<div className="flex gap-2">
<Popover {...args}>
<PopoverTrigger>
<Button color="warning" variant="faded">
Default offset (7)
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} offset={15}>
<PopoverTrigger>
<Button color="warning" variant="faded">
15 offset
</Button>
</PopoverTrigger>
{content}
</Popover>
<Popover {...args} offset={-7}>
<PopoverTrigger>
<Button color="warning" variant="faded">
-7 offset
</Button>
</PopoverTrigger>
{content}
</Popover>
</div>
);
export const Default = Template.bind({}); export const Default = Template.bind({});
Default.args = { Default.args = {
...defaultProps, ...defaultProps,
showArrow: true,
}; };
export const DisableAnimation = Template.bind({}); export const DisableAnimation = Template.bind({});
DisableAnimation.args = { DisableAnimation.args = {
...defaultProps, ...defaultProps,
showArrow: true,
disableAnimation: true, disableAnimation: true,
}; };
export const WithArrow = Template.bind({});
WithArrow.args = {
...defaultProps,
showArrow: true,
};
export const OpenChange = OpenChangeTemplate.bind({});
OpenChange.args = {
...defaultProps,
};
export const Variants = VariantsTemplate.bind({});
Variants.args = {
...defaultProps,
color: "primary",
};
export const Placements = PlacementsTemplate.bind({});
Placements.args = {
...defaultProps,
color: "secondary",
};
export const WithOffset = OffsetTemplate.bind({});
WithOffset.args = {
...defaultProps,
color: "warning",
};

View File

@ -84,7 +84,6 @@ const Tooltip = forwardRef<TooltipProps, "div">((props, ref) => {
{content} {content}
{arrowContent} {arrowContent}
</Component> </Component>
;
</OverlayContainer> </OverlayContainer>
) : ( ) : (
<AnimatePresence initial={false}> <AnimatePresence initial={false}>

View File

@ -303,6 +303,12 @@ Default.args = {
...defaultProps, ...defaultProps,
}; };
export const DisableAnimation = Template.bind({});
DisableAnimation.args = {
...defaultProps,
disableAnimation: true,
};
export const WithArrow = Template.bind({}); export const WithArrow = Template.bind({});
WithArrow.args = { WithArrow.args = {
...defaultProps, ...defaultProps,