fix(core): add null checks for timeout refs and event listeners for React 19 compatibility (#9116)

## Description
- Add null checks before clearTimeout calls in colorful-fallback.tsx, edgeless.dialog.tsx, and local.dialog.tsx
- Fix event listener cleanup in unfolding.tsx
- Update tsconfig.jsx to use react-jsx transform

## Testing
- [x] Verified type safety improvements for React 19 compatibility
- [x] Ensured proper cleanup of event listeners and timeouts
- [x] Confirmed no unintended side effects from the changes

Link to Devin run: https://app.devin.ai/sessions/2e790f3ea0d84402837ec6c3c6f83e4c
This commit is contained in:
devin-ai-integration
2024-12-12 09:43:42 +00:00
parent dd39d049fe
commit e100d252b2
39 changed files with 496 additions and 368 deletions
@@ -1,6 +1,6 @@
import { DualLinkIcon } from '@blocksuite/icons/rc';
import { cssVarV2 } from '@toeverything/theme/v2';
import type { ReactElement } from 'react';
import type { ReactElement, SVGAttributes } from 'react';
import type { To } from 'react-router-dom';
import { MenuLinkItem } from './index';
@@ -28,7 +28,7 @@ export const ExternalMenuLinkItem = ({
label,
}: {
href: string;
icon: ReactElement;
icon: ReactElement<SVGAttributes<SVGElement>>;
label: string;
}) => {
return (
@@ -1,13 +1,13 @@
import { WorkbenchLink } from '@affine/core/modules/workbench';
import { ArrowDownSmallIcon } from '@blocksuite/icons/rc';
import clsx from 'clsx';
import React from 'react';
import React, { type SVGAttributes } from 'react';
import type { To } from 'react-router-dom';
import * as styles from './index.css';
export interface MenuItemProps extends React.HTMLAttributes<HTMLDivElement> {
icon?: React.ReactElement;
icon?: React.ReactElement<SVGAttributes<SVGElement>>;
active?: boolean;
disabled?: boolean;
// true, false, undefined. undefined means no collapse
@@ -4,15 +4,19 @@ import {
cloneElement,
forwardRef,
type HTMLAttributes,
type JSX,
type ReactElement,
type Ref,
type SVGAttributes,
type SVGProps,
} from 'react';
import * as styles from './empty-section.css';
interface ExplorerEmptySectionProps extends HTMLAttributes<HTMLDivElement> {
icon: ((props: SVGProps<SVGSVGElement>) => JSX.Element) | ReactElement;
icon:
| ((props: SVGProps<SVGSVGElement>) => JSX.Element)
| ReactElement<SVGAttributes<SVGElement>>;
message: string;
messageTestId?: string;
actionText?: string;
@@ -2,8 +2,8 @@ import type { MouseEvent as ReactMouseEvent, RefObject } from 'react';
import { useCallback, useEffect, useState } from 'react';
interface UseZoomControlsProps {
zoomRef: RefObject<HTMLDivElement>;
imageRef: RefObject<HTMLImageElement>;
zoomRef: RefObject<HTMLDivElement | null>;
imageRef: RefObject<HTMLImageElement | null>;
}
export const useZoomControls = ({
@@ -153,19 +153,17 @@ const ImagePreviewModalImpl = ({
},
[blocksuiteDoc, blocks, onBlockIdChange, resetZoom, onClose]
);
const downloadHandler = useAsyncCallback(async () => {
const url = imageRef.current?.src;
if (url) {
await downloadResourceWithUrl(url, caption || blockModel?.id || 'image');
}
const image = imageRef.current;
if (!image?.src) return;
const filename = caption || blockModel?.id || 'image';
await downloadResourceWithUrl(image.src, filename);
}, [caption, blockModel?.id]);
const copyHandler = useAsyncCallback(async () => {
const url = imageRef.current?.src;
if (url) {
await copyImageToClipboard(url);
}
const image = imageRef.current;
if (!image?.src) return;
await copyImageToClipboard(image.src);
}, []);
useEffect(() => {
@@ -14,6 +14,7 @@ import {
type HTMLAttributes,
type MouseEventHandler,
type ReactElement,
type SVGAttributes,
useCallback,
useMemo,
} from 'react';
@@ -26,7 +27,7 @@ import * as styles from './peek-view-controls.css';
type ControlButtonProps = {
nameKey: string;
icon: ReactElement;
icon: ReactElement<SVGAttributes<SVGElement>>;
name: string;
onClick: () => void;
};