mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-02 18:09:58 +08:00
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:
@@ -27,7 +27,12 @@ import {
|
||||
import { useService, WorkspaceService } from '@toeverything/infra';
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import { type ReactElement, useCallback, useState } from 'react';
|
||||
import {
|
||||
type ReactElement,
|
||||
type SVGAttributes,
|
||||
useCallback,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import * as style from './styles.css';
|
||||
|
||||
@@ -222,8 +227,8 @@ const ImportOptionItem = ({
|
||||
onImport,
|
||||
}: {
|
||||
label: string;
|
||||
prefixIcon: ReactElement;
|
||||
suffixIcon?: ReactElement;
|
||||
prefixIcon: ReactElement<SVGAttributes<SVGElement>>;
|
||||
suffixIcon?: ReactElement<SVGAttributes<SVGElement>>;
|
||||
suffixTooltip?: string;
|
||||
type: ImportType;
|
||||
onImport: (type: ImportType) => void;
|
||||
|
||||
+13
-5
@@ -4,7 +4,14 @@ import { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql';
|
||||
import { Trans, useI18n } from '@affine/i18n';
|
||||
import { AfFiNeIcon } from '@blocksuite/icons/rc';
|
||||
import { useLiveData, useServices } from '@toeverything/infra';
|
||||
import { type ReactNode, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import {
|
||||
type ReactNode,
|
||||
type RefObject,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { CloudPlanLayout } from './layout';
|
||||
import { LifetimePlan } from './lifetime/lifetime-plan';
|
||||
@@ -236,7 +243,7 @@ export const CloudPlans = () => {
|
||||
// auto scroll to current plan card
|
||||
useEffect(() => {
|
||||
if (!scrollWrapper.current) return;
|
||||
const currentPlanCard = scrollWrapper.current?.querySelector(
|
||||
const currentPlanCard = scrollWrapper.current.querySelector(
|
||||
'[data-current="true"]'
|
||||
);
|
||||
const wrapperComputedStyle = getComputedStyle(scrollWrapper.current);
|
||||
@@ -247,11 +254,12 @@ export const CloudPlans = () => {
|
||||
: 0;
|
||||
const appeared = scrollWrapper.current.dataset.appeared === 'true';
|
||||
const animationFrameId = requestAnimationFrame(() => {
|
||||
scrollWrapper.current?.scrollTo({
|
||||
if (!scrollWrapper.current) return;
|
||||
scrollWrapper.current.scrollTo({
|
||||
behavior: appeared ? 'smooth' : 'instant',
|
||||
left,
|
||||
});
|
||||
scrollWrapper.current?.setAttribute('data-appeared', 'true');
|
||||
scrollWrapper.current.dataset.appeared = 'true';
|
||||
});
|
||||
return () => {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
@@ -343,7 +351,7 @@ export const CloudPlans = () => {
|
||||
select={cloudSelect}
|
||||
toggle={cloudToggle}
|
||||
scroll={cloudScroll}
|
||||
scrollRef={scrollWrapper}
|
||||
scrollRef={scrollWrapper as RefObject<HTMLDivElement>}
|
||||
lifetime={isOnetimePro ? null : <LifetimePlan />}
|
||||
/>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user