Fix button tooltips
This commit is contained in:
		
					parent
					
						
							
								abae58489c
							
						
					
				
			
			
				commit
				
					
						d7d38c1ba9
					
				
			
		
					 8 changed files with 105 additions and 174 deletions
				
			
		| 
						 | 
				
			
			@ -1,32 +1,46 @@
 | 
			
		|||
import React, { forwardRef } from "react";
 | 
			
		||||
import React, { forwardRef, useRef } from "react";
 | 
			
		||||
import { useTooltipTriggerState } from "@react-stately/tooltip";
 | 
			
		||||
import { FocusableProvider } from "@react-aria/focus";
 | 
			
		||||
import { useTooltipTrigger, useTooltip } from "@react-aria/tooltip";
 | 
			
		||||
import { mergeProps, useObjectRef } from "@react-aria/utils";
 | 
			
		||||
import styles from "./Tooltip.module.css";
 | 
			
		||||
import classNames from "classnames";
 | 
			
		||||
import { OverlayContainer, useOverlayPosition } from "@react-aria/overlays";
 | 
			
		||||
 | 
			
		||||
export function Tooltip({ position, state, ...props }) {
 | 
			
		||||
export const Tooltip = forwardRef(
 | 
			
		||||
  ({ position, state, className, ...props }, ref) => {
 | 
			
		||||
    let { tooltipProps } = useTooltip(props, state);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div
 | 
			
		||||
      className={classNames(styles.tooltip, styles[position || "bottom"])}
 | 
			
		||||
        className={classNames(styles.tooltip, className)}
 | 
			
		||||
        {...mergeProps(props, tooltipProps)}
 | 
			
		||||
        ref={ref}
 | 
			
		||||
      >
 | 
			
		||||
        {props.children}
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export const TooltipTrigger = forwardRef(({ children, ...rest }, ref) => {
 | 
			
		||||
  const tooltipState = useTooltipTriggerState(rest);
 | 
			
		||||
  const triggerRef = useObjectRef(ref);
 | 
			
		||||
  const overlayRef = useRef();
 | 
			
		||||
  const { triggerProps, tooltipProps } = useTooltipTrigger(
 | 
			
		||||
    rest,
 | 
			
		||||
    tooltipState,
 | 
			
		||||
    triggerRef
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const { overlayProps } = useOverlayPosition({
 | 
			
		||||
    placement: rest.placement || "top",
 | 
			
		||||
    targetRef: triggerRef,
 | 
			
		||||
    overlayRef,
 | 
			
		||||
    isOpen: tooltipState.isOpen,
 | 
			
		||||
    offset: 5,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  if (
 | 
			
		||||
    !Array.isArray(children) ||
 | 
			
		||||
    children.length > 2 ||
 | 
			
		||||
| 
						 | 
				
			
			@ -40,13 +54,20 @@ export const TooltipTrigger = forwardRef(({ children, ...rest }, ref) => {
 | 
			
		|||
  const [tooltipTrigger, tooltip] = children;
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={styles.tooltipContainer}>
 | 
			
		||||
      <tooltipTrigger.type
 | 
			
		||||
        {...mergeProps(triggerProps, tooltipTrigger.props, rest)}
 | 
			
		||||
        ref={triggerRef}
 | 
			
		||||
      />
 | 
			
		||||
      {tooltipState.isOpen && tooltip({ state: tooltipState, ...tooltipProps })}
 | 
			
		||||
    </div>
 | 
			
		||||
    <FocusableProvider ref={triggerRef} {...triggerProps}>
 | 
			
		||||
      {<tooltipTrigger.type {...mergeProps(tooltipTrigger.props, rest)} />}
 | 
			
		||||
      {tooltipState.isOpen && (
 | 
			
		||||
        <OverlayContainer>
 | 
			
		||||
          <Tooltip
 | 
			
		||||
            state={tooltipState}
 | 
			
		||||
            {...mergeProps(tooltipProps, overlayProps)}
 | 
			
		||||
            ref={overlayRef}
 | 
			
		||||
          >
 | 
			
		||||
            {tooltip()}
 | 
			
		||||
          </Tooltip>
 | 
			
		||||
        </OverlayContainer>
 | 
			
		||||
      )}
 | 
			
		||||
    </FocusableProvider>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,5 @@
 | 
			
		|||
.tooltip {
 | 
			
		||||
  background-color: var(--bgColor2);
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
| 
						 | 
				
			
			@ -9,25 +8,5 @@
 | 
			
		|||
  border-radius: 8px;
 | 
			
		||||
  max-width: 135px;
 | 
			
		||||
  width: max-content;
 | 
			
		||||
  z-index: 1;
 | 
			
		||||
  left: 50%;
 | 
			
		||||
  transform: translateX(-50%);
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tooltip.top {
 | 
			
		||||
  bottom: calc(100% + 6px);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tooltip.bottom {
 | 
			
		||||
  top: calc(100% + 6px);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tooltip.bottomLeft {
 | 
			
		||||
  top: calc(100% + 6px);
 | 
			
		||||
  left: -25%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tooltipContainer {
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,7 +62,7 @@ export function UserMenu({
 | 
			
		|||
 | 
			
		||||
  return (
 | 
			
		||||
    <PopoverMenuTrigger placement="bottom right">
 | 
			
		||||
      <TooltipTrigger>
 | 
			
		||||
      <TooltipTrigger placement="bottom left">
 | 
			
		||||
        <Button variant="icon" className={styles.userButton}>
 | 
			
		||||
          {isAuthenticated && !isPasswordlessUser ? (
 | 
			
		||||
            <Avatar
 | 
			
		||||
| 
						 | 
				
			
			@ -75,11 +75,7 @@ export function UserMenu({
 | 
			
		|||
            <UserIcon />
 | 
			
		||||
          )}
 | 
			
		||||
        </Button>
 | 
			
		||||
        {(props) => (
 | 
			
		||||
          <Tooltip position="bottomLeft" {...props}>
 | 
			
		||||
            Profile
 | 
			
		||||
          </Tooltip>
 | 
			
		||||
        )}
 | 
			
		||||
        {() => "Profile"}
 | 
			
		||||
      </TooltipTrigger>
 | 
			
		||||
      {(props) => (
 | 
			
		||||
        <Menu {...props} label="User menu" onAction={onAction}>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,25 +76,13 @@ export const Button = forwardRef(
 | 
			
		|||
  }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export function ButtonTooltip({ className, children }) {
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={classNames(styles.buttonTooltip, className)}>
 | 
			
		||||
      {children}
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function MicButton({ muted, ...rest }) {
 | 
			
		||||
  return (
 | 
			
		||||
    <TooltipTrigger>
 | 
			
		||||
      <Button variant="toolbar" {...rest} off={muted}>
 | 
			
		||||
        {muted ? <MuteMicIcon /> : <MicIcon />}
 | 
			
		||||
      </Button>
 | 
			
		||||
      {(props) => (
 | 
			
		||||
        <Tooltip position="top" {...props}>
 | 
			
		||||
          {muted ? "Unmute microphone" : "Mute microphone"}
 | 
			
		||||
        </Tooltip>
 | 
			
		||||
      )}
 | 
			
		||||
      {() => (muted ? "Unmute microphone" : "Mute microphone")}
 | 
			
		||||
    </TooltipTrigger>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -105,11 +93,7 @@ export function VideoButton({ muted, ...rest }) {
 | 
			
		|||
      <Button variant="toolbar" {...rest} off={muted}>
 | 
			
		||||
        {muted ? <DisableVideoIcon /> : <VideoIcon />}
 | 
			
		||||
      </Button>
 | 
			
		||||
      {(props) => (
 | 
			
		||||
        <Tooltip position="top" {...props}>
 | 
			
		||||
          {muted ? "Turn on camera" : "Turn off camera"}
 | 
			
		||||
        </Tooltip>
 | 
			
		||||
      )}
 | 
			
		||||
      {() => (muted ? "Turn on camera" : "Turn off camera")}
 | 
			
		||||
    </TooltipTrigger>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -120,11 +104,7 @@ export function ScreenshareButton({ enabled, className, ...rest }) {
 | 
			
		|||
      <Button variant="toolbar" {...rest} on={enabled}>
 | 
			
		||||
        <ScreenshareIcon />
 | 
			
		||||
      </Button>
 | 
			
		||||
      {(props) => (
 | 
			
		||||
        <Tooltip position="top" {...props}>
 | 
			
		||||
          {enabled ? "Stop sharing screen" : "Share screen"}
 | 
			
		||||
        </Tooltip>
 | 
			
		||||
      )}
 | 
			
		||||
      {() => (enabled ? "Stop sharing screen" : "Share screen")}
 | 
			
		||||
    </TooltipTrigger>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -139,11 +119,7 @@ export function HangupButton({ className, ...rest }) {
 | 
			
		|||
      >
 | 
			
		||||
        <HangupIcon />
 | 
			
		||||
      </Button>
 | 
			
		||||
      {(props) => (
 | 
			
		||||
        <Tooltip position="top" {...props}>
 | 
			
		||||
          Leave
 | 
			
		||||
        </Tooltip>
 | 
			
		||||
      )}
 | 
			
		||||
      {() => "Leave"}
 | 
			
		||||
    </TooltipTrigger>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,35 +100,6 @@ limitations under the License.
 | 
			
		|||
  fill: #21262c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.buttonTooltip {
 | 
			
		||||
  display: none;
 | 
			
		||||
  background-color: var(--bgColor2);
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  padding: 8px 10px;
 | 
			
		||||
  color: var(--textColor1);
 | 
			
		||||
  border-radius: 8px;
 | 
			
		||||
  max-width: 135px;
 | 
			
		||||
  width: max-content;
 | 
			
		||||
  z-index: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.buttonTooltip.bottomRight {
 | 
			
		||||
  right: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.toolbarButton:hover .buttonTooltip {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  bottom: calc(100% + 6px);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.iconButton:hover .buttonTooltip {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  top: calc(100% + 6px);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.secondary,
 | 
			
		||||
.copyButton {
 | 
			
		||||
  color: #0dbd8b;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,20 +1,16 @@
 | 
			
		|||
import React, { useRef } from "react";
 | 
			
		||||
import React, { forwardRef, useRef } from "react";
 | 
			
		||||
import styles from "./PopoverMenu.module.css";
 | 
			
		||||
import { useMenuTriggerState } from "@react-stately/menu";
 | 
			
		||||
import { useMenuTrigger } from "@react-aria/menu";
 | 
			
		||||
import { OverlayContainer, useOverlayPosition } from "@react-aria/overlays";
 | 
			
		||||
import { mergeProps, useObjectRef } from "@react-aria/utils";
 | 
			
		||||
import classNames from "classnames";
 | 
			
		||||
import { Popover } from "./Popover";
 | 
			
		||||
 | 
			
		||||
export function PopoverMenuTrigger({
 | 
			
		||||
  children,
 | 
			
		||||
  placement,
 | 
			
		||||
  className,
 | 
			
		||||
  disableOnState,
 | 
			
		||||
  ...rest
 | 
			
		||||
}) {
 | 
			
		||||
export const PopoverMenuTrigger = forwardRef(
 | 
			
		||||
  ({ children, placement, className, disableOnState, ...rest }, ref) => {
 | 
			
		||||
    const popoverMenuState = useMenuTriggerState(rest);
 | 
			
		||||
  const buttonRef = useRef();
 | 
			
		||||
    const buttonRef = useObjectRef(ref);
 | 
			
		||||
    const { menuTriggerProps, menuProps } = useMenuTrigger(
 | 
			
		||||
      {},
 | 
			
		||||
      popoverMenuState,
 | 
			
		||||
| 
						 | 
				
			
			@ -46,8 +42,7 @@ export function PopoverMenuTrigger({
 | 
			
		|||
    return (
 | 
			
		||||
      <div className={classNames(styles.popoverMenuTrigger, className)}>
 | 
			
		||||
        <popoverTrigger.type
 | 
			
		||||
        {...popoverTrigger.props}
 | 
			
		||||
        {...menuTriggerProps}
 | 
			
		||||
          {...mergeProps(popoverTrigger.props, menuTriggerProps)}
 | 
			
		||||
          on={!disableOnState && popoverMenuState.isOpen}
 | 
			
		||||
          ref={buttonRef}
 | 
			
		||||
        />
 | 
			
		||||
| 
						 | 
				
			
			@ -70,3 +65,4 @@ export function PopoverMenuTrigger({
 | 
			
		|||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,11 +16,7 @@ export function GridLayoutMenu({ layout, setLayout }) {
 | 
			
		|||
        <Button variant="icon">
 | 
			
		||||
          {layout === "spotlight" ? <SpotlightIcon /> : <FreedomIcon />}
 | 
			
		||||
        </Button>
 | 
			
		||||
        {(props) => (
 | 
			
		||||
          <Tooltip position="bottom" {...props}>
 | 
			
		||||
            Layout Type
 | 
			
		||||
          </Tooltip>
 | 
			
		||||
        )}
 | 
			
		||||
        {() => "Layout Type"}
 | 
			
		||||
      </TooltipTrigger>
 | 
			
		||||
      {(props) => (
 | 
			
		||||
        <Menu {...props} label="Grid layout menu" onAction={setLayout}>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,15 +38,11 @@ export function OverflowMenu({
 | 
			
		|||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      <PopoverMenuTrigger disableOnState>
 | 
			
		||||
        <TooltipTrigger>
 | 
			
		||||
        <TooltipTrigger placement="top">
 | 
			
		||||
          <Button variant="toolbar">
 | 
			
		||||
            <OverflowIcon />
 | 
			
		||||
          </Button>
 | 
			
		||||
          {(props) => (
 | 
			
		||||
            <Tooltip position="top" {...props}>
 | 
			
		||||
              More
 | 
			
		||||
            </Tooltip>
 | 
			
		||||
          )}
 | 
			
		||||
          {() => "More"}
 | 
			
		||||
        </TooltipTrigger>
 | 
			
		||||
        {(props) => (
 | 
			
		||||
          <Menu {...props} label="More menu" onAction={onAction}>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue