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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
/**
* 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 |
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 |
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 |
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 |
/**
* 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 |
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 |
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>
)
}