react#MouseEventHandler TypeScript Examples

The following examples show how to use react#MouseEventHandler. 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: WalletModalButton.tsx    From wallet-adapter with Apache License 2.0 6 votes vote down vote up
WalletModalButton: FC<ButtonProps> = ({
    children = 'Select Wallet',
    type = 'primary',
    size = 'large',
    htmlType = 'button',
    onClick,
    ...props
}) => {
    const { setVisible } = useWalletModal();

    const handleClick: MouseEventHandler<HTMLButtonElement> = useCallback(
        (event) => {
            if (onClick) onClick(event);
            if (!event.defaultPrevented) setVisible(true);
        },
        [onClick, setVisible]
    );

    return (
        <Button onClick={handleClick} type={type} size={size} htmlType={htmlType} {...props}>
            {children}
        </Button>
    );
}
Example #2
Source File: ToTopToBottom.tsx    From datart with Apache License 2.0 6 votes vote down vote up
ToTopBtn: FC<{
  fn: MouseEventHandler<HTMLElement> | undefined;
  title: string;
}> = ({ fn, title }) => {
  return (
    <Tooltip title={title}>
      <ToolbarButton onClick={fn} icon={<VerticalAlignTopOutlined />} />
    </Tooltip>
  );
}
Example #3
Source File: ToTopToBottom.tsx    From datart with Apache License 2.0 6 votes vote down vote up
ToBottomBtn: FC<{
  fn: MouseEventHandler<HTMLElement> | undefined;
  title: string;
}> = ({ fn, title }) => {
  return (
    <Tooltip title={title}>
      <ToolbarButton onClick={fn} icon={<VerticalAlignBottomOutlined />} />
    </Tooltip>
  );
}
Example #4
Source File: Tabs.tsx    From slice-machine with Apache License 2.0 6 votes vote down vote up
Icon = ({
  theme,
  onClick,
}: {
  theme: Theme;
  onClick: MouseEventHandler<HTMLButtonElement>;
}) => (
  <SliceMachineIconButton
    size={20}
    Icon={HiOutlineCog}
    label="Edit tab"
    sx={{ cursor: "pointer", color: theme.colors?.icons }}
    onClick={onClick}
  />
)
Example #5
Source File: UndoRedo.tsx    From datart with Apache License 2.0 6 votes vote down vote up
UndoBtn: FC<{
  fn: MouseEventHandler<HTMLElement> | undefined;
  title: string;
}> = ({ fn, title }) => {
  const pastState = useSelector(selectPastState);
  const canUndo = useMemo(() => !!pastState.length, [pastState.length]);
  return (
    <Tooltip title={title}>
      <ToolbarButton disabled={!canUndo} onClick={fn} icon={<UndoOutlined />} />
    </Tooltip>
  );
}
Example #6
Source File: toolbar-button.tsx    From fantasy-editor with MIT License 6 votes vote down vote up
ToolbarButton: FunctionComponent<Props> = forwardRef((props, ref) => {
  const { children, active = false, disabled = false, style, onMouseDown, className } = props;

  const handleMouseDown: MouseEventHandler = event => {
    event.preventDefault();
    onMouseDown?.(event);
  };

  return (
    <button
      disabled={disabled}
      style={style}
      className={classNames('fc-toolbar-btn', disabled ? 'disable' : active ? 'active' : null, className)}
      ref={ref as any}
      onMouseDown={handleMouseDown}
    >
      {children}
    </button>
  );
})
Example #7
Source File: UndoRedo.tsx    From datart with Apache License 2.0 6 votes vote down vote up
RedoBtn: FC<{
  fn: MouseEventHandler<HTMLElement> | undefined;
  title: string;
}> = ({ fn, title }) => {
  const futureState = useSelector(selectFutureState);

  const canRedo = useMemo(() => !!futureState.length, [futureState.length]);
  return (
    <Tooltip title={title}>
      <ToolbarButton disabled={!canRedo} onClick={fn} icon={<RedoOutlined />} />
    </Tooltip>
  );
}
Example #8
Source File: MenuTile.tsx    From yasd with MIT License 6 votes vote down vote up
MenuTile: React.FC<MenuTileProps> = (props) => {
  const handleClick: MouseEventHandler = (e) => {
    if (props.onClick) {
      props.onClick(e)
    }
  }

  return (
    <div
      onClick={handleClick}
      css={[
        props.onClick &&
          tw`cursor-pointer transform transition-transform duration-100 active:scale-95`,
      ]}
    >
      <Card
        css={[
          css`
            user-select: none;
            min-height: 8rem;
          `,
          tw`p-4 border-none shadow-sm bg-gray-100 transition-colors duration-150 ease-in-out`,
          props.onClick && tw`hover:bg-gray-200 active:bg-gray-200`,
        ]}
      >
        {props.children}
      </Card>
    </div>
  )
}
Example #9
Source File: AlertStatusSummaryButton.tsx    From backstage with Apache License 2.0 6 votes vote down vote up
AlertStatusSummaryButton = ({
  children,
  onClick,
}: PropsWithChildren<AlertStatusSummaryButtonProps>) => {
  const classes = useStyles();
  const [clicked, setClicked] = useState(false);
  const iconClassName = classnames(classes.icon, {
    [classes.clicked]: clicked,
  });

  const handleOnClick: MouseEventHandler = e => {
    setClicked(prevClicked => !prevClicked);
    onClick(e);
  };

  return (
    <Button
      variant="text"
      color="primary"
      disableElevation
      aria-label="expand"
      endIcon={<ExpandMoreIcon className={iconClassName} />}
      onClick={handleOnClick}
    >
      {children}
    </Button>
  );
}
Example #10
Source File: ActionItemCard.tsx    From backstage with Apache License 2.0 6 votes vote down vote up
ActionItemCard = ({
  alert,
  avatar,
  number,
  disableScroll = false,
}: ActionItemCardProps) => {
  const classes = useStyles();
  const rootClasses = classnames(classes.root, {
    [classes.activeRoot]: !disableScroll,
  });
  const [, setScroll] = useScroll();

  const onActionItemClick: MouseEventHandler = () => {
    if (!disableScroll && number) {
      setScroll(`alert-${number}`);
    }
  };

  return (
    <Card className={classes.card} raised={false} onClick={onActionItemClick}>
      <CardHeader
        classes={{
          root: rootClasses,
          action: classes.action,
          title: classes.title,
        }}
        title={alert.title}
        subheader={alert.subtitle}
        avatar={avatar}
      />
    </Card>
  );
}
Example #11
Source File: WalletDialogButton.tsx    From wallet-adapter with Apache License 2.0 6 votes vote down vote up
WalletDialogButton: FC<ButtonProps> = ({
    children = 'Select Wallet',
    color = 'primary',
    variant = 'contained',
    type = 'button',
    onClick,
    ...props
}) => {
    const { setOpen } = useWalletDialog();

    const handleClick: MouseEventHandler<HTMLButtonElement> = useCallback(
        (event) => {
            if (onClick) onClick(event);
            if (!event.defaultPrevented) setOpen(true);
        },
        [onClick, setOpen]
    );

    return (
        <Button color={color} variant={variant} type={type} onClick={handleClick} {...props}>
            {children}
        </Button>
    );
}
Example #12
Source File: WalletConnectButton.tsx    From wallet-adapter with Apache License 2.0 6 votes vote down vote up
WalletConnectButton: FC<ButtonProps> = ({ children, disabled, onClick, ...props }) => {
    const { wallet, connect, connecting, connected } = useWallet();

    const handleClick: MouseEventHandler<HTMLButtonElement> = useCallback(
        (event) => {
            if (onClick) onClick(event);
            // eslint-disable-next-line @typescript-eslint/no-empty-function
            if (!event.defaultPrevented) connect().catch(() => {});
        },
        [onClick, connect]
    );

    const content = useMemo(() => {
        if (children) return children;
        if (connecting) return 'Connecting ...';
        if (connected) return 'Connected';
        if (wallet) return 'Connect';
        return 'Connect Wallet';
    }, [children, connecting, connected, wallet]);

    return (
        <Button
            className="wallet-adapter-button-trigger"
            disabled={disabled || !wallet || connecting || connected}
            startIcon={wallet ? <WalletIcon wallet={wallet} /> : undefined}
            onClick={handleClick}
            {...props}
        >
            {content}
        </Button>
    );
}
Example #13
Source File: WalletDisconnectButton.tsx    From wallet-adapter with Apache License 2.0 6 votes vote down vote up
WalletDisconnectButton: FC<ButtonProps> = ({ children, disabled, onClick, ...props }) => {
    const { wallet, disconnect, disconnecting } = useWallet();

    const handleClick: MouseEventHandler<HTMLButtonElement> = useCallback(
        (event) => {
            if (onClick) onClick(event);
            // eslint-disable-next-line @typescript-eslint/no-empty-function
            if (!event.defaultPrevented) disconnect().catch(() => {});
        },
        [onClick, disconnect]
    );

    const content = useMemo(() => {
        if (children) return children;
        if (disconnecting) return 'Disconnecting ...';
        if (wallet) return 'Disconnect';
        return 'Disconnect Wallet';
    }, [children, disconnecting, wallet]);

    return (
        <Button
            className="wallet-adapter-button-trigger"
            disabled={disabled || !wallet}
            startIcon={wallet ? <WalletIcon wallet={wallet} /> : undefined}
            onClick={handleClick}
            {...props}
        >
            {content}
        </Button>
    );
}
Example #14
Source File: MultiPicker.tsx    From rari-dApp with GNU Affero General Public License v3.0 6 votes vote down vote up
function MultiPickerButton({
  children,
  selected,
  onClick,
}: {
  children: ReactNode;
  selected: boolean;
  onClick?: MouseEventHandler<HTMLButtonElement>;
}) {
  return (
    <Button
      colorScheme="black"
      variant={selected ? "solid" : "ghost"}
      borderRadius="full"
      onClick={onClick}
      bgColor={selected ? "#00C628" : "transparent"}
    >
      {children}
    </Button>
  );
}
Example #15
Source File: handleMouseMoveInDraggable.ts    From ui-schema with MIT License 6 votes vote down vote up
handleMouseMoveInDraggable = (
    noDragOnNodes: string[] | undefined,
    canDrag: boolean,
    setDisableDrag: (disableDrag: boolean) => void
): MouseEventHandler =>
    (e) => {
        if (!noDragOnNodes || noDragOnNodes.length === 0) {
            return
        }
        // all of this `disableDrag` is primary to fix the FF bug:
        // https://bugzilla.mozilla.org/show_bug.cgi?id=800050

        // @ts-ignore
        if (noDragOnNodes.indexOf(e.target.nodeName) === -1) {
            if (!canDrag) {
                setDisableDrag(false)
            }
            return
        }
        e.stopPropagation()
        if (canDrag) {
            setDisableDrag(true)
        }
    }
Example #16
Source File: WalletConnectButton.tsx    From wallet-adapter with Apache License 2.0 5 votes vote down vote up
WalletConnectButton: FC<ButtonProps> = ({
    color = 'primary',
    variant = 'contained',
    type = 'button',
    children,
    disabled,
    onClick,
    ...props
}) => {
    const { wallet, connect, connecting, connected } = useWallet();

    const handleClick: MouseEventHandler<HTMLButtonElement> = useCallback(
        (event) => {
            if (onClick) onClick(event);
            // eslint-disable-next-line @typescript-eslint/no-empty-function
            if (!event.defaultPrevented)
                connect().catch(() => {
                    // Silently catch because any errors are caught by the context `onError` handler
                });
        },
        [onClick, connect]
    );

    const content = useMemo(() => {
        if (children) return children;
        if (connecting) return 'Connecting ...';
        if (connected) return 'Connected';
        if (wallet) return 'Connect';
        return 'Connect Wallet';
    }, [children, connecting, connected, wallet]);

    return (
        <Button
            color={color}
            variant={variant}
            type={type}
            onClick={handleClick}
            disabled={disabled || !wallet || connecting || connected}
            startIcon={<WalletIcon wallet={wallet} />}
            {...props}
        >
            {content}
        </Button>
    );
}
Example #17
Source File: SessionMenu.tsx    From caritas-onlineBeratung-frontend with GNU Affero General Public License v3.0 5 votes vote down vote up
SessionMenuFlyoutGroup = ({
	chatItem,
	activeSession,
	groupChatInfoLink,
	editGroupChatSettingsLink,
	handleLeaveGroupChat,
	handleStopGroupChat
}: {
	chatItem: GroupChatItemInterface;
	activeSession: ActiveSessionType;
	groupChatInfoLink: string;
	editGroupChatSettingsLink: string;
	handleStopGroupChat: MouseEventHandler;
	handleLeaveGroupChat: MouseEventHandler;
}) => {
	const { userData } = useContext(UserDataContext);

	return (
		<>
			{chatItem?.subscribed && (
				<div
					onClick={handleLeaveGroupChat}
					className="sessionMenu__item sessionMenu__item--mobile"
				>
					{translate('chatFlyout.leaveGroupChat')}
				</div>
			)}
			{hasUserAuthority(AUTHORITIES.CONSULTANT_DEFAULT, userData) && (
				<Link
					to={groupChatInfoLink}
					className="sessionMenu__item sessionMenu__item--mobile"
				>
					{translate('chatFlyout.groupChatInfo')}
				</Link>
			)}
			{chatItem?.subscribed &&
				hasUserAuthority(AUTHORITIES.CONSULTANT_DEFAULT, userData) && (
					<div
						onClick={handleStopGroupChat}
						className="sessionMenu__item sessionMenu__item--mobile"
					>
						{translate('chatFlyout.stopGroupChat')}
					</div>
				)}
			{isGroupChatOwner(activeSession, userData) && !chatItem.active && (
				<Link
					to={{
						pathname: editGroupChatSettingsLink,
						state: {
							isEditMode: true,
							prevIsInfoPage: false
						}
					}}
					className="sessionMenu__item sessionMenu__item--mobile"
				>
					{translate('chatFlyout.editGroupChat')}
				</Link>
			)}
		</>
	);
}
Example #18
Source File: WalletDisconnectButton.tsx    From wallet-adapter with Apache License 2.0 5 votes vote down vote up
WalletDisconnectButton: FC<ButtonProps> = ({
    type = 'primary',
    size = 'large',
    htmlType = 'button',
    children,
    disabled,
    onClick,
    ...props
}) => {
    const { wallet, disconnect, disconnecting } = useWallet();

    const handleClick: MouseEventHandler<HTMLButtonElement> = useCallback(
        (event) => {
            if (onClick) onClick(event);
            // eslint-disable-next-line @typescript-eslint/no-empty-function
            if (!event.defaultPrevented)
                disconnect().catch(() => {
                    // Silently catch because any errors are caught by the context `onError` handler
                });
        },
        [onClick, disconnect]
    );

    const content = useMemo(() => {
        if (children) return children;
        if (disconnecting) return 'Disconnecting ...';
        if (wallet) return 'Disconnect';
        return 'Disconnect Wallet';
    }, [children, disconnecting, wallet]);

    return (
        <Button
            onClick={handleClick}
            disabled={disabled || !wallet}
            icon={<WalletIcon wallet={wallet} />}
            type={type}
            size={size}
            htmlType={htmlType}
            {...props}
        >
            {content}
        </Button>
    );
}
Example #19
Source File: WalletConnectButton.tsx    From wallet-adapter with Apache License 2.0 5 votes vote down vote up
WalletConnectButton: FC<ButtonProps> = ({
    type = 'primary',
    size = 'large',
    htmlType = 'button',
    children,
    disabled,
    onClick,
    ...props
}) => {
    const { wallet, connect, connecting, connected } = useWallet();

    const handleClick: MouseEventHandler<HTMLButtonElement> = useCallback(
        (event) => {
            if (onClick) onClick(event);
            // eslint-disable-next-line @typescript-eslint/no-empty-function
            if (!event.defaultPrevented)
                connect().catch(() => {
                    // Silently catch because any errors are caught by the context `onError` handler
                });
        },
        [onClick, connect]
    );

    const content = useMemo(() => {
        if (children) return children;
        if (connecting) return 'Connecting ...';
        if (connected) return 'Connected';
        if (wallet) return 'Connect';
        return 'Connect Wallet';
    }, [children, connecting, connected, wallet]);

    return (
        <Button
            onClick={handleClick}
            disabled={disabled || !wallet || connecting || connected}
            icon={<WalletIcon wallet={wallet} />}
            type={type}
            size={size}
            htmlType={htmlType}
            {...props}
        >
            {content}
        </Button>
    );
}
Example #20
Source File: WalletDisconnectButton.tsx    From wallet-adapter with Apache License 2.0 5 votes vote down vote up
WalletDisconnectButton: FC<ButtonProps> = ({
    color = 'primary',
    variant = 'contained',
    type = 'button',
    children,
    disabled,
    onClick,
    ...props
}) => {
    const { wallet, disconnect, disconnecting } = useWallet();

    const handleClick: MouseEventHandler<HTMLButtonElement> = useCallback(
        (event) => {
            if (onClick) onClick(event);
            // eslint-disable-next-line @typescript-eslint/no-empty-function
            if (!event.defaultPrevented)
                disconnect().catch(() => {
                    // Silently catch because any errors are caught by the context `onError` handler
                });
        },
        [onClick, disconnect]
    );

    const content = useMemo(() => {
        if (children) return children;
        if (disconnecting) return 'Disconnecting ...';
        if (wallet) return 'Disconnect';
        return 'Disconnect Wallet';
    }, [children, disconnecting, wallet]);

    return (
        <Button
            color={color}
            variant={variant}
            type={type}
            onClick={handleClick}
            disabled={disabled || !wallet}
            startIcon={<WalletIcon wallet={wallet} />}
            {...props}
        >
            {content}
        </Button>
    );
}
Example #21
Source File: Paper.tsx    From dropzone-ui-react with MIT License 5 votes vote down vote up
Paper: FC<PaperProps> = (props: PaperProps) => {
  const {
    children,
    shadow,
    style,
    className,
    onMouseEnter,
    onMouseLeave,
    component,
  } = mergeProps(props, PaperPropsDefault);
  /**
   * uses the shadow prop to create a classname
   *
   * @returns an appropiate paper classanme
   */
  const makeClassName = (): string => {
    let classNameFinal = "";
    if (!shadow) {
      classNameFinal = `paper-root shadow`;
    } else {
      classNameFinal = `paper-root shadow${shadow}`;
    }

    if (className) {
      classNameFinal += ` ${className}`;
    }
    return classNameFinal;
  };
  const handleMouseEnter: MouseEventHandler<HTMLDivElement> = (
    evt: React.MouseEvent<HTMLDivElement, MouseEvent>
  ) => {
    onMouseEnter?.();
  };
  const handleMouseLeave: MouseEventHandler<HTMLDivElement> = (
    evt: React.MouseEvent<HTMLDivElement, MouseEvent>
  ) => {
    onMouseLeave?.();
  };

  return React.createElement(
    component ? component : "div",
    {
      className: makeClassName(),
      style: style,
      onMouseEnter: handleMouseEnter,
      onMouseLeave: handleMouseLeave,
    },
    children
  );
  /*
    return (
      <>
        <div
          className={makeClassName()}
          style={style}
          onMouseEnter={handleMouseEnter}
          onMouseLeave={handleMouseLeave}
        >
          {children}
        </div>
      </>
    );
    */
}
Example #22
Source File: ActionItems.tsx    From backstage with Apache License 2.0 5 votes vote down vote up
ActionItems = ({
  active,
  snoozed,
  accepted,
  dismissed,
}: ActionItemsProps) => {
  const classes = useStyles();
  const [, setScroll] = useScroll();

  const isSnoozedButtonDisplayed = !!snoozed.length;
  const isAcceptedButtonDisplayed = !!accepted.length;
  const isDismissedButtonDisplayed = !!dismissed.length;
  const isStatusButtonGroupDisplayed = !!active.length;

  const onStatusButtonClick: MouseEventHandler = () =>
    setScroll(ScrollType.AlertSummary);

  return (
    <>
      <Paper>
        {active.map((alert, index) => (
          <Fragment key={`alert-${index}`}>
            <ActionItemCard
              alert={alert}
              number={index + 1}
              avatar={<Avatar className={classes.avatar}>{index + 1}</Avatar>}
            />
            {index < active.length - 1 && <Divider />}
          </Fragment>
        ))}
      </Paper>
      {isStatusButtonGroupDisplayed && (
        <Box display="flex" justifyContent="flex-end" mt={2}>
          {isAcceptedButtonDisplayed && (
            <AlertStatusButton
              title="Accepted"
              aria-label={AlertStatus.Accepted}
              icon={<AcceptIcon />}
              amount={accepted.length}
              onClick={onStatusButtonClick}
            />
          )}
          {isSnoozedButtonDisplayed && (
            <AlertStatusButton
              title="Snoozed"
              aria-label={AlertStatus.Snoozed}
              amount={snoozed.length}
              icon={<SnoozeIcon />}
              onClick={onStatusButtonClick}
            />
          )}
          {isDismissedButtonDisplayed && (
            <AlertStatusButton
              title="Dismissed"
              aria-label={AlertStatus.Dismissed}
              icon={<DismissIcon />}
              amount={dismissed.length}
              onClick={onStatusButtonClick}
            />
          )}
        </Box>
      )}
    </>
  );
}
Example #23
Source File: CopyTextButton.tsx    From backstage with Apache License 2.0 5 votes vote down vote up
/**
 * Copy text button with visual feedback
 *
 * @public
 * @remarks
 *
 * Visual feedback takes form of:
 *  - a hover color
 *  - click ripple
 *  - Tooltip shown when user has clicked
 *
 * @example
 *
 * `<CopyTextButton text="My text that I want to be copied to the clipboard" />`
 */
export function CopyTextButton(props: CopyTextButtonProps) {
  const {
    text,
    tooltipDelay = 1000,
    tooltipText = 'Text copied to clipboard',
  } = props;
  const errorApi = useApi(errorApiRef);
  const [open, setOpen] = useState(false);
  const [{ error }, copyToClipboard] = useCopyToClipboard();

  useEffect(() => {
    if (error) {
      errorApi.post(error);
    }
  }, [error, errorApi]);

  const handleCopyClick: MouseEventHandler = e => {
    e.stopPropagation();
    setOpen(true);
    copyToClipboard(text);
  };

  return (
    <>
      <Tooltip
        id="copy-test-tooltip"
        title={tooltipText}
        placement="top"
        leaveDelay={tooltipDelay}
        onClose={() => setOpen(false)}
        open={open}
      >
        <IconButton onClick={handleCopyClick}>
          <CopyIcon />
        </IconButton>
      </Tooltip>
    </>
  );
}
Example #24
Source File: Header.tsx    From rari-dApp with GNU Affero General Public License v3.0 5 votes vote down vote up
HeaderLink = ({
  name,
  route,
  ml,
  onMouseOver,
  onMouseOut,
}: {
  name: string;
  route: string;

  ml?: number | string;
  onMouseOver?: MouseEventHandler<HTMLAnchorElement>;
  onMouseOut?: MouseEventHandler<HTMLAnchorElement>;
}) => {
  const location = useLocation();

  const isExternal = route.startsWith("http");

  const isOnThisRoute =
    location.pathname === route ||
    location.pathname.replace(/\/+$/, "") === route;

  return isExternal ? (
    <Link
      href={route}
      isExternal
      ml={ml ?? 0}
      whiteSpace="nowrap"
      className="no-underline"
      onMouseOver={onMouseOver}
      onMouseOut={onMouseOut}
    >
      <Text fontWeight={isOnThisRoute ? "bold" : "normal"}>{name}</Text>
    </Link>
  ) : (
    <Link
      /* @ts-ignore */
      as={RouterLink}
      to={route}
      ml={ml ?? 0}
      whiteSpace="nowrap"
      className="no-underline"
      onMouseOver={onMouseOver}
      onMouseOut={onMouseOut}
    >
      <Text fontWeight={isOnThisRoute ? "bold" : "normal"}>{name}</Text>
    </Link>
  );
}
Example #25
Source File: SessionMenu.tsx    From caritas-onlineBeratung-frontend with GNU Affero General Public License v3.0 5 votes vote down vote up
SessionMenuGroup = ({
	chatItem,
	activeSession,
	groupChatInfoLink,
	editGroupChatSettingsLink,
	handleStopGroupChat,
	handleLeaveGroupChat,
	isJoinGroupChatView = false
}: {
	chatItem: GroupChatItemInterface;
	activeSession: ActiveSessionType;
	groupChatInfoLink: string;
	editGroupChatSettingsLink: string;
	handleStopGroupChat: MouseEventHandler;
	handleLeaveGroupChat: MouseEventHandler;
	isJoinGroupChatView?: boolean;
}) => {
	const { userData } = useContext(UserDataContext);

	return (
		<>
			{chatItem?.subscribed && !isJoinGroupChatView && (
				<span
					onClick={handleLeaveGroupChat}
					className="sessionMenu__item--desktop sessionMenu__button"
				>
					<span className="sessionMenu__icon">
						<LeaveChatIcon />
						{translate('chatFlyout.leaveGroupChat')}
					</span>
				</span>
			)}

			{hasUserAuthority(AUTHORITIES.CONSULTANT_DEFAULT, userData) && (
				<Link
					to={groupChatInfoLink}
					className="sessionMenu__item--desktop sessionMenu__button"
				>
					<span className="sessionMenu__icon">
						<GroupChatInfoIcon />
						{translate('chatFlyout.groupChatInfo')}
					</span>
				</Link>
			)}
			{chatItem?.subscribed &&
				hasUserAuthority(AUTHORITIES.CONSULTANT_DEFAULT, userData) && (
					<span
						onClick={handleStopGroupChat}
						className="sessionMenu__item--desktop sessionMenu__button"
					>
						<span className="sessionMenu__icon">
							<StopGroupChatIcon />
							{translate('chatFlyout.stopGroupChat')}
						</span>
					</span>
				)}

			{isGroupChatOwner(activeSession, userData) && !chatItem.active && (
				<Link
					to={{
						pathname: editGroupChatSettingsLink,
						state: { isEditMode: true, prevIsInfoPage: false }
					}}
					className="sessionMenu__item--desktop sessionMenu__button"
				>
					<span className="sessionMenu__icon">
						<EditGroupChatIcon />
						{translate('chatFlyout.editGroupChat')}
					</span>
				</Link>
			)}
		</>
	);
}
Example #26
Source File: App.tsx    From pybricks-code with MIT License 4 votes vote down vote up
App: React.VFC = () => {
    const { isDarkMode } = useTernaryDarkMode();
    const { isSettingShowDocsEnabled } = useSettingIsShowDocsEnabled();
    const [isDragging, setIsDragging] = useState(false);

    const [docsSplit, setDocsSplit] = useLocalStorage('app-docs-split', 30);
    const [terminalSplit, setTerminalSplit] = useLocalStorage('app-terminal-split', 30);

    // Classes.DARK has to be applied to body element, otherwise it won't
    // affect portals
    useEffect(() => {
        if (!isDarkMode) {
            // no class for light mode, so nothing to do
            return;
        }

        document.body.classList.add(Classes.DARK);
        return () => document.body.classList.remove(Classes.DARK);
    }, [isDarkMode]);

    useEffect(() => {
        const listener = (e: KeyboardEvent) => {
            // prevent default browser keyboard shortcuts that we use
            // NB: some of these like 'n' and 'w' cannot be prevented when
            // running "in the browser"
            if (e.ctrlKey && ['d', 'n', 's', 'w'].includes(e.key)) {
                e.preventDefault();
            }
        };

        addEventListener('keydown', listener);
        return () => removeEventListener('keydown', listener);
    }, []);

    // keep track of last focused element in the activities area and restore
    // focus to that element if any non-interactive area is clicked

    const [lastActivitiesFocusChild, setLastActivitiesFocusChild] =
        useState<HTMLElement | null>(null);

    const handleFocus = useCallback<FocusEventHandler>(
        (e) => {
            if (e.target instanceof HTMLElement) {
                setLastActivitiesFocusChild(e.target);
            }
        },
        [setLastActivitiesFocusChild],
    );

    const handleActivitiesMouseDown = useCallback<MouseEventHandler<HTMLDivElement>>(
        (e) => {
            if (
                lastActivitiesFocusChild &&
                e.currentTarget.contains(lastActivitiesFocusChild)
            ) {
                // if the last focused child exists and it is still inside of
                // the activities area, focus it
                lastActivitiesFocusChild.focus();
            } else {
                // otherwise, focus the first focusable element
                const walker = getFocusableTreeWalker(e.currentTarget);
                const first = walker.nextNode();

                if (first instanceof HTMLElement) {
                    first.focus();
                }
            }

            // prevent document body from getting focus
            e.stopPropagation();
            e.preventDefault();
        },
        [lastActivitiesFocusChild],
    );

    return (
        <div className="pb-app" onContextMenu={(e) => e.preventDefault()}>
            <div className="pb-app-body">
                <div
                    className="pb-app-activities"
                    onFocus={handleFocus}
                    onMouseDown={handleActivitiesMouseDown}
                >
                    <Activities />
                </div>
                {/* need a container with position: relative; for SplitterLayout since it uses position: absolute; */}
                <div className="pb-app-main" style={{ position: 'relative' }}>
                    <SplitterLayout
                        customClassName={
                            isSettingShowDocsEnabled ? 'pb-show-docs' : 'pb-hide-docs'
                        }
                        onDragStart={(): void => setIsDragging(true)}
                        onDragEnd={(): void => setIsDragging(false)}
                        percentage={true}
                        secondaryInitialSize={docsSplit}
                        onSecondaryPaneSizeChange={setDocsSplit}
                    >
                        <SplitterLayout
                            vertical={true}
                            percentage={true}
                            secondaryInitialSize={terminalSplit}
                            onSecondaryPaneSizeChange={setTerminalSplit}
                        >
                            <div className="pb-app-editor">
                                <Toolbar />
                                <Editor />
                            </div>
                            <div className="pb-app-terminal">
                                <Terminal />
                            </div>
                        </SplitterLayout>
                        <div className="pb-app-docs">
                            {isDragging && <div className="pb-app-docs-drag-helper" />}
                            <Docs />
                        </div>
                    </SplitterLayout>
                </div>
            </div>
            <StatusBar />
        </div>
    );
}
Example #27
Source File: index.ts    From use-long-press with MIT License 4 votes vote down vote up
/**
 * Detect click / tap and hold event
 *
 * @param callback <p>
 *   Function to call when long press event is detected
 *   (click or tap lasts for <i>threshold</i> amount of time or longer)
 *   </p>
 * @param options <ul>
 * <li><b>threshold</b>
 * - Period of time that must elapse after detecting click or tap in order to trigger <i>callback</i></li>
 * <li><b>captureEvent</b>
 * - If React Event will be supplied as first argument to all callbacks</li>
 * <li><b>detect</b>
 * - Which type of events should be detected ('mouse' | 'touch' | 'both' )
 * <li><b>cancelOnMovement</b>
 * - <p>If long press should be canceled on mouse / touch move.</p>
 * <p>You can use this option to turn it on / off or set specific move tolerance as follows:</p>
 * <ol><li><i>true</i> or <i>false</i> (by default) - when set to true tolerance value will default to <i>25px</i>
 * <li><i>number</i> - set a specific tolerance value (square size inside which movement won't cancel long press)</li></ol>
 * </li>
 * <li><b>onStart</b>
 * - Called right after detecting click / tap event (e.g. onMouseDown or onTouchStart)
 * <li><b>onFinish</b>
 * - Called (if long press <u>was triggered</u>)
 * on releasing click or tap (e.g. onMouseUp, onMouseLeave or onTouchEnd)
 * <li><b>onCancel</b>
 * - Called (if long press <u>was <b>not</b> triggered</u>)
 * on releasing click or tap (e.g. onMouseUp, onMouseLeave or onTouchEnd)
 * </ul>
 */
export function useLongPress<
  Target extends Element = Element,
  Callback extends LongPressCallback<Target> = LongPressCallback<Target>,
  Context extends unknown = undefined
>(
  callback: Callback | null,
  {
    threshold = 400,
    captureEvent = false,
    detect = LongPressDetectEvents.BOTH,
    cancelOnMovement = false,
    filterEvents,
    onStart,
    onMove,
    onFinish,
    onCancel,
  }: LongPressOptions<Target, Context> = {}
): CallableContextResult<LongPressResult<Target, typeof detect> | Record<string, never>, Context> {
  const isLongPressActive = useRef(false);
  const isPressed = useRef(false);
  const timer = useRef<NodeJS.Timeout>();
  const savedCallback = useRef(callback);
  const startPosition = useRef<Coordinates>(null);

  const start = useCallback(
    (context?: Context) => (event: LongPressEvent<Target>) => {
      // Prevent multiple start triggers
      if (isPressed.current) {
        return;
      }

      // Ignore events other than mouse and touch
      if (!isMouseEvent(event) && !isTouchEvent(event)) {
        return;
      }

      // If we don't want all events to trigger long press and provided event is filtered out
      if (filterEvents !== undefined && !filterEvents(event)) {
        return;
      }

      startPosition.current = getCurrentPosition(event);

      if (captureEvent) {
        event.persist();
      }

      const meta: LongPressCallbackMeta<Context> = context === undefined ? {} : { context };

      // When touched trigger onStart and start timer
      onStart?.(event, meta);
      isPressed.current = true;
      timer.current = setTimeout(() => {
        if (savedCallback.current) {
          savedCallback.current(event, meta);
          isLongPressActive.current = true;
        }
      }, threshold);
    },
    [captureEvent, filterEvents, onStart, threshold]
  );

  const cancel = useCallback(
    (context?: Context, reason?: LongPressEventReason) => (event: LongPressEvent<Target>) => {
      // Ignore events other than mouse and touch
      if (!isMouseEvent(event) && !isTouchEvent(event)) {
        return;
      }

      startPosition.current = null;

      if (captureEvent) {
        event.persist();
      }

      const meta: LongPressCallbackMeta<Context> = context === undefined ? {} : { context };

      // Trigger onFinish callback only if timer was active
      if (isLongPressActive.current) {
        onFinish?.(event, meta);
      } else if (isPressed.current) {
        // Otherwise, if not active trigger onCancel
        onCancel?.(event, { ...meta, reason: reason ?? LongPressEventReason.CANCELED_BY_TIMEOUT });
      }
      isLongPressActive.current = false;
      isPressed.current = false;
      timer.current !== undefined && clearTimeout(timer.current);
    },
    [captureEvent, onFinish, onCancel]
  );

  const handleMove = useCallback(
    (context?: Context) => (event: LongPressEvent<Target>) => {
      onMove?.(event, { context });
      if (cancelOnMovement && startPosition.current) {
        const currentPosition = getCurrentPosition(event);
        /* istanbul ignore else */
        if (currentPosition) {
          const moveThreshold = cancelOnMovement === true ? 25 : cancelOnMovement;
          const movedDistance = {
            x: Math.abs(currentPosition.x - startPosition.current.x),
            y: Math.abs(currentPosition.y - startPosition.current.y),
          };

          // If moved outside move tolerance box then cancel long press
          if (movedDistance.x > moveThreshold || movedDistance.y > moveThreshold) {
            cancel(context, LongPressEventReason.CANCELED_BY_MOVEMENT)(event);
          }
        }
      }
    },
    [cancel, cancelOnMovement, onMove]
  );

  useEffect(
    () => (): void => {
      // Clear timeout on unmount
      timer.current !== undefined && clearTimeout(timer.current);
    },
    []
  );

  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  return useMemo(() => {
    function result(context?: Context) {
      const mouseHandlers = {
        onMouseDown: start(context) as MouseEventHandler<Target>,
        onMouseMove: handleMove(context) as MouseEventHandler<Target>,
        onMouseUp: cancel(context) as MouseEventHandler<Target>,
        onMouseLeave: cancel(context) as MouseEventHandler<Target>,
      };

      const touchHandlers = {
        onTouchStart: start(context) as TouchEventHandler<Target>,
        onTouchMove: handleMove(context) as TouchEventHandler<Target>,
        onTouchEnd: cancel(context) as TouchEventHandler<Target>,
      };

      if (callback === null) {
        return {};
      }

      if (detect === LongPressDetectEvents.MOUSE) {
        return mouseHandlers;
      }

      if (detect === LongPressDetectEvents.TOUCH) {
        return touchHandlers;
      }

      return { ...mouseHandlers, ...touchHandlers };
    }

    return result;
  }, [callback, cancel, detect, handleMove, start]);
}
Example #28
Source File: KeybindingsForButton.tsx    From xcloud-keyboard-mouse with GNU General Public License v3.0 4 votes vote down vote up
function KeybindingsForButton({ button, value, onChange, readOnly, error, useSpacers = false }: TrippleKeybindProps) {
  const [isListening, setIsListening] = useState(false);
  const keyListener = useRef<null | ((e: KeyboardEvent) => void)>(null);
  const codes = useMemo(() => (!value ? [] : Array.isArray(value) ? value : [value]), [value]);

  const handleCancelListen = useCallback(() => {
    setIsListening(false);
    if (keyListener.current) document.removeEventListener('keydown', keyListener.current);
  }, []);

  const handleMouseDown: MouseEventHandler<HTMLDivElement> = useCallback(
    (e) => {
      if (e.cancelable) e.preventDefault();
      const { button: mouseButton } = e;
      if (mouseButton === 0 || mouseButton === 2) {
        const code = mouseButton === 0 ? 'Click' : 'RightClick';
        if (codes.indexOf(code) === -1) {
          onChange(button, codes.concat([code]));
        }
      }
      handleCancelListen();
      return false;
    },
    [button, codes, handleCancelListen, onChange],
  );

  const handleWheel: WheelEventHandler<HTMLDivElement> = useCallback(
    (e) => {
      if (e.cancelable) e.preventDefault();
      const code = 'Scroll';
      if (codes.indexOf(code) === -1) {
        onChange(button, codes.concat([code]));
      }
      handleCancelListen();
    },
    [button, codes, handleCancelListen, onChange],
  );

  const handleClickAdd = useCallback(() => {
    if (readOnly) return;
    setIsListening(true);
    keyListener.current = function onKeyDown(e: KeyboardEvent) {
      if (e.cancelable) e.preventDefault();
      const { code } = e;
      if (code !== 'Escape' && codes.indexOf(code) === -1) {
        onChange(button, codes.concat([code]));
      }
      handleCancelListen();
    };
    document.addEventListener('keydown', keyListener.current, false);
  }, [button, codes, readOnly, handleCancelListen, onChange]);

  const handleRemove = (i: number) => {
    onChange(
      button,
      codes.filter((_, j) => i !== j),
    );
  };

  const showNoneMessage = !codes.length && readOnly;
  const canAddMore = codes.length < MAX_BINDINGS;
  const showAddBtn = !readOnly && canAddMore;
  const numSpacers = readOnly || codes.length >= MAX_BINDINGS - 1 ? 0 : 1;
  const spacers: string[] = !useSpacers || showNoneMessage ? [] : new Array(numSpacers).fill(' ');
  const modal = (
    <Modal
      center
      open={isListening}
      onClose={handleCancelListen}
      showCloseIcon={false}
      focusTrapped={true}
      closeOnEsc={false}
    >
      <div
        className="vertical centered unselectable"
        style={{ width: '60vw', height: '50vh', padding: 20 }}
        onMouseDown={isListening ? handleMouseDown : undefined}
        onWheel={isListening ? handleWheel : undefined}
      >
        <h3>Press any key or click to bind...</h3>
        <p>(Press Esc to cancel)</p>
      </div>
    </Modal>
  );
  const errorNotice = error ? (
    <TooltipHost content={error} id={`keybind-error-tooltip-${button}`} directionalHint={DirectionalHint.rightCenter}>
      <ExclamationCircle className="error margin-left-s" />
    </TooltipHost>
  ) : null;
  return (
    <tr>
      <th>
        {camelToSpace(button)}
        {modal}
        {errorNotice}
      </th>
      {showNoneMessage ? (
        <td className="none" colSpan={3}>
          No bindings for button
        </td>
      ) : null}
      {codes.map((code, i) => (
        <td key={code}>
          <div>
            <span>{formatCodeName(code)}</span>
            {readOnly ? null : (
              <IconButton
                className="error-bg delete-icon"
                size={18}
                iconProps={{ iconName: 'BoxMultiplySolid', className: 'error' }}
                title="Remove binding"
                disabled={isListening}
                onClick={() => handleRemove(i)}
              />
            )}
          </div>
        </td>
      ))}
      {showAddBtn ? (
        <td>
          <IconButton
            iconProps={{ iconName: 'Add' }}
            title="Add binding"
            size={18}
            disabled={isListening}
            onClick={handleClickAdd}
          />
        </td>
      ) : null}
      {spacers.map((_, i) => (
        <td className="empty" key={`s${i}`}>
          <div>Empty Binding</div>
        </td>
      ))}
    </tr>
  );
}
Example #29
Source File: index.tsx    From yasd with MIT License 4 votes vote down vote up
Page: React.FC = () => {
  const { t } = useTranslation()
  const [group, setGroup] = useState<'dynamic' | 'static'>('dynamic')
  const { data: dnsResult, error: dnsResultError } = useSWR<DnsResult>(
    '/dns',
    fetcher,
  )
  const list = useMemo(() => {
    if (group === 'dynamic') {
      return dnsResult?.dnsCache ?? []
    }
    return dnsResult?.local ?? []
  }, [dnsResult, group])

  const flushDns: MouseEventHandler = () => {
    fetcher({
      url: '/dns/flush',
      method: 'POST',
    })
      .then(() => {
        toast.success(t('common.success_interaction'))
        return mutate('/dns')
      })
      .catch((err) => {
        toast.error(t('common.failed_interaction'))
        console.error(err)
      })
  }

  const openIpDetail = (ip: string) => {
    window.open(`https://ip.sb/ip/${ip}`, '_blank', 'noopener noreferrer')
  }

  const rowRenderer: ListRowRenderer = useCallback(
    ({
      key, // Unique key within array of rows
      index, // Index of row within collection
      isScrolling, // The List is currently being scrolled
      isVisible, // This row is visible within the List (eg it is not an overscanned row)
      style, // Style object to be applied to row (to position it)
    }) => {
      if (group === 'dynamic') {
        const record = (list as DnsResult['dnsCache'])[index]

        return (
          <div
            key={key}
            style={style}
            onClick={() => openIpDetail(record.data[0])}
            css={[
              tw`flex flex-col justify-center py-2`,
              tw`cursor-pointer hover:bg-gray-100`,
              css`
                padding-left: calc(env(safe-area-inset-left) + 0.75rem);
                padding-right: calc(env(safe-area-inset-right) + 0.75rem);
              `,
            ]}
          >
            <div tw="text-sm truncate">{record.domain}</div>
            <div tw="text-xs text-gray-700 leading-tight">
              DNS: {record.server}
            </div>
            <div tw="text-xs text-gray-700 leading-tight truncate">
              {t('dns.result')}: {record.data.join(', ')}
            </div>
            <div tw="text-xs text-gray-700 leading-tight truncate">
              {t('dns.path')}: {record.path}
            </div>
          </div>
        )
      } else {
        const record = (list as DnsResult['local'])[index]

        return (
          <div
            key={key}
            style={style}
            css={[
              tw`flex flex-col justify-center py-2`,
              css`
                padding-left: calc(env(safe-area-inset-left) + 0.75rem);
                padding-right: calc(env(safe-area-inset-right) + 0.75rem);
              `,
            ]}
          >
            <div tw="text-sm truncate">{record.domain}</div>
            {!!record.server && (
              <div tw="text-xs text-gray-700 leading-tight">
                DNS: {record.server}
              </div>
            )}
            <div tw="text-xs text-gray-700 leading-tight">
              {t('dns.result')}: {record.data ?? 'N/A'}
            </div>
            <div tw="text-xs text-gray-700 leading-tight">
              {t('dns.source')}: {record.source ?? 'N/A'}
            </div>
            {!!record.comment && (
              <div tw="text-xs text-gray-700 leading-tight">
                {t('dns.comment')}: {record.comment}
              </div>
            )}
          </div>
        )
      }
    },
    [group, list],
  )

  return (
    <FixedFullscreenContainer>
      <PageTitle title="DNS" />

      <div tw="flex-1">
        <AutoSizer>
          {({ width, height }) => {
            return (
              <List
                width={width}
                height={height}
                rowCount={list.length}
                rowHeight={85}
                rowRenderer={rowRenderer}
                style={{
                  outline: 'none',
                }}
                css={css`
                  & > div {
                    ${tw`divide-y divide-gray-200`}
                  }
                `}
              />
            )
          }}
        </AutoSizer>
      </div>

      <div
        css={[
          tw`flex divide-x divide-gray-200 border-t border-solid border-gray-200 py-2 px-2`,
          css`
            & > div {
              ${tw`mx-2`}
            }
            & > div:first-of-type {
              margin-left: 0;
            }
          `,
        ]}
      >
        <SelectorGroup
          css={[
            tw`flex justify-center items-center`,
            css`
              & label {
                ${tw`py-2 px-4 ml-2 my-1 text-sm`}
              }
              & label:first-of-type {
                margin-left: 0;
              }
            `,
          ]}
          label="choose the dns result group"
          name="selector-group"
          onChange={(event: ChangeEvent<HTMLInputElement>) => {
            setGroup(event.target.value as 'dynamic' | 'static')
          }}
          options={[
            {
              children: t('dns.dynamic'),
              value: 'dynamic',
            },
            {
              children: t('dns.static'),
              value: 'static',
            },
          ]}
          value={group}
        />

        <div tw="flex items-center">
          <Button
            tw="font-normal"
            variant="tertiary"
            size="kilo"
            onClick={flushDns}
          >
            {t('dns.flush_dns')}
          </Button>
        </div>
      </div>
    </FixedFullscreenContainer>
  )
}