Skip to content

Commit b46392f

Browse files
committed
Merge branch 'main' into testing-session-fixes
2 parents 1a13e2f + 939205c commit b46392f

File tree

8 files changed

+94
-40
lines changed

8 files changed

+94
-40
lines changed

bin/pure-render.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ module.exports = {
5252
node.type === 'IfStatement' &&
5353
node.test.type === 'BinaryExpression' &&
5454
(node.test.operator === '==' || node.test.operator === '===') &&
55-
isMemberExpressionEqual(node.test.left, member)
55+
(isMemberExpressionEqual(node.test.left, member) ||
56+
isMemberExpressionEqual(node.test.right, member))
5657
) {
5758
conditional = node.test;
5859
}
@@ -98,7 +99,7 @@ module.exports = {
9899
type: 'Identifier',
99100
name: 'undefined'
100101
};
101-
if (isLiteralEqual(conditional.operator, init, conditional.right)) {
102+
if (isLiteralEqual(conditional.operator, init, conditional.right) || isLiteralEqual(conditional.operator, init, conditional.left)) {
102103
return;
103104
}
104105
}

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@
140140
"babel-plugin-transform-glob-import": "^1.0.1",
141141
"babelify": "^10.0.0",
142142
"chalk": "^4.1.2",
143-
"chromatic": "^11.3.0",
143+
"chromatic": "^11.25.2",
144144
"clsx": "^2.0.0",
145145
"color-space": "^1.16.0",
146146
"concurrently": "^6.0.2",

packages/@react-aria/utils/src/mergeProps.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
3434
* @param args - Multiple sets of props to merge together.
3535
*/
3636
export function mergeProps<T extends PropsArg[]>(...args: T): UnionToIntersection<TupleTypes<T>> {
37-
// Start with a base clone of the first argument. This is a lot faster than starting
37+
// Start with a base clone of the last argument. This is a lot faster than starting
3838
// with an empty object and adding properties as we go.
39-
let result: Props = {...args[0]};
40-
for (let i = 1; i < args.length; i++) {
39+
let result: Props = {...args[args.length - 1]};
40+
for (let i = args.length - 2; i >= 0; i--) {
4141
let props = args[i];
4242
for (let key in props) {
4343
let a = result[key];
@@ -53,20 +53,20 @@ export function mergeProps<T extends PropsArg[]>(...args: T): UnionToIntersectio
5353
key.charCodeAt(2) >= /* 'A' */ 65 &&
5454
key.charCodeAt(2) <= /* 'Z' */ 90
5555
) {
56-
result[key] = chain(a, b);
56+
result[key] = chain(b, a);
5757

5858
// Merge classnames, sometimes classNames are empty string which eval to false, so we just need to do a type check
5959
} else if (
6060
(key === 'className' || key === 'UNSAFE_className') &&
6161
typeof a === 'string' &&
6262
typeof b === 'string'
6363
) {
64-
result[key] = clsx(a, b);
64+
result[key] = clsx(b, a);
6565
} else if (key === 'id' && a && b) {
66-
result.id = mergeIds(a, b);
66+
result.id = mergeIds(b, a);
6767
// Override others
68-
} else {
69-
result[key] = b !== undefined ? b : a;
68+
} else if (a === undefined) {
69+
result[key] = b;
7070
}
7171
}
7272
}

packages/@react-aria/utils/src/useId.ts

+6-5
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,15 @@ export function useId(defaultId?: string): string {
5454
};
5555
}, [res]);
5656

57-
// This cannot cause an infinite loop because the ref is updated first.
57+
// This cannot cause an infinite loop because the ref is always cleaned up.
5858
// eslint-disable-next-line
5959
useEffect(() => {
6060
let newId = nextId.current;
61-
if (newId) {
62-
nextId.current = null;
63-
setValue(newId);
64-
}
61+
if (newId) { setValue(newId); }
62+
63+
return () => {
64+
if (newId) { nextId.current = null; }
65+
};
6566
});
6667

6768
return res;

packages/@react-aria/utils/test/mergeProps.test.js packages/@react-aria/utils/test/mergeProps.test.jsx

+52-14
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@
1111
*/
1212

1313
import clsx from 'clsx';
14-
import {mergeIds} from '../src/useId';
15-
import {mergeProps} from '../';
16-
14+
import { mergeIds, useId } from '../src/useId';
15+
import { mergeProps } from '../src/mergeProps';
16+
import { render } from '@react-spectrum/test-utils-internal';
1717

1818
describe('mergeProps', function () {
1919
it('handles one argument', function () {
20-
let onClick = () => {};
20+
let onClick = () => { };
2121
let className = 'primary';
2222
let id = 'test_id';
23-
let mergedProps = mergeProps({onClick, className, id});
23+
let mergedProps = mergeProps({ onClick, className, id });
2424
expect(mergedProps.onClick).toBe(onClick);
2525
expect(mergedProps.className).toBe(className);
2626
expect(mergedProps.id).toBe(id);
@@ -32,9 +32,9 @@ describe('mergeProps', function () {
3232
let message2 = 'click2';
3333
let message3 = 'click3';
3434
let mergedProps = mergeProps(
35-
{onClick: () => mockFn(message1)},
36-
{onClick: () => mockFn(message2)},
37-
{onClick: () => mockFn(message3)}
35+
{ onClick: () => mockFn(message1) },
36+
{ onClick: () => mockFn(message2) },
37+
{ onClick: () => mockFn(message3) }
3838
);
3939
mergedProps.onClick();
4040
expect(mockFn).toHaveBeenNthCalledWith(1, message1);
@@ -51,14 +51,15 @@ describe('mergeProps', function () {
5151
let focus = 'focus';
5252
let margin = 2;
5353
const mergedProps = mergeProps(
54-
{onClick: () => mockFn(click1)},
55-
{onHover: () => mockFn(hover), styles: {margin}},
56-
{onClick: () => mockFn(click2), onFocus: () => mockFn(focus)}
54+
{ onClick: () => mockFn(click1) },
55+
{ onHover: () => mockFn(hover), styles: { margin } },
56+
{ onClick: () => mockFn(click2), onFocus: () => mockFn(focus) }
5757
);
58-
5958
mergedProps.onClick();
59+
let callOrder = mockFn.mock.invocationCallOrder;
6060
expect(mockFn).toHaveBeenNthCalledWith(1, click1);
6161
expect(mockFn).toHaveBeenNthCalledWith(2, click2);
62+
expect(callOrder[0]).toBeLessThan(callOrder[1]);
6263
mergedProps.onFocus();
6364
expect(mockFn).toHaveBeenNthCalledWith(3, focus);
6465
mergedProps.onHover();
@@ -71,7 +72,7 @@ describe('mergeProps', function () {
7172
let className1 = 'primary';
7273
let className2 = 'hover';
7374
let className3 = 'focus';
74-
let mergedProps = mergeProps({className: className1}, {className: className2}, {className: className3});
75+
let mergedProps = mergeProps({ className: className1 }, { className: className2 }, { className: className3 });
7576
let mergedClassNames = clsx(className1, className2, className3);
7677
expect(mergedProps.className).toBe(mergedClassNames);
7778
});
@@ -80,8 +81,45 @@ describe('mergeProps', function () {
8081
let id1 = 'id1';
8182
let id2 = 'id2';
8283
let id3 = 'id3';
83-
let mergedProps = mergeProps({id: id1}, {id: id2}, {id: id3});
84+
let mergedProps = mergeProps({ id: id1 }, { id: id2 }, { id: id3 });
8485
let mergedIds = mergeIds(mergeIds(id1, id2), id3);
8586
expect(mergedProps.id).toBe(mergedIds);
8687
});
88+
89+
it('combines ids with aria ids', function () {
90+
let Spy = jest.fn((props) => <div {...props} />);
91+
92+
const Component = () => {
93+
let id1 = 'id1';
94+
let id2 = useId('id2');
95+
96+
mergeProps({ id: id1 }, { id: id2 });
97+
98+
return <Spy id={id2} />
99+
};
100+
101+
render(<Component />);
102+
103+
// We use stringMatching to support optional refs in React 19.
104+
expect(Spy).toHaveBeenCalledWith({ id: 'id2' }, expect.not.stringMatching(/\A(?!x)x/));
105+
expect(Spy).toHaveBeenLastCalledWith({ id: 'id1' }, expect.not.stringMatching(/\A(?!x)x/));
106+
});
107+
108+
it('combines reoccuring ids', function () {
109+
const Component = () => {
110+
let id1 = useId('id1');
111+
let id2 = useId('id2');
112+
113+
return <div {...mergeProps({ id: id1 }, { id: id2 }, { id: id1 })} />;
114+
};
115+
116+
expect(() => render(<Component />)).not.toThrow();
117+
});
118+
119+
it('overrides other props', function () {
120+
let id1 = 'id1';
121+
let id2 = 'id2';
122+
let mergedProps = mergeProps({ data: id1 }, { data: id2 });
123+
expect(mergedProps.data).toBe(id2);
124+
});
87125
});

packages/@react-spectrum/datepicker/src/styles.css

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
}
8989

9090
.react-spectrum-Datepicker-segments {
91-
display: inline;
91+
display: inline-block;
9292
align-items: center;
9393
}
9494

packages/@react-spectrum/s2/src/Image.tsx

+18-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {ContextValue, SlotProps} from 'react-aria-components';
2-
import {createContext, ForwardedRef, forwardRef, HTMLAttributeReferrerPolicy, ReactNode, useCallback, useContext, useMemo, useReducer, useRef} from 'react';
2+
import {createContext, ForwardedRef, forwardRef, HTMLAttributeReferrerPolicy, ReactNode, useCallback, useContext, useMemo, useReducer, useRef, version} from 'react';
33
import {DefaultImageGroup, ImageGroup} from './ImageCoordinator';
44
import {loadingStyle, useIsSkeleton, useLoadingAnimation} from './Skeleton';
55
import {mergeStyles} from '../style/runtime';
@@ -27,8 +27,11 @@ export interface ImageProps extends UnsafeStyles, SlotProps {
2727
* [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#decoding).
2828
*/
2929
decoding?: 'async' | 'auto' | 'sync',
30-
// Only supported in React 19...
31-
// fetchPriority?: 'high' | 'low' | 'auto',
30+
/**
31+
* Provides a hint of the relative priority to use when fetching the image.
32+
* [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#fetchpriority).
33+
*/
34+
fetchPriority?: 'high' | 'low' | 'auto',
3235
/**
3336
* Whether the image should be loaded immediately or lazily when scrolled into view.
3437
* [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#loading).
@@ -146,6 +149,7 @@ export const Image = forwardRef(function Image(props: ImageProps, domRef: Forwar
146149
alt,
147150
crossOrigin,
148151
decoding,
152+
fetchPriority,
149153
loading,
150154
referrerPolicy,
151155
slot
@@ -223,6 +227,7 @@ export const Image = forwardRef(function Image(props: ImageProps, domRef: Forwar
223227
{errorState}
224228
{!errorState && (
225229
<img
230+
{...getFetchPriorityProp(fetchPriority)}
226231
src={src}
227232
alt={alt}
228233
crossOrigin={crossOrigin}
@@ -235,5 +240,14 @@ export const Image = forwardRef(function Image(props: ImageProps, domRef: Forwar
235240
className={imgStyles({isRevealed, isTransitioning})} />
236241
)}
237242
</div>
238-
), [slot, hidden, domRef, UNSAFE_style, UNSAFE_className, styles, isAnimating, errorState, src, alt, crossOrigin, decoding, loading, referrerPolicy, onLoad, onError, isRevealed, isTransitioning]);
243+
), [slot, hidden, domRef, UNSAFE_style, UNSAFE_className, styles, isAnimating, errorState, src, alt, crossOrigin, decoding, fetchPriority, loading, referrerPolicy, onLoad, onError, isRevealed, isTransitioning]);
239244
});
245+
246+
function getFetchPriorityProp(fetchPriority?: 'high' | 'low' | 'auto'): Record<string, string | undefined> {
247+
const pieces = version.split('.');
248+
const major = parseInt(pieces[0], 10);
249+
if (major >= 19) {
250+
return {fetchPriority};
251+
}
252+
return {fetchpriority: fetchPriority};
253+
}

yarn.lock

+5-5
Original file line numberDiff line numberDiff line change
@@ -14370,9 +14370,9 @@ __metadata:
1437014370
languageName: node
1437114371
linkType: hard
1437214372

14373-
"chromatic@npm:^11.3.0":
14374-
version: 11.3.0
14375-
resolution: "chromatic@npm:11.3.0"
14373+
"chromatic@npm:^11.25.2":
14374+
version: 11.25.2
14375+
resolution: "chromatic@npm:11.25.2"
1437614376
peerDependencies:
1437714377
"@chromatic-com/cypress": ^0.*.* || ^1.0.0
1437814378
"@chromatic-com/playwright": ^0.*.* || ^1.0.0
@@ -14385,7 +14385,7 @@ __metadata:
1438514385
chroma: dist/bin.js
1438614386
chromatic: dist/bin.js
1438714387
chromatic-cli: dist/bin.js
14388-
checksum: 10c0/e977ef43a43ebb0250ec8fc46f5751c8cb9b798f75fcf9ec52485c1127caf9d6cef0346a9dd1660a8967faf1a7cde579571a0ac130cfaf475d6f22e4929003b6
14388+
checksum: 10c0/2cb4bb40a062005292a4cd606321f6c9bdaa31e255e66bae12c780bca9b72e883c017ebe48c5a9228db88a010f5977571ef7dfdcdd4195ad0e7b955f9966d7df
1438914389
languageName: node
1439014390
linkType: hard
1439114391

@@ -29355,7 +29355,7 @@ __metadata:
2935529355
babel-plugin-transform-glob-import: "npm:^1.0.1"
2935629356
babelify: "npm:^10.0.0"
2935729357
chalk: "npm:^4.1.2"
29358-
chromatic: "npm:^11.3.0"
29358+
chromatic: "npm:^11.25.2"
2935929359
clsx: "npm:^2.0.0"
2936029360
color-space: "npm:^1.16.0"
2936129361
concurrently: "npm:^6.0.2"

0 commit comments

Comments
 (0)