From 358ce322429d0de25d303239771cbf1035583696 Mon Sep 17 00:00:00 2001 From: azizChebbi Date: Sat, 16 Sep 2023 14:10:13 +0100 Subject: [PATCH] fix: i changed the popover declaration for the docs to be shown --- .../react/src/components/Popover/index.tsx | 402 +++++++++--------- 1 file changed, 204 insertions(+), 198 deletions(-) diff --git a/packages/react/src/components/Popover/index.tsx b/packages/react/src/components/Popover/index.tsx index 090d04b49bf7..08f07da43672 100644 --- a/packages/react/src/components/Popover/index.tsx +++ b/packages/react/src/components/Popover/index.tsx @@ -104,231 +104,237 @@ export type PopoverProps = PolymorphicProps< PopoverBaseProps >; -function PopoverRenderFunction( - { - isTabTip, - align = isTabTip ? 'bottom-left' : 'bottom', - as: BaseComponent = 'span' as E, - autoAlign = false, - caret = isTabTip ? false : true, - className: customClassName, - children, - dropShadow = true, - highContrast = false, - onRequestClose, - open, - ...rest - }: PopoverProps, - forwardRef: ForwardedRef -) { - const prefix = usePrefix(); - const floating = useRef(null); - const popover = useRef(null); - - // If the `Popover` is the last focusable item in the tab order, it should also close when the browser window loses focus (#12922) - useWindowEvent('blur', () => { - if (open) { - onRequestClose?.(); - } - }); - - useWindowEvent('click', (event: Event) => { - if (open && !popover?.current?.contains(event.target as Node)) { - onRequestClose?.(); - } - }); - - const value = useMemo(() => { - return { - floating, - }; - }, []); - - if (isTabTip) { - const tabTipAlignments: PopoverAlignment[] = [ - 'bottom-left', - 'bottom-right', - ]; - - if (!tabTipAlignments.includes(align)) { - align = 'bottom-left'; - } - } +export interface PopoverComponent { + ( + props: PopoverProps & { forwardRef?: ForwardedRef } + ): JSX.Element | null; + displayName?: string; + propTypes?: WeakValidationMap>; +} - const ref = useMergedRefs([forwardRef, popover]); - const [autoAligned, setAutoAligned] = useState(false); - const [autoAlignment, setAutoAlignment] = useState(align); - const className = cx( +export const Popover: PopoverComponent = React.forwardRef( + function PopoverRenderFunction( { - [`${prefix}--popover-container`]: true, - [`${prefix}--popover--caret`]: caret, - [`${prefix}--popover--drop-shadow`]: dropShadow, - [`${prefix}--popover--high-contrast`]: highContrast, - [`${prefix}--popover--open`]: open, - [`${prefix}--popover--${autoAlignment}`]: autoAligned && !isTabTip, - [`${prefix}--popover--${align}`]: !autoAligned, - [`${prefix}--popover--tab-tip`]: isTabTip, - }, - customClassName - ); - - useIsomorphicEffect(() => { - if (!open) { - return; - } - - if (!autoAlign || isTabTip) { - setAutoAligned(false); - return; - } - - if (!floating.current) { - return; - } + isTabTip, + align = isTabTip ? 'bottom-left' : 'bottom', + as: BaseComponent = 'span' as E, + autoAlign = false, + caret = isTabTip ? false : true, + className: customClassName, + children, + dropShadow = true, + highContrast = false, + onRequestClose, + open, + ...rest + }: PopoverProps, + forwardRef: ForwardedRef + ) { + const prefix = usePrefix(); + const floating = useRef(null); + const popover = useRef(null); + + // If the `Popover` is the last focusable item in the tab order, it should also close when the browser window loses focus (#12922) + useWindowEvent('blur', () => { + if (open) { + onRequestClose?.(); + } + }); - if (autoAligned === true) { - return; + useWindowEvent('click', (event: Event) => { + if (open && !popover?.current?.contains(event.target as Node)) { + onRequestClose?.(); + } + }); + + const value = useMemo(() => { + return { + floating, + }; + }, []); + + if (isTabTip) { + const tabTipAlignments: PopoverAlignment[] = [ + 'bottom-left', + 'bottom-right', + ]; + + if (!tabTipAlignments.includes(align)) { + align = 'bottom-left'; + } } - const rect = floating.current.getBoundingClientRect(); - - // The conditions, per side, of when the popover is not visible, excluding the popover's internal padding(16) - const conditions = { - left: rect.x < -16, - top: rect.y < -16, - right: rect.x + (rect.width - 16) > document.documentElement.clientWidth, - bottom: - rect.y + (rect.height - 16) > document.documentElement.clientHeight, - }; - - if ( - !conditions.left && - !conditions.top && - !conditions.right && - !conditions.bottom - ) { - setAutoAligned(false); - return; - } + const ref = useMergedRefs([forwardRef, popover]); + const [autoAligned, setAutoAligned] = useState(false); + const [autoAlignment, setAutoAlignment] = useState(align); + const className = cx( + { + [`${prefix}--popover-container`]: true, + [`${prefix}--popover--caret`]: caret, + [`${prefix}--popover--drop-shadow`]: dropShadow, + [`${prefix}--popover--high-contrast`]: highContrast, + [`${prefix}--popover--open`]: open, + [`${prefix}--popover--${autoAlignment}`]: autoAligned && !isTabTip, + [`${prefix}--popover--${align}`]: !autoAligned, + [`${prefix}--popover--tab-tip`]: isTabTip, + }, + customClassName + ); + + useIsomorphicEffect(() => { + if (!open) { + return; + } - const alignments: PopoverAlignment[] = [ - 'top', - 'top-left', - 'right-bottom', - 'right', - 'right-top', - 'bottom-left', - 'bottom', - 'bottom-right', - 'left-top', - 'left', - 'left-bottom', - 'top-right', - ]; - - // Creates the prioritized list of options depending on ideal alignment coming from `align` - const options = [align]; - let option = - alignments[(alignments.indexOf(align) + 1) % alignments.length]; - - while (option) { - if (options.includes(option)) { - break; + if (!autoAlign || isTabTip) { + setAutoAligned(false); + return; } - options.push(option); - option = alignments[(alignments.indexOf(option) + 1) % alignments.length]; - } - function isVisible(alignment: PopoverAlignment) { - if (!popover.current || !floating.current) { - return false; + if (!floating.current) { + return; } - popover.current.classList.add(`${prefix}--popover--${alignment}`); + if (autoAligned === true) { + return; + } const rect = floating.current.getBoundingClientRect(); - // Check if popover is not visible to the left of the screen - if (rect.x < -16) { - popover.current.classList.remove(`${prefix}--popover--${alignment}`); - return false; + // The conditions, per side, of when the popover is not visible, excluding the popover's internal padding(16) + const conditions = { + left: rect.x < -16, + top: rect.y < -16, + right: + rect.x + (rect.width - 16) > document.documentElement.clientWidth, + bottom: + rect.y + (rect.height - 16) > document.documentElement.clientHeight, + }; + + if ( + !conditions.left && + !conditions.top && + !conditions.right && + !conditions.bottom + ) { + setAutoAligned(false); + return; } - // Check if popover is not visible at the top of the screen - if (rect.y < -16) { - popover.current.classList.remove(`${prefix}--popover--${alignment}`); - return false; + const alignments: PopoverAlignment[] = [ + 'top', + 'top-left', + 'right-bottom', + 'right', + 'right-top', + 'bottom-left', + 'bottom', + 'bottom-right', + 'left-top', + 'left', + 'left-bottom', + 'top-right', + ]; + + // Creates the prioritized list of options depending on ideal alignment coming from `align` + const options = [align]; + let option = + alignments[(alignments.indexOf(align) + 1) % alignments.length]; + + while (option) { + if (options.includes(option)) { + break; + } + options.push(option); + option = + alignments[(alignments.indexOf(option) + 1) % alignments.length]; } - // Check if popover is not visible to right of screen - if (rect.x + (rect.width - 16) > document.documentElement.clientWidth) { - popover.current.classList.remove(`${prefix}--popover--${alignment}`); - return false; - } + function isVisible(alignment: PopoverAlignment) { + if (!popover.current || !floating.current) { + return false; + } + + popover.current.classList.add(`${prefix}--popover--${alignment}`); + + const rect = floating.current.getBoundingClientRect(); + + // Check if popover is not visible to the left of the screen + if (rect.x < -16) { + popover.current.classList.remove(`${prefix}--popover--${alignment}`); + return false; + } + + // Check if popover is not visible at the top of the screen + if (rect.y < -16) { + popover.current.classList.remove(`${prefix}--popover--${alignment}`); + return false; + } + + // Check if popover is not visible to right of screen + if (rect.x + (rect.width - 16) > document.documentElement.clientWidth) { + popover.current.classList.remove(`${prefix}--popover--${alignment}`); + return false; + } + + // Check if popover is not visible to bottom of screen + if ( + rect.y + (rect.height - 16) > + document.documentElement.clientHeight + ) { + popover.current.classList.remove(`${prefix}--popover--${alignment}`); + return false; + } - // Check if popover is not visible to bottom of screen - if (rect.y + (rect.height - 16) > document.documentElement.clientHeight) { popover.current.classList.remove(`${prefix}--popover--${alignment}`); - return false; + return true; } - popover.current.classList.remove(`${prefix}--popover--${alignment}`); - return true; - } + let alignment: PopoverAlignment | null = null; - let alignment: PopoverAlignment | null = null; + for (let i = 0; i < options.length; i++) { + const option = options[i]; - for (let i = 0; i < options.length; i++) { - const option = options[i]; - - if (isVisible(option)) { - alignment = option; - break; + if (isVisible(option)) { + alignment = option; + break; + } } - } - if (alignment) { - setAutoAligned(true); - setAutoAlignment(alignment); - } - }, [autoAligned, align, autoAlign, prefix, open, isTabTip]); - - const mappedChildren = React.Children.map(children, (child) => { - const item = child as any; - - if (item?.type === 'button') { - const { className } = item.props; - const tabTipClasses = cx( - `${prefix}--popover--tab-tip__button`, - className - ); - return React.cloneElement(item, { - className: tabTipClasses, - }); - } else { - return item; - } - }); - - const BaseComponentAsAny = BaseComponent as any; + if (alignment) { + setAutoAligned(true); + setAutoAlignment(alignment); + } + }, [autoAligned, align, autoAlign, prefix, open, isTabTip]); + + const mappedChildren = React.Children.map(children, (child) => { + const item = child as any; + + if (item?.type === 'button') { + const { className } = item.props; + const tabTipClasses = cx( + `${prefix}--popover--tab-tip__button`, + className + ); + return React.cloneElement(item, { + className: tabTipClasses, + }); + } else { + return item; + } + }); - return ( - - - {isTabTip ? mappedChildren : children} - - - ); -} + const BaseComponentAsAny = BaseComponent as any; -export const Popover = React.forwardRef(PopoverRenderFunction) as (< - E extends ElementType = 'span' ->( - props: PopoverProps -) => JSX.Element) & { - displayName?: string | undefined; - propTypes?: WeakValidationMap> | undefined; -}; + return ( + + + {isTabTip ? mappedChildren : children} + + + ); + } +); // Note: this displayName is temporarily set so that Storybook ArgTable // correctly displays the name of this component