react-dom#createPortal TypeScript Examples

The following examples show how to use react-dom#createPortal. 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: index.tsx    From amazon-chime-sdk-smart-video-sending-demo with Apache License 2.0 7 votes vote down vote up
Portal:FC<PortalProps> = ({ children, rootId }) => {
    let el: HTMLElement | null;
    let newRoot: HTMLElement | null;
    const [mount, setMount] = useState<any>();

    useEffect(() => {
      if(!!rootId) {
        el = document.getElementById(rootId)
      }

      if (!!el) {
          setMount(el);
      } else {
        newRoot = document.createElement('div');
        document.body.appendChild(newRoot);
        setMount(newRoot);
      }
      return () => {
        !!newRoot && newRoot.remove();
      };
    }, [rootId]);

    return mount ? createPortal(children, mount) : null
}
Example #2
Source File: BottomDrawer.tsx    From pancake-toolkit with GNU General Public License v3.0 6 votes vote down vote up
BottomDrawer: React.FC<BottomDrawerProps> = ({ content, isOpen, setIsOpen }) => {
  const ref = useRef<HTMLDivElement>(null);
  const shouldRender = useDelayedUnmount(isOpen, 350);
  const { isMobile } = useMatchBreakpoints();

  useOnClickOutside(ref, () => setIsOpen(false));

  if (!shouldRender || !isMobile) {
    return null;
  }

  const portal = getPortalRoot();

  return (
    <>
      {portal
        ? createPortal(
            <>
              <Overlay />
              <DrawerContainer ref={ref} isUnmounting={!isOpen}>
                <Box position="absolute" right="16px" top="0">
                  <IconButton variant="text" onClick={() => setIsOpen(false)}>
                    <CloseIcon />
                  </IconButton>
                </Box>
                {content}
              </DrawerContainer>
            </>,
            portal
          )
        : null}
    </>
  );
}
Example #3
Source File: SlideDrawer.tsx    From test with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
SlideDrawer = ({ children, visible, lockScroll = true, direction = '', ...props }) => {
  if (typeof window !== 'undefined') {
    const [open, setOpen] = useState(false)
    const [close, setClose] = useState(false)

    useEffect(() => {
      if (visible) setOpen(true)
    }, [visible])

    if (!visible && open) {
      setOpen(false)
      setClose(true)
      setTimeout(() => {
        setClose(false)
      }, 300)
    }

    if (visible || close) {
      return createPortal(
        <ScrollLock isActive={lockScroll}>
          <StyledContainer
            animate={open ? 'visible' : 'hidden'}
            variants={variants}
            custom={direction}
            {...props}
          >
            {children}
          </StyledContainer>
        </ScrollLock>,
        document.body,
      )
    }
  }
  return null
}
Example #4
Source File: portal.tsx    From basement-grotesque with SIL Open Font License 1.1 6 votes vote down vote up
Portal: React.FC<Props> = ({
  children,
  id = 'my-awesome-portal',
  onMount
}) => {
  const ref = useRef<HTMLElement>()
  const [isMounted, setIsMounted] = useState(false)

  useEffect(() => {
    let portal: HTMLElement | undefined = undefined
    const existingPortal = document.getElementById(id) as HTMLElement | null
    if (existingPortal) {
      portal = existingPortal
    } else {
      portal = document.createElement('div')
      portal.id = id
      document.body.appendChild(portal)
    }
    ref.current = portal
    setIsMounted(true)
  }, [id])

  useEffect(() => {
    if (isMounted && onMount) onMount()
  }, [isMounted, onMount])

  return isMounted && ref.current ? createPortal(children, ref.current) : null
}
Example #5
Source File: TransactionDetailModal.tsx    From raspiblitz-web with MIT License 6 votes vote down vote up
TransactionDetailModal: FC<Props> = ({ transaction, close }) => {
  const { t } = useTranslation();

  // prevent error when closing via 'Esc' key
  if (!transaction) {
    return <></>;
  }

  const { category } = transaction;

  return createPortal(
    <ModalDialog close={close}>
      <section className="flex flex-col">
        <h4 className="font-extrabold">{t("tx.tx_details")}</h4>
        {category === "onchain" && <OnchainDetails details={transaction} />}
        {category === "ln" && <LNDetails details={transaction} />}
      </section>
    </ModalDialog>,
    MODAL_ROOT
  );
}
Example #6
Source File: index.tsx    From rocketredis with MIT License 6 votes vote down vote up
ToastContainer: React.FC<ToastContainerProps> = ({ toasts }) => {
  const visibleToasts = useMemo(() => {
    if (toasts.length > 5) {
      return toasts.slice(toasts.length - 5, toasts.length)
    }

    return toasts
  }, [toasts])

  const transitions = useTransition(visibleToasts, toast => toast.id, {
    from: { right: '-120%' },
    enter: { right: '0%' },
    leave: { right: '-120%' },
    config: {
      duration: 200
    }
  })

  return createPortal(
    <Container>
      {transitions.map(({ item, key, props }) => (
        <Toast key={key} style={props} toast={item} />
      ))}
    </Container>,
    document.body
  )
}
Example #7
Source File: usePortal.ts    From ebs-design with MIT License 6 votes vote down vote up
usePortal = (id = 'portal') => {
  const wrapperRef = useRef<HTMLElement | null>(document.getElementById(id));

  if (wrapperRef.current === null && typeof document !== 'undefined') {
    const div = document.createElement('div');
    div.id = id;

    wrapperRef.current = div;
  }

  useLayoutEffect(() => {
    const wrapper = wrapperRef.current;

    if (!wrapper || typeof document === 'undefined') {
      return;
    }

    document.body.appendChild(wrapper);
  }, []);

  return (children) => wrapperRef.current && createPortal(children, wrapperRef.current);
}
Example #8
Source File: Modal.tsx    From substrate-api-explorer with Apache License 2.0 6 votes vote down vote up
Modal = ({ onClose, children, className = '', style }: Props) =>
  createPortal(
    <S.Wrapper className={className} style={style}>
      <S.Content>
        <S.Close src="/icons/close.svg" onClick={onClose}>
          <img src="/icons/close.svg" alt="x" />
        </S.Close>
        {children}
      </S.Content>
      <S.Dimmer onClick={onClose} />
    </S.Wrapper>,
    document.body
  )
Example #9
Source File: DraggableOverlay.tsx    From dnd-kit with MIT License 6 votes vote down vote up
export function DraggableOverlay({
  axis,
  dropAnimation = dropAnimationConfig,
}: Props) {
  const {active} = useDndContext();

  return createPortal(
    <DragOverlay dropAnimation={dropAnimation}>
      {active ? <Draggable axis={axis} dragging dragOverlay /> : null}
    </DragOverlay>,
    document.body
  );
}
Example #10
Source File: Modal.tsx    From gear-js with GNU General Public License v3.0 6 votes vote down vote up
Modal = ({ heading, close, children, className }: Props) => {
  const [root, setRoot] = useState<HTMLDivElement>();
  const bodyClassName = clsx(styles.body, className);

  const handleOverlayClick = ({ target, currentTarget }: MouseEvent) => {
    if (target === currentTarget) close();
  };

  useEffect(() => {
    const div = document.createElement('div');
    div.id = 'modal-root';
    document.body.appendChild(div);
    setRoot(div);

    return () => {
      document.body.removeChild(div);
    };
  }, []);

  const component = (
    <div className={styles.overlay} onClick={handleOverlayClick} data-testid="overlay">
      <div className={styles.modal} data-testid="modal">
        <Button className={styles.button} icon={icon} color="transparent" onClick={close} />
        <h3 className={styles.heading}>{heading}</h3>
        {children && (
          <div className={bodyClassName} data-testid="body">
            {children}
          </div>
        )}
      </div>
    </div>
  );

  return root ? createPortal(component, root) : null;
}
Example #11
Source File: ModalContainer.controller.tsx    From tezos-link with Apache License 2.0 6 votes vote down vote up
ModalContainer = ({ children }: ModalProps) => {
  const modalRoot = document.getElementById('modal')
  const element = document.createElement('div')

  useEffect(() => {
    // @ts-ignore
    modalRoot.appendChild(element)

    return function cleanup() {
      // @ts-ignore
      modalRoot.removeChild(element)
    }
  })

  return createPortal(children, element)
}
Example #12
Source File: portal.tsx    From react-web-share with MIT License 6 votes vote down vote up
PortalComponent: any = ({ children }: any) => {
  const el = document.createElement("div");

  React.useEffect(() => {
    document.body.appendChild(el);
    return () => {
      document.body.removeChild(el);
    };
  }, [el]);

  return createPortal(children, el);
}
Example #13
Source File: Marker.tsx    From meshtastic-web with GNU General Public License v3.0 6 votes vote down vote up
Marker = ({
  children,
  center,
  ...props
}: MarkerProps): JSX.Element => {
  const { map } = useMapbox();
  const ref = useRef<HTMLDivElement>(document.createElement('div'));

  const addMarker = useCallback((): void => {
    if (map) {
      const marker = new MapboxMarker(ref.current, props).setLngLat(center);
      marker.addTo(map);
    }
  }, [map, center, props]);

  useEffect(() => {
    map?.on('load', () => {
      addMarker();
    });
  }, [addMarker, map]);

  useEffect(() => {
    if (map?.loaded()) {
      addMarker();
    }
  }, [addMarker, map]);

  <div ref={ref}>{children}</div>;

  return createPortal(children, ref.current);
}
Example #14
Source File: Modal.tsx    From jobsgowhere with MIT License 6 votes vote down vote up
Modal: React.FC<Props> = ({ id, category, onHide }) => {
  const [modalNode, setModalNode] = React.useState<HTMLDivElement | null>(null);
  React.useEffect(() => {
    const node = document.createElement("div");
    document.body.appendChild(node);
    setModalNode(node);
  }, []);

  function markup() {
    return (
      <ModalBackground>
        <ModalContainer>
          <ModalTitle>Delete Post</ModalTitle>
          <ModalDescription>
            Posts that are deleted can never be recovered. Do you want to continue?
          </ModalDescription>
          <Buttons>
            <Button fullWidth onClick={onHide}>
              Cancel
            </Button>
            <Button
              fullWidth
              primary
              onClick={() => {
                onHide();
                handleDeletePost(id, category);
              }}
            >
              Delete
            </Button>
          </Buttons>
        </ModalContainer>
      </ModalBackground>
    );
  }
  if (!modalNode) return null;
  return createPortal(markup(), modalNode);
}
Example #15
Source File: Portal.tsx    From mantine with MIT License 6 votes vote down vote up
export function Portal(props: PortalProps): ReactPortal {
  const { children, zIndex, target, className, position } = useMantineDefaultProps(
    'Portal',
    defaultProps,
    props
  );

  const theme = useMantineTheme();
  const [mounted, setMounted] = useState(false);
  const ref = useRef<HTMLElement>();

  useIsomorphicEffect(() => {
    setMounted(true);
    ref.current = !target
      ? document.createElement('div')
      : typeof target === 'string'
      ? document.querySelector(target)
      : target;

    if (!target) {
      document.body.appendChild(ref.current);
    }

    return () => {
      !target && document.body.removeChild(ref.current);
    };
  }, [target]);

  if (!mounted) {
    return null;
  }

  return createPortal(
    <div className={className} dir={theme.dir} style={{ position: position as any, zIndex }}>
      {children}
    </div>,
    ref.current
  );
}
Example #16
Source File: ClientOnlyPortal.ts    From dh-web with GNU General Public License v3.0 6 votes vote down vote up
export default function ClientOnlyPortal(
    { children, selector }: ClientOnlyPortalProperties,
): ReactPortal {
    const reference = useRef();
    const [mounted, setMounted] = useState(false);

    useEffect(() => {
        reference.current = document.querySelector(selector);
        setMounted(true);
    }, [selector]);

    // eslint-disable-next-line unicorn/no-null
    return mounted ? createPortal(children, reference.current) : null;
}
Example #17
Source File: App.tsx    From netify with BSD 2-Clause "Simplified" License 6 votes vote down vote up
App = memo(function App() {
	const composeShown = useStore($ruleComposeShown);
	const editorShown = !!useStore($ruleEditorShownFor);
	const detailsShown = !!useStore($ruleDetailsShownFor);

	const modalTarget = useMemo(() => document.getElementById('modal-root')!, []);

	return (
		<div className={styles.root}>
			<div className={styles.header}>
				<AppHeader />
			</div>
			<div className={styles.content}>
				<AppSections
					mainSection={<Rules />}
					secondarySection={<Logs />}
					floatingSection={detailsShown ? <RuleViewer /> : null}
				/>
			</div>

			{composeShown && createPortal(<RuleCompose />, modalTarget)}

			{editorShown && createPortal(<RuleEditor />, modalTarget)}
		</div>
	);
})
Example #18
Source File: Portal.tsx    From crowdsource-dataplatform with MIT License 6 votes vote down vote up
Portal = ({ children }: PortalProps) => {
  let portalRoot: HTMLElement | null = null;
  let el: Element | undefined;

  /* istanbul ignore next */
  if (typeof window !== 'undefined') {
    portalRoot = document.getElementById('portal');

    if (!portalRoot) {
      portalRoot = document.createElement('div');
      portalRoot.setAttribute('id', 'portal');
      document.body.appendChild(portalRoot);
    }

    el = document.createElement('div');
  }

  useEffect(() => {
    portalRoot?.appendChild(el!!);

    return () => {
      portalRoot?.removeChild(el!!);
    };
  }, [el, portalRoot]);

  return createPortal(children, el!!);
}
Example #19
Source File: usePortal.tsx    From react-amap with MIT License 6 votes vote down vote up
usePortal = () => {
  const [container] = React.useState<HTMLDivElement>(() => {
    const el = document.createElement('div');
    return el;
  });
  const [portal, setPortal] = useState<State>({
    render: () => null,
    remove: () => null,
  });

  const ReactCreatePortal = React.useCallback<(elmm: HTMLDivElement) => State>((elmm) => {
    const Portal: State['render'] = ({ children }) => {
      if (!children) return null;
      return createPortal(children, elmm);
    };
    const remove: State['remove'] = (elm) => {
      elm && unmountComponentAtNode(elm);
    };
    return { render: Portal, remove };
  }, []);

  useEffect(() => {
    if (container) portal.remove();
    const newPortal = ReactCreatePortal(container);
    setPortal(newPortal);
    return () => {
      newPortal.remove(container);
    };
  }, [container]);

  return { Portal: portal.render, container };
}
Example #20
Source File: index.tsx    From easy-email with MIT License 6 votes vote down vote up
IframeComponent = ({ children, title, windowRef, ...props }: Props) => {
  const [mountNode, setMountNode] = useState(null);

  const onLoad: React.ReactEventHandler<HTMLIFrameElement> = (evt) => {
    const contentWindow = (evt.target as any)?.contentWindow;
    if (!contentWindow) return;
    windowRef?.(contentWindow);
    const innerBody = contentWindow.document.body;
    innerBody.style.backgroundColor = 'transparent';
    setMountNode(innerBody);
  };

  return (
    <iframe
      title={title}
      srcDoc={
        '<!doctype html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"> <head></head> <body> </body> </html>'
      }
      {...(props as any)}
      onLoad={onLoad}
    >
      {mountNode && createPortal(children, mountNode)}
    </iframe>
  );
}
Example #21
Source File: Portal.tsx    From projectboard with MIT License 6 votes vote down vote up
Portal: React.FC<Props> = (props) => {
  let { children } = props;
  let [mounted, setMounted] = useState(false);

  useEffect(() => setMounted(true), []);

  if (!mounted) return null;
  return createPortal(children, document.body);
}
Example #22
Source File: index.tsx    From ChatUI with MIT License 6 votes vote down vote up
Popover: React.FC<PopoverProps> = (props) => {
  const { className, active, target, children, onClose } = props;
  const wrapper = useClickOutside(onClose, 'mousedown');
  const { didMount, isShow } = useMount({ active, ref: wrapper });
  const [style, setStyle] = useState({});

  const updatePos = useCallback(() => {
    if (!wrapper.current) return;

    const targetRect = target.getBoundingClientRect();
    const rect = wrapper.current.getBoundingClientRect();

    setStyle({
      top: `${targetRect.top - rect.height}px`,
      left: `${targetRect.left}px`,
    });
  }, [target, wrapper]);

  useEffect(() => {
    if (wrapper.current) {
      wrapper.current.focus();
      updatePos();
    }
  }, [didMount, updatePos, wrapper]);

  useWindowResize(updatePos);

  if (!didMount) return null;

  return createPortal(
    <div className={clsx('Popover', className, { active: isShow })} ref={wrapper} style={style}>
      <div className="Popover-body">{children}</div>
      <svg className="Popover-arrow" viewBox="0 0 9 5">
        <polygon points="0,0 5,5, 9,0" />
      </svg>
    </div>,
    document.body,
  );
}
Example #23
Source File: modal.tsx    From geist-ui with MIT License 5 votes vote down vote up
ModalComponent: React.FC<React.PropsWithChildren<ModalProps>> = ({
  visible: customVisible,
  onClose,
  children,
  keyboard,
  wrapClassName,
  onContentClick,
  disableBackdropClick,
  positionClassName,
  backdropClassName,
  layerClassName,
}: React.PropsWithChildren<ModalProps> & typeof defaultProps) => {
  const portal = usePortal('modal')
  const { SCALES } = useScale()
  const [, setBodyHidden] = useBodyScroll(null, { delayReset: 300 })
  const [visible, setVisible] = useState<boolean>(false)
  const [withoutActionsChildren, ActionsChildren] = pickChild(children, ModalAction)
  const hasActions = ActionsChildren && React.Children.count(ActionsChildren) > 0
  const closeModal = () => {
    onClose && onClose()
    setVisible(false)
    setBodyHidden(false)
  }

  useEffect(() => {
    if (typeof customVisible === 'undefined') return
    setVisible(customVisible)
    setBodyHidden(customVisible)
  }, [customVisible])

  const { bindings } = useKeyboard(
    () => {
      keyboard && closeModal()
    },
    KeyCode.Escape,
    {
      disableGlobalEvent: true,
    },
  )

  const closeFromBackdrop = () => {
    if (disableBackdropClick) return
    closeModal()
  }

  const modalConfig: ModalConfig = useMemo(
    () => ({
      close: closeModal,
    }),
    [],
  )

  if (!portal) return null
  return createPortal(
    <ModalContext.Provider value={modalConfig}>
      <Backdrop
        onClick={closeFromBackdrop}
        onContentClick={onContentClick}
        visible={visible}
        width={SCALES.width(26)}
        positionClassName={positionClassName}
        backdropClassName={backdropClassName}
        layerClassName={layerClassName}
        {...bindings}>
        <ModalWrapper visible={visible} className={wrapClassName}>
          {withoutActionsChildren}
          {hasActions && <ModalActions>{ActionsChildren}</ModalActions>}
        </ModalWrapper>
      </Backdrop>
    </ModalContext.Provider>,
    portal,
  )
}
Example #24
Source File: Tooltip.tsx    From ebs-design with MIT License 5 votes vote down vote up
Tooltip: React.FC<TooltipProps> = ({
  className,
  bodyClass,
  children,
  title,
  tooltip,
  hideArrow,
  width,
  nowrap,
  inline,
  interactive = true,
  ...tooltipConfig
}) => {
  const { getArrowProps, getTooltipProps, setTooltipRef, setTriggerRef, visible } = usePopperTooltip({
    ...{ ...tooltipConfig, interactive },
  });

  return (
    <div className={cn(`ebs-tooltip`, { [`ebs-tooltip--nowrap`]: nowrap, [`ebs-tooltip--inline`]: inline })}>
      <div className="ebs-tooltip__trigger" ref={setTriggerRef}>
        {children}
      </div>
      {visible &&
        createPortal(
          <div
            ref={setTooltipRef}
            {...getTooltipProps({
              className: cn(`ebs-tooltip__wrapper`, className, { [`ebs-tooltip--nowrap`]: nowrap }),
              style: { width },
            })}
          >
            {!hideArrow && (
              <div
                {...getArrowProps({
                  className: 'ebs-tooltip__arrow',
                })}
              >
                <Icon type="arrow-top" />
              </div>
            )}

            <div className={cn(`ebs-tooltip__body`, bodyClass)}>
              {title && <div className="ebs-tooltip__body-title">{title}</div>}

              {tooltip}
            </div>
          </div>,
          document.body,
        )}
    </div>
  );
}
Example #25
Source File: Modal.tsx    From excalidraw with MIT License 5 votes vote down vote up
Modal = (props: {
  className?: string;
  children: React.ReactNode;
  maxWidth?: number;
  onCloseRequest(): void;
  labelledBy: string;
  theme?: AppState["theme"];
  closeOnClickOutside?: boolean;
}) => {
  const { theme = THEME.LIGHT, closeOnClickOutside = true } = props;
  const modalRoot = useBodyRoot(theme);

  if (!modalRoot) {
    return null;
  }

  const handleKeydown = (event: React.KeyboardEvent) => {
    if (event.key === KEYS.ESCAPE) {
      event.nativeEvent.stopImmediatePropagation();
      event.stopPropagation();
      props.onCloseRequest();
    }
  };

  return createPortal(
    <div
      className={clsx("Modal", props.className)}
      role="dialog"
      aria-modal="true"
      onKeyDown={handleKeydown}
      aria-labelledby={props.labelledBy}
    >
      <div
        className="Modal__background"
        onClick={closeOnClickOutside ? props.onCloseRequest : undefined}
      ></div>
      <div
        className="Modal__content"
        style={{ "--max-width": `${props.maxWidth}px` }}
        tabIndex={0}
      >
        {props.children}
      </div>
    </div>,
    modalRoot,
  );
}
Example #26
Source File: Modal.tsx    From excalidraw-embed with MIT License 5 votes vote down vote up
Modal = (props: {
  className?: string;
  children: React.ReactNode;
  maxWidth?: number;
  onCloseRequest(): void;
  labelledBy: string;
}) => {
  const modalRoot = useBodyRoot();

  const handleKeydown = (event: React.KeyboardEvent) => {
    if (event.key === KEYS.ESCAPE) {
      event.nativeEvent.stopImmediatePropagation();
      props.onCloseRequest();
    }
  };
  return createPortal(
    <div
      className={`Modal ${props.className ?? ""}`}
      role="dialog"
      aria-modal="true"
      onKeyDown={handleKeydown}
      aria-labelledby={props.labelledBy}
    >
      <div className="Modal__background" onClick={props.onCloseRequest}></div>
      <div
        className="Modal__content"
        style={
          {
            "--max-width": `${props.maxWidth}px`,
            maxHeight: "100%",
            overflowY: "scroll",
          } as any
        }
      >
        {props.children}
      </div>
    </div>,
    modalRoot,
  );
}
Example #27
Source File: ngSupport.ts    From frontegg-react with MIT License 5 votes vote down vote up
DOMProxy = {
  createElement,
  createPortal,
  render,
}
Example #28
Source File: BaseMenu.tsx    From vvs-ui with GNU General Public License v3.0 5 votes vote down vote up
BaseMenu: React.FC<BaseMenuProps> = ({ component, options, children, isOpen = false }) => {
  const [targetElement, setTargetElement] = useState<HTMLElement | null>(null);
  const [menuElement, setMenuElement] = useState<HTMLElement | null>(null);
  const placement = options?.placement ?? "bottom";
  const offset = options?.offset ?? [0, 10];
  const padding = options?.padding ?? { left: 16, right: 16 };

  const [isMenuOpen, setIsMenuOpen] = useState(isOpen);

  const toggle = () => {
    setIsMenuOpen((prev) => !prev);
  };

  const open = () => {
    setIsMenuOpen(true);
  };

  const close = () => {
    setIsMenuOpen(false);
  };

  // Allow for component to be controlled
  useEffect(() => {
    setIsMenuOpen(isOpen);
  }, [isOpen, setIsMenuOpen]);

  useEffect(() => {
    const handleClickOutside = ({ target }: Event) => {
      if (target instanceof Node) {
        if (
          menuElement !== null &&
          targetElement !== null &&
          !menuElement.contains(target) &&
          !targetElement.contains(target)
        ) {
          setIsMenuOpen(false);
        }
      }
    };
    if (menuElement !== null) {
      document.addEventListener("click", handleClickOutside);
    }
    return () => {
      document.removeEventListener("click", handleClickOutside);
    };
  }, [menuElement, targetElement]);

  const { styles, attributes } = usePopper(targetElement, menuElement, {
    placement,
    modifiers: [
      { name: "offset", options: { offset } },
      { name: "preventOverflow", options: { padding } },
    ],
  });

  const menu = (
    <div ref={setMenuElement} style={styles.popper} {...attributes.popper}>
      {typeof children === "function" ? children({ toggle, open, close }) : children}
    </div>
  );

  const renderMenu = portalRoot ? createPortal(menu, portalRoot) : menu;

  return (
    <>
      <ClickableElementContainer ref={setTargetElement} onClick={toggle}>
        {component}
      </ClickableElementContainer>
      {isMenuOpen && renderMenu}
    </>
  );
}
Example #29
Source File: color.tsx    From XFlow with MIT License 5 votes vote down vote up
ColorPicker: React.FC<IProps> = props => {
  const { label, value = '', onChange } = props
  const [show, setShow] = useState(false)
  const colorRef = useRef<string>(value)
  const { graphProvider } = useXFlowApp()
  const graphConfig = useRef<IGraphConfig>()
  graphProvider.getGraphOptions().then(x6GraphConfig => {
    graphConfig.current = x6GraphConfig
  })

  const PickContainer = () => {
    return (
      <div className={`${PREFIX}-pick-color-container`}>
        <div className={`${PREFIX}-popover`}>
          <SketchPicker
            onChange={color => {
              colorRef.current = color.hex
            }}
          />
          <div className="foolter">
            <Button
              onClick={() => {
                setShow(false)
              }}
            >
              取消
            </Button>
            <Button
              type="primary"
              onClick={() => {
                onChange?.(colorRef.current)
                setShow(false)
              }}
            >
              确认
            </Button>
          </div>
        </div>
      </div>
    )
  }

  const createPickColorContainer = (visible: boolean) => {
    const existElements = document.getElementsByClassName(`${PREFIX}-pick-color-container`)
    if (existElements.length) {
      Array.from(existElements).forEach(ele => {
        ele.parentNode?.removeChild(ele)
      })
    }
    if (!visible) {
      return
    }
    const div = document.createElement('div')
    render(createPortal(<PickContainer />, document.getElementsByTagName('body')[0]), div)
  }

  return (
    <div className="group">
      {label && <label>{label}</label>}
      <div
        className={`${PREFIX}-color-container`}
        onClick={() => {
          setShow(true)
        }}
      >
        <div
          className={`${PREFIX}-color`}
          style={{
            backgroundColor: value,
            height: '100%',
          }}
        />
      </div>
      {createPickColorContainer(show)}
    </div>
  )
}