mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 21:27:20 +00:00
@@ -1,9 +1,10 @@
|
||||
import { Tooltip } from '@affine/component/ui/tooltip';
|
||||
import { useCatchEventCallback } from '@affine/core/hooks/use-catch-event-hook';
|
||||
import { SubscriptionPlan } from '@affine/graphql';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { useLiveData, useServices } from '@toeverything/infra';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { openSettingModalAtom } from '../../../atoms';
|
||||
import {
|
||||
@@ -35,17 +36,13 @@ export const UserPlanButton = () => {
|
||||
}, [subscriptionService]);
|
||||
|
||||
const setSettingModalAtom = useSetAtom(openSettingModalAtom);
|
||||
const handleClick = useCallback(
|
||||
(e: React.MouseEvent<HTMLDivElement>) => {
|
||||
e.stopPropagation();
|
||||
setSettingModalAtom({
|
||||
open: true,
|
||||
activeTab: 'plans',
|
||||
scrollAnchor: 'cloudPricingPlan',
|
||||
});
|
||||
},
|
||||
[setSettingModalAtom]
|
||||
);
|
||||
const handleClick = useCatchEventCallback(() => {
|
||||
setSettingModalAtom({
|
||||
open: true,
|
||||
activeTab: 'plans',
|
||||
scrollAnchor: 'cloudPricingPlan',
|
||||
});
|
||||
}, [setSettingModalAtom]);
|
||||
|
||||
const t = useI18n();
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
import { Avatar } from '@affine/component/ui/avatar';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { useCatchEventCallback } from '@affine/core/hooks/use-catch-event-hook';
|
||||
import { track } from '@affine/core/mixpanel';
|
||||
import { SubscriptionPlan } from '@affine/graphql';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
@@ -17,7 +18,7 @@ import {
|
||||
useServices,
|
||||
} from '@toeverything/infra';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import type { FC, MouseEvent } from 'react';
|
||||
import type { FC } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import {
|
||||
@@ -53,14 +54,10 @@ export const UserAvatar = () => {
|
||||
[session]
|
||||
);
|
||||
|
||||
const handleRemoveUserAvatar = useAsyncCallback(
|
||||
async (e: MouseEvent<HTMLButtonElement>) => {
|
||||
track.$.settingsPanel.accountSettings.removeAvatar();
|
||||
e.stopPropagation();
|
||||
await session.removeAvatar();
|
||||
},
|
||||
[session]
|
||||
);
|
||||
const handleRemoveUserAvatar = useCatchEventCallback(async () => {
|
||||
track.$.settingsPanel.accountSettings.removeAvatar();
|
||||
await session.removeAvatar();
|
||||
}, [session]);
|
||||
|
||||
return (
|
||||
<Upload
|
||||
|
||||
@@ -2,14 +2,14 @@ import { FlexWrapper, Input, notify, Wrapper } from '@affine/component';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { WorkspaceAvatar } from '@affine/component/workspace-avatar';
|
||||
import { Upload } from '@affine/core/components/pure/file-upload';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { useCatchEventCallback } from '@affine/core/hooks/use-catch-event-hook';
|
||||
import { WorkspacePermissionService } from '@affine/core/modules/permissions';
|
||||
import { validateAndReduceImage } from '@affine/core/utils/reduce-image';
|
||||
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { CameraIcon } from '@blocksuite/icons/rc';
|
||||
import { useLiveData, useService, WorkspaceService } from '@toeverything/infra';
|
||||
import type { KeyboardEvent, MouseEvent } from 'react';
|
||||
import type { KeyboardEvent } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import * as style from './style.css';
|
||||
@@ -106,13 +106,9 @@ export const ProfilePanel = () => {
|
||||
handleUpdateWorkspaceName(input);
|
||||
}, [handleUpdateWorkspaceName, input]);
|
||||
|
||||
const handleRemoveUserAvatar = useAsyncCallback(
|
||||
async (e: MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation();
|
||||
await setWorkspaceAvatar(null);
|
||||
},
|
||||
[setWorkspaceAvatar]
|
||||
);
|
||||
const handleRemoveUserAvatar = useCatchEventCallback(async () => {
|
||||
await setWorkspaceAvatar(null);
|
||||
}, [setWorkspaceAvatar]);
|
||||
|
||||
const handleUploadAvatar = useCallback(
|
||||
(file: File) => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useCatchEventCallback } from '@affine/core/hooks/use-catch-event-hook';
|
||||
import { track } from '@affine/core/mixpanel';
|
||||
import { CloseIcon, DownloadIcon } from '@blocksuite/icons/rc';
|
||||
import clsx from 'clsx';
|
||||
@@ -15,7 +16,7 @@ export function AppDownloadButton({
|
||||
}) {
|
||||
const [show, setShow] = useState(true);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
const handleClose = useCatchEventCallback(() => {
|
||||
setShow(false);
|
||||
}, []);
|
||||
|
||||
@@ -39,13 +40,7 @@ export function AppDownloadButton({
|
||||
<DownloadIcon className={styles.icon} />
|
||||
<span className={styles.ellipsisTextOverflow}>Download App</span>
|
||||
</div>
|
||||
<div
|
||||
className={styles.closeIcon}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
handleClose();
|
||||
}}
|
||||
>
|
||||
<div className={styles.closeIcon} onClick={handleClose}>
|
||||
<CloseIcon />
|
||||
</div>
|
||||
<div className={styles.particles} aria-hidden="true"></div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Tooltip } from '@affine/component';
|
||||
import { useCatchEventCallback } from '@affine/core/hooks/use-catch-event-hook';
|
||||
import { popupWindow } from '@affine/core/utils';
|
||||
import { Unreachable } from '@affine/env/constant';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
@@ -118,13 +119,9 @@ function OpenDownloadPage({ updateAvailable }: ButtonContentProps) {
|
||||
|
||||
function WhatsNew({ onDismissChangelog }: ButtonContentProps) {
|
||||
const t = useI18n();
|
||||
const onClickClose: React.MouseEventHandler = useCallback(
|
||||
e => {
|
||||
onDismissChangelog();
|
||||
e.stopPropagation();
|
||||
},
|
||||
[onDismissChangelog]
|
||||
);
|
||||
const onClickClose = useCatchEventCallback(() => {
|
||||
onDismissChangelog();
|
||||
}, [onDismissChangelog]);
|
||||
return (
|
||||
<>
|
||||
<div className={clsx([styles.whatsNewLabel])}>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Menu } from '@affine/component';
|
||||
import { useCatchEventCallback } from '@affine/core/hooks/use-catch-event-hook';
|
||||
import type { Tag } from '@affine/core/modules/tag';
|
||||
import { CloseIcon, MoreHorizontalIcon } from '@blocksuite/icons/rc';
|
||||
import { LiveData, useLiveData } from '@toeverything/infra';
|
||||
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||
import clsx from 'clsx';
|
||||
import type { MouseEventHandler } from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { stopPropagation } from '../utils';
|
||||
import * as styles from './page-tags.css';
|
||||
@@ -62,13 +62,9 @@ export const TagItem = ({
|
||||
}: TagItemProps) => {
|
||||
const value = useLiveData(tag?.value$);
|
||||
const color = useLiveData(tag?.color$);
|
||||
const handleRemove: MouseEventHandler = useCallback(
|
||||
e => {
|
||||
e.stopPropagation();
|
||||
onRemoved?.();
|
||||
},
|
||||
[onRemoved]
|
||||
);
|
||||
const handleRemove = useCatchEventCallback(() => {
|
||||
onRemoved?.();
|
||||
}, [onRemoved]);
|
||||
return (
|
||||
<div
|
||||
data-testid="page-tag"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Button, Input, Modal } from '@affine/component';
|
||||
import { useCatchEventCallback } from '@affine/core/hooks/use-catch-event-hook';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import type { KeyboardEvent } from 'react';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
@@ -74,7 +75,7 @@ export const CreateCollection = ({
|
||||
}
|
||||
onConfirm(value);
|
||||
}, [onConfirm, value, isNameEmpty]);
|
||||
const onKeyDown = useCallback(
|
||||
const onKeyDown = useCatchEventCallback(
|
||||
(e: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === 'Escape') {
|
||||
if (isNameEmpty) {
|
||||
@@ -83,7 +84,6 @@ export const CreateCollection = ({
|
||||
e.currentTarget.blur();
|
||||
}
|
||||
}
|
||||
e.stopPropagation();
|
||||
},
|
||||
[isNameEmpty]
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { type DependencyList } from 'react';
|
||||
|
||||
export type AsyncErrorHandler = (error: Error) => void;
|
||||
|
||||
@@ -17,7 +17,7 @@ export const AsyncCallbackContext = React.createContext<AsyncErrorHandler>(
|
||||
*/
|
||||
export function useAsyncCallback<T extends any[]>(
|
||||
callback: (...args: T) => Promise<void>,
|
||||
deps: any[]
|
||||
deps: DependencyList
|
||||
): (...args: T) => void {
|
||||
const handleAsyncError = React.useContext(AsyncCallbackContext);
|
||||
return React.useCallback(
|
||||
|
||||
17
packages/frontend/core/src/hooks/use-catch-event-hook.ts
Normal file
17
packages/frontend/core/src/hooks/use-catch-event-hook.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { type DependencyList, type SyntheticEvent } from 'react';
|
||||
|
||||
import { useAsyncCallback } from './affine-async-hooks';
|
||||
|
||||
export const useCatchEventCallback = <E extends SyntheticEvent>(
|
||||
cb: (e: E) => void | Promise<void>,
|
||||
deps: DependencyList
|
||||
) => {
|
||||
return useAsyncCallback(
|
||||
async (e: E) => {
|
||||
e.stopPropagation();
|
||||
await cb(e);
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
deps
|
||||
);
|
||||
};
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import { appSidebarWidthAtom } from '@affine/core/components/app-sidebar/index.jotai';
|
||||
import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { useCatchEventCallback } from '@affine/core/hooks/use-catch-event-hook';
|
||||
import type { AffineDNDData } from '@affine/core/types/dnd';
|
||||
import { apis, events } from '@affine/electron-api';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
@@ -92,15 +93,19 @@ const WorkbenchTab = ({
|
||||
},
|
||||
[tabsHeaderService, workbench.id]
|
||||
);
|
||||
const onCloseTab: MouseEventHandler = useAsyncCallback(
|
||||
const handleAuxClick: MouseEventHandler = useCatchEventCallback(
|
||||
async e => {
|
||||
e.stopPropagation();
|
||||
|
||||
await tabsHeaderService.closeTab?.(workbench.id);
|
||||
if (e.button === 1) {
|
||||
await tabsHeaderService.closeTab?.(workbench.id);
|
||||
}
|
||||
},
|
||||
[tabsHeaderService, workbench.id]
|
||||
);
|
||||
|
||||
const handleCloseTab = useCatchEventCallback(async () => {
|
||||
await tabsHeaderService.closeTab?.(workbench.id);
|
||||
}, [tabsHeaderService, workbench.id]);
|
||||
|
||||
const { dropTargetRef, closestEdge } = useDropTarget<AffineDNDData>(
|
||||
() => ({
|
||||
closestEdge: {
|
||||
@@ -154,6 +159,7 @@ const WorkbenchTab = ({
|
||||
onContextMenu={() => {
|
||||
onContextMenu(viewIdx);
|
||||
}}
|
||||
onAuxClick={handleAuxClick}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
onActivateView(viewIdx);
|
||||
@@ -185,7 +191,7 @@ const WorkbenchTab = ({
|
||||
<button
|
||||
data-testid="close-tab-button"
|
||||
className={styles.tabCloseButton}
|
||||
onClick={onCloseTab}
|
||||
onClick={handleCloseTab}
|
||||
>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { useCatchEventCallback } from '@affine/core/hooks/use-catch-event-hook';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { type To } from 'history';
|
||||
import { forwardRef, type MouseEvent } from 'react';
|
||||
@@ -21,10 +21,9 @@ export const WorkbenchLink = forwardRef<
|
||||
const link =
|
||||
basename +
|
||||
(typeof to === 'string' ? to : `${to.pathname}${to.search}${to.hash}`);
|
||||
const handleClick = useAsyncCallback(
|
||||
const handleClick = useCatchEventCallback(
|
||||
async (event: React.MouseEvent<HTMLAnchorElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (onClick?.(event) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user