@popperjs/core#Modifier TypeScript Examples

The following examples show how to use @popperjs/core#Modifier. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Popup.tsx    From posthog-foss with MIT License 4 votes vote down vote up
/** This is a custom popup control that uses `react-popper` to position DOM nodes */
export function Popup({
    children,
    overlay,
    visible,
    onClickOutside,
    onClickInside,
    placement = 'bottom-start',
    fallbackPlacements = ['bottom-end', 'top-start', 'top-end'],
    className,
    actionable = false,
    sameWidth = false,
}: PopupProps): JSX.Element {
    const [referenceElement, setReferenceElement] = useState<HTMLDivElement | null>(null)
    const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null)

    const popupId = useMemo(() => uniqueMemoizedIndex++, [])
    const localRefs = [popperElement, referenceElement]

    useOutsideClickHandler(localRefs, (event) => visible && onClickOutside?.(event), [visible])

    const modifiers = useMemo<Partial<Modifier<any, any>>[]>(
        () => [
            {
                name: 'offset',
                options: {
                    offset: [0, 4],
                },
            },
            fallbackPlacements
                ? {
                      name: 'flip',
                      options: {
                          fallbackPlacements: fallbackPlacements,
                      },
                  }
                : {},
            sameWidth
                ? {
                      name: 'sameWidth',
                      enabled: true,
                      fn: ({ state }) => {
                          state.styles.popper.width = `${state.rects.reference.width}px`
                      },
                      phase: 'beforeWrite',
                      requires: ['computeStyles'],
                  }
                : {},
        ],
        []
    )

    const { styles, attributes } = usePopper(referenceElement, popperElement, {
        placement: placement,
        modifiers,
    })

    const clonedChildren =
        typeof children === 'function'
            ? children({
                  setRef: setReferenceElement as (ref: HTMLElement | null) => void,
              })
            : React.Children.toArray(children).map((child) =>
                  React.cloneElement(child as ReactElement, {
                      ref: setReferenceElement,
                  })
              )

    return (
        <>
            {clonedChildren}
            {visible
                ? ReactDOM.createPortal(
                      <div
                          className={clsx('Popup', actionable && 'Popup--actionable', className)}
                          ref={setPopperElement}
                          style={styles.popper}
                          onClick={onClickInside}
                          {...attributes.popper}
                      >
                          <PopupContext.Provider value={popupId}>{overlay}</PopupContext.Provider>
                      </div>,
                      document.querySelector('body') as HTMLElement
                  )
                : null}
        </>
    )
}
Example #2
Source File: index.tsx    From exevo-pan with The Unlicense 4 votes vote down vote up
Popover = ({
  className,
  children,
  content,
  placement = 'top',
  trigger = 'hover',
  visible,
  offset = [0, 0],
  ...props
}: PopoverProps) => {
  const {
    translations: { common },
  } = useTranslations()

  const [isVisible, setVisible] = useState<boolean>(visible ?? false)
  const derivedVisibility =
    trigger === 'none' ? visible ?? isVisible : isVisible

  const [referenceElement, setReferenceElement] =
    useState<PopperReferenceElement>(null)

  const [popperElement, setPopperElement] =
    useState<PopperReferenceElement>(null)

  const modifiers: Partial<Modifier<string, Record<string, unknown>>>[] =
    useMemo(
      () => [
        {
          name: 'flip',
          enabled: true,
          options: {
            allowedAutoPlacements: ['top', 'bottom'],
          },
        },
        {
          name: 'offset',
          options: {
            offset,
          },
        },
      ],
      [offset],
    )

  const { styles, attributes } = usePopper(referenceElement, popperElement, {
    placement,
    modifiers,
  })

  const triggers = useMemo(() => {
    switch (trigger) {
      case 'click':
        return {
          tabIndex: 0,
          onClick: () => setVisible((prev) => !prev),
          onKeyPress: (event: React.KeyboardEvent) => {
            if (checkKeyboardTrigger(event.code)) {
              event.preventDefault()
              setVisible((prev) => !prev)
            }
          },
        }
      case 'hover':
        return {
          tabIndex: 0,
          onMouseEnter: () => setVisible(true),
          onMouseLeave: () => setVisible(false),
          onFocus: () => setVisible(true),
          onBlur: () => setVisible(false),
        }
      case 'none':
      default:
        return {}
    }
  }, [trigger])

  const increaseHoverArea = trigger === 'hover' && derivedVisibility

  return (
    <>
      <div
        ref={setReferenceElement}
        className="child:z-1 child:relative relative inline-block cursor-pointer"
        {...triggers}
      >
        {increaseHoverArea && (
          <div
            role="none"
            className="top-1/2 left-1/2"
            style={{
              position: 'absolute',
              transform: 'translate(-50%, -50%)',
              width: `calc(100% + ${offset[0] + 8}px)`,
              height: `calc(100% + ${offset[1] + 8}px)`,
            }}
          />
        )}

        {children}
      </div>

      {derivedVisibility && (
        <div
          ref={setPopperElement}
          style={styles.popper}
          {...attributes.popper}
          className={clsx(
            'z-51 animate-fadeIn',
            className,
            attributes.popper?.className,
          )}
          {...props}
          {...(trigger === 'hover' ? { ...triggers, tabIndex: undefined } : {})}
        >
          {Children.map(content, (contentChild) => {
            if (!isValidElement(contentChild)) return contentChild
            if (typeof contentChild.type === 'string') return contentChild

            return cloneElement(contentChild, {
              'aria-hidden': false,
              disabled: false,
              hidden: false,
            })
          })}
        </div>
      )}

      {trigger === 'click' && derivedVisibility && (
        <button
          type="button"
          className="bg-backdrop animate-fadeIn fixed top-0 left-0 z-50 h-screen w-screen"
          aria-label={common.PopoverCloseLabel}
          onClick={() => setVisible(false)}
        />
      )}
    </>
  )
}