render()

in packages/eui/src/components/popover/popover.tsx [610:799]


  render() {
    const {
      anchorPosition,
      button,
      insert,
      isOpen,
      ownFocus,
      children,
      className,
      closePopover,
      panelClassName,
      panelPaddingSize,
      panelProps,
      panelRef,
      panelStyle,
      popoverScreenReaderText,
      popoverRef,
      hasArrow,
      arrowChildren,
      repositionOnScroll,
      repositionToCrossAxis,
      zIndex,
      attachToAnchor,
      display,
      offset,
      onPositionChange,
      buffer,
      'aria-label': ariaLabel,
      'aria-labelledby': ariaLabelledBy,
      'aria-live': ariaLiveProp,
      container,
      focusTrapProps,
      initialFocus: initialFocusProp,
      tabIndex: _tabIndexProp,
      ...rest
    } = this.props;
    const tabIndexProp = panelProps?.tabIndex ?? _tabIndexProp;

    const styles = euiPopoverStyles();
    const popoverStyles = [styles.euiPopover, { display, label: display }];
    const classes = classNames(
      'euiPopover',
      {
        'euiPopover-isOpen': this.state.isOpening,
      },
      className
    );

    const showArrow = hasArrow && !attachToAnchor;

    let panel;

    if (!this.state.suppressingPopover && (isOpen || this.state.isClosing)) {
      let tabIndex = tabIndexProp;
      let initialFocus = initialFocusProp;
      let ariaDescribedby;
      let ariaLive: HTMLAttributes<any>['aria-live'];

      const panelAriaModal = panelProps?.hasOwnProperty('aria-modal')
        ? panelProps['aria-modal']
        : 'true';
      const panelRole = panelProps?.hasOwnProperty('role')
        ? panelProps.role
        : 'dialog';

      if (ownFocus || panelAriaModal !== 'true') {
        tabIndex = tabIndexProp ?? 0;
        ariaLive = 'off';
        if (!initialFocus) {
          initialFocus = () => this.panel!;
        }
      } else {
        ariaLive = ariaLiveProp ?? 'assertive';
      }

      let focusTrapScreenReaderText;
      if (ownFocus || popoverScreenReaderText) {
        ariaDescribedby = this.descriptionId;

        focusTrapScreenReaderText = (
          <EuiScreenReaderOnly>
            <p id={this.descriptionId}>
              {ownFocus && (
                <EuiI18n
                  token="euiPopover.screenReaderAnnouncement"
                  default="You are in a dialog. Press Escape, or tap/click outside the dialog to close."
                />
              )}
              {popoverScreenReaderText}
            </p>
          </EuiScreenReaderOnly>
        );
      }

      const returnFocus = this.state.isOpenStable ? returnFocusConfig : false;

      panel = (
        <EuiPortal {...(insert && { insert })}>
          <EuiFocusTrap
            clickOutsideDisables={true}
            onClickOutside={this.onClickOutside}
            returnFocus={returnFocus} // Ignore temporary state of indecisive focus
            initialFocus={initialFocus}
            onEscapeKey={this.onEscapeKey}
            disabled={
              !ownFocus || !this.state.isOpenStable || this.state.isClosing
            }
            {...focusTrapProps}
          >
            <EuiPopoverPanel
              {...(panelProps as EuiPopoverPanelProps)}
              panelRef={this.panelRef}
              isOpen={this.state.isOpening}
              position={this.state.arrowPosition}
              isAttached={attachToAnchor}
              className={classNames(panelClassName, panelProps?.className)}
              hasShadow={false}
              paddingSize={panelPaddingSize}
              tabIndex={tabIndex}
              aria-live={ariaLive}
              role={panelRole}
              aria-label={ariaLabel}
              aria-labelledby={ariaLabelledBy}
              aria-modal={panelAriaModal}
              aria-describedby={ariaDescribedby}
              style={{
                ...this.state.popoverStyles,
                // Adding `will-change` to reduce risk of a blurry animation in Chrome 86+
                willChange: !this.state.isOpenStable
                  ? 'transform, opacity'
                  : undefined,
              }}
            >
              {showArrow && this.state.arrowPosition && (
                <EuiPopoverArrow
                  position={this.state.arrowPosition}
                  style={this.state.arrowStyles}
                >
                  {arrowChildren}
                </EuiPopoverArrow>
              )}
              {focusTrapScreenReaderText}
              <EuiMutationObserver
                observerOptions={{
                  attributes: true, // element attribute changes
                  childList: true, // added/removed elements
                  characterData: true, // text changes
                  subtree: true, // watch all child elements
                }}
                onMutation={this.onMutation}
              >
                {(mutationRef) => <div ref={mutationRef}>{children}</div>}
              </EuiMutationObserver>
            </EuiPopoverPanel>
          </EuiFocusTrap>
        </EuiPortal>
      );
    }

    // react-focus-on and related do not register outside click detection
    // when disabled, so we still need to conditionally check for that ourselves
    if (ownFocus) {
      return (
        <div
          css={popoverStyles}
          className={classes}
          ref={this.popoverRef}
          {...rest}
        >
          {button instanceof HTMLElement ? null : button}
          {panel}
        </div>
      );
    } else {
      return (
        <EuiOutsideClickDetector onOutsideClick={this.closePopover}>
          <div
            css={popoverStyles}
            className={classes}
            ref={this.popoverRef}
            onKeyDown={this.onKeyDown}
            {...rest}
          >
            {button instanceof HTMLElement ? null : button}
            {panel}
          </div>
        </EuiOutsideClickDetector>
      );
    }
  }