Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"dependencies": {
"@rc-component/portal": "^2.0.0",
"@rc-component/motion": "^1.0.0",
"@rc-component/util": "^1.0.0",
"@rc-component/util": "^1.3.0",
"classnames": "^2.2.6"
},
"devDependencies": {
Expand Down
26 changes: 15 additions & 11 deletions src/Image.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import useMergedState from '@rc-component/util/lib/hooks/useMergedState';
import useControlledState from '@rc-component/util/lib/hooks/useControlledState';
import classnames from 'classnames';
import * as React from 'react';
import { useContext, useMemo, useState } from 'react';
Expand Down Expand Up @@ -125,18 +125,18 @@ const ImageInternal: CompoundedComponent<ImageProps> = props => {
...restProps
}: PreviewConfig = preview && typeof preview === 'object' ? preview : {};

const coverPlacement = typeof cover === 'object' && (cover as CoverConfig).placement ?
(cover as CoverConfig).placement || 'center' :
'center';
const coverPlacement =
typeof cover === 'object' && (cover as CoverConfig).placement
? (cover as CoverConfig).placement || 'center'
: 'center';

const coverNode = typeof cover === 'object' && (cover as CoverConfig).coverNode ?
(cover as CoverConfig).coverNode :
cover as React.ReactNode;
const coverNode =
typeof cover === 'object' && (cover as CoverConfig).coverNode
? (cover as CoverConfig).coverNode
: (cover as React.ReactNode);

Comment on lines +128 to 137
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

cover 为 null 时会运行时崩溃,需空值与 ReactElement 判定

typeof cover === 'object'cover === null 时仍为 true,随后访问 (cover as CoverConfig).placement/coverNode 会抛异常。此外 React 元素同为 object,建议排除 ReactElement。

可按下述方式修复(同时简化判定):

-  const coverPlacement =
-    typeof cover === 'object' && (cover as CoverConfig).placement
-      ? (cover as CoverConfig).placement || 'center'
-      : 'center';
-
-  const coverNode =
-    typeof cover === 'object' && (cover as CoverConfig).coverNode
-      ? (cover as CoverConfig).coverNode
-      : (cover as React.ReactNode);
+  const coverObj =
+    cover && typeof cover === 'object' && !React.isValidElement(cover)
+      ? (cover as CoverConfig)
+      : undefined;
+  const coverPlacement = coverObj?.placement ?? 'center';
+  const coverNode = coverObj?.coverNode ?? (cover as React.ReactNode);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const coverPlacement =
typeof cover === 'object' && (cover as CoverConfig).placement
? (cover as CoverConfig).placement || 'center'
: 'center';
const coverNode = typeof cover === 'object' && (cover as CoverConfig).coverNode ?
(cover as CoverConfig).coverNode :
cover as React.ReactNode;
const coverNode =
typeof cover === 'object' && (cover as CoverConfig).coverNode
? (cover as CoverConfig).coverNode
: (cover as React.ReactNode);
const coverObj =
cover && typeof cover === 'object' && !React.isValidElement(cover)
? (cover as CoverConfig)
: undefined;
const coverPlacement = coverObj?.placement ?? 'center';
const coverNode = coverObj?.coverNode ?? (cover as React.ReactNode);
🤖 Prompt for AI Agents
In src/Image.tsx around lines 128 to 137, the current checks use typeof cover
=== 'object' which is true for null and for React elements, causing runtime
crashes; update the logic to first guard against null/undefined and React
elements (use cover != null and React.isValidElement(cover) to exclude React
nodes), then safely access placement and coverNode with optional chaining and
provide 'center'/default ReactNode fallbacks; simplify to: check cover is
non-null, not a React element, then read (cover as CoverConfig)?.placement and
(cover as CoverConfig)?.coverNode with defaults.

// ============================ Open ============================
const [isShowPreview, setShowPreview] = useMergedState(!!previewOpen, {
value: previewOpen,
});
const [isShowPreview, setShowPreview] = useControlledState(!!previewOpen, previewOpen);

const [mousePosition, setMousePosition] = useState<null | { x: number; y: number }>(null);

Expand Down Expand Up @@ -249,7 +249,11 @@ const ImageInternal: CompoundedComponent<ImageProps> = props => {
{/* Preview Click Mask */}
{cover !== false && canPreview && (
<div
className={classnames(`${prefixCls}-cover`, classNames.cover, `${prefixCls}-cover-${coverPlacement}`)}
className={classnames(
`${prefixCls}-cover`,
classNames.cover,
`${prefixCls}-cover-${coverPlacement}`,
)}
style={{
display: style?.display === 'none' ? 'none' : undefined,
...styles.cover,
Expand Down
17 changes: 7 additions & 10 deletions src/PreviewGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import useMergedState from '@rc-component/util/lib/hooks/useMergedState';
import useControlledState from '@rc-component/util/lib/hooks/useControlledState';
import * as React from 'react';
import { useState } from 'react';
import type { ImgInfo } from './Image';
Expand Down Expand Up @@ -60,21 +60,18 @@ const Group: React.FC<PreviewGroupProps> = ({

// ========================= Preview ==========================
// >>> Index
const [current, setCurrent] = useMergedState(0, {
value: currentIndex,
});
const [current, setCurrent] = useControlledState(0, currentIndex);

const [keepOpenIndex, setKeepOpenIndex] = useState(false);

// >>> Image
const { src, ...imgCommonProps } = mergedItems[current]?.data || {};
// >>> Visible
const [isShowPreview, setShowPreview] = useMergedState(!!previewOpen, {
value: previewOpen,
onChange: val => {
onOpenChange?.(val, { current });
},
});
const [isShowPreview, setShowPreview] = useControlledState(!!previewOpen, previewOpen);

React.useEffect(() => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不等价,直接封装:

const triggerShowPreview = useEvent(next => {
  setShowPreview(next);
    if (next  !== ...
});

onOpenChange?.(isShowPreview, { current });
}, [isShowPreview, current, onOpenChange]);

// >>> Position
const [mousePosition, setMousePosition] = useState<null | { x: number; y: number }>(null);
Expand Down