Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
9 changes: 7 additions & 2 deletions src/Image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { TransformType } from './hooks/useImageTransform';
import useRegisterImage from './hooks/useRegisterImage';
import useStatus from './hooks/useStatus';
import type { ImageElementProps } from './interface';
import { getFetchPriorityProps } from './util';

export interface ImgInfo {
url: string;
Expand Down Expand Up @@ -99,6 +100,7 @@ const ImageInternal: CompoundedComponent<ImageProps> = props => {
// Image
src: imgSrc,
alt,
fetchPriority,
placeholder,
fallback,

Expand Down Expand Up @@ -161,7 +163,10 @@ const ImageInternal: CompoundedComponent<ImageProps> = props => {

const imgCommonProps = useMemo(
() => {
const obj: ImageElementProps = {};
const obj: ImageElementProps = {
...getFetchPriorityProps(fetchPriority),
};

COMMON_PROPS.forEach((prop: any) => {
if (props[prop] !== undefined) {
obj[prop] = props[prop];
Expand All @@ -170,7 +175,7 @@ const ImageInternal: CompoundedComponent<ImageProps> = props => {

return obj;
},
Comment on lines 165 to 177
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This useMemo callback can be simplified to improve readability and maintainability. The current implementation uses a long if-else if chain, which is verbose and harder to maintain when adding or removing props.

Consider refactoring this to build the props object more dynamically by separating the generic props from the special case for fetchPriority.

    () => {
      const propsToPass = {
        alt,
        crossOrigin,
        decoding,
        draggable,
        loading,
        referrerPolicy,
        sizes,
        srcSet,
        useMap,
      };

      const obj: Partial<ImageElementProps> = {};
      for (const key in propsToPass) {
        if (Object.prototype.hasOwnProperty.call(propsToPass, key) && propsToPass[key] !== undefined) {
          obj[key] = propsToPass[key];
        }
      }

      Object.assign(obj, getFetchPriorityProps(fetchPriority));

      return obj;
    },

COMMON_PROPS.map(prop => props[prop]),
[fetchPriority, ...COMMON_PROPS.map(prop => props[prop])],
);

// ========================== Register ==========================
Expand Down
15 changes: 12 additions & 3 deletions src/PreviewGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { PreviewGroupContext } from './context';
import type { TransformType } from './hooks/useImageTransform';
import usePreviewItems from './hooks/usePreviewItems';
import type { ImageElementProps, OnGroupPreview } from './interface';
import { getFetchPriorityProps } from './util';

export interface GroupPreviewConfig extends InternalPreviewConfig {
current?: number;
Expand Down Expand Up @@ -66,7 +67,15 @@ const Group: React.FC<PreviewGroupProps> = ({
const [keepOpenIndex, setKeepOpenIndex] = useState(false);

// >>> Image
const { src, ...imgCommonProps } = mergedItems[current]?.data || {};
const { src, ...currentData } = mergedItems[current]?.data || {};
const imgCommonProps = React.useMemo(() => {
const { fetchpriority, ...restImageProps } = currentData;

return {
...restImageProps,
...getFetchPriorityProps(fetchpriority),
};
}, [currentData]);
// >>> Visible
const [isShowPreview, setShowPreview] = useControlledState(!!previewOpen, previewOpen);
const triggerShowPreview = useEvent((next: boolean) => {
Expand All @@ -92,7 +101,7 @@ const Group: React.FC<PreviewGroupProps> = ({

setKeepOpenIndex(true);
},
[mergedItems, fromItems],
[fromItems, mergedItems, setCurrent, triggerShowPreview],
);

// Reset current when reopen
Expand All @@ -104,7 +113,7 @@ const Group: React.FC<PreviewGroupProps> = ({
} else {
setKeepOpenIndex(false);
}
}, [isShowPreview]);
}, [isShowPreview, keepOpenIndex, setCurrent]);

// ========================== Events ==========================
const onInternalChange: GroupPreviewConfig['onChange'] = (next, prev) => {
Expand Down
6 changes: 5 additions & 1 deletion src/interface.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export type FetchPriority = 'high' | 'low' | 'auto';

/**
* Used for PreviewGroup passed image data
*/
Expand All @@ -13,7 +15,9 @@ export type ImageElementProps = Pick<
| 'srcSet'
| 'useMap'
| 'alt'
>;
> & {
fetchpriority?: FetchPriority;
};

export type PreviewImageElementProps = {
data: ImageElementProps;
Expand Down
13 changes: 13 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import * as React from 'react';
import type { FetchPriority } from './interface';

export function isImageValid(src: string) {
return new Promise(resolve => {
if (!src) {
Expand All @@ -11,6 +14,16 @@ export function isImageValid(src: string) {
});
}

export function getFetchPriorityProps(value?: FetchPriority) {
if (!value) {
return {};
}

const major = Number(React.version.split('.')[0]);

return major >= 19 ? { fetchPriority: value } : { fetchpriority: value };
}

// ============================= Legacy =============================
export function getClientSize() {
const width = document.documentElement.clientWidth;
Expand Down
41 changes: 41 additions & 0 deletions tests/fetchPriority.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
describe('getFetchPriorityProps', () => {
afterEach(() => {
jest.resetModules();
jest.dontMock('react');
});

it('uses lowercase fetchpriority for React 18', () => {
jest.doMock('react', () => ({
...jest.requireActual('react'),
version: '18.3.1',
}));

jest.isolateModules(() => {
const { getFetchPriorityProps } = require('../src/util');
expect(getFetchPriorityProps('high')).toEqual({
fetchpriority: 'high',
});
});
});

it('uses camelCase fetchPriority for React 19', () => {
jest.doMock('react', () => ({
...jest.requireActual('react'),
version: '19.2.4',
}));

jest.isolateModules(() => {
const { getFetchPriorityProps } = require('../src/util');
expect(getFetchPriorityProps('high')).toEqual({
fetchPriority: 'high',
});
});
});

it('returns empty props when value is undefined', () => {
jest.isolateModules(() => {
const { getFetchPriorityProps } = require('../src/util');
expect(getFetchPriorityProps()).toEqual({});
});
});
});
7 changes: 6 additions & 1 deletion tests/preview.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -809,11 +809,12 @@ describe('Preview', () => {
);
});

it('pass img common props to previewed image', () => {
it('passes image common props to previewed image', () => {
const { container } = render(
<Image
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
referrerPolicy="no-referrer"
fetchPriority="high"
/>,
);

Expand All @@ -826,6 +827,10 @@ describe('Preview', () => {
'referrerPolicy',
'no-referrer',
);
expect(document.querySelector('.rc-image-preview-img')).toHaveAttribute(
'fetchpriority',
'high',
);
});

describe('actionsRender', () => {
Expand Down
29 changes: 29 additions & 0 deletions tests/previewGroup.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,35 @@ describe('PreviewGroup', () => {
);
});

it('passes fetchpriority to previewed image in group mode', () => {
const { container } = render(
<Image.PreviewGroup>
<Image src="src1" fetchPriority="high" />
<Image src="src2" fetchPriority="low" />
</Image.PreviewGroup>,
);

fireEvent.click(container.querySelector('.rc-image'));
act(() => {
jest.runAllTimers();
});

expect(document.querySelector('.rc-image-preview-img')).toHaveAttribute(
'fetchpriority',
'high',
);

fireEvent.click(document.querySelector('.rc-image-preview-switch-next'));
act(() => {
jest.runAllTimers();
});

expect(document.querySelector('.rc-image-preview-img')).toHaveAttribute(
'fetchpriority',
'low',
);
});

it('album mode', () => {
const { container } = render(
<Image.PreviewGroup items={['src1', 'src2', 'src3']}>
Expand Down