Skip to content

Commit 4637d34

Browse files
committed
Merge branch 'main' of github.com:adobe/react-spectrum into loadmore_rac
2 parents f35df51 + 493a9ae commit 4637d34

File tree

7 files changed

+107
-109
lines changed

7 files changed

+107
-109
lines changed

packages/@react-aria/selection/src/useSelectableCollection.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,7 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
505505

506506
// Scroll the focused element into view when the focusedKey changes.
507507
let lastFocusedKey = useRef(manager.focusedKey);
508+
let raf = useRef<number | null>(null);
508509
useEffect(() => {
509510
if (manager.isFocused && manager.focusedKey != null && (manager.focusedKey !== lastFocusedKey.current || didAutoFocusRef.current) && scrollRef.current && ref.current) {
510511
let modality = getInteractionModality();
@@ -516,8 +517,16 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
516517
}
517518

518519
if (modality === 'keyboard' || didAutoFocusRef.current) {
519-
scrollIntoView(scrollRef.current, element);
520520

521+
if (raf.current) {
522+
cancelAnimationFrame(raf.current);
523+
}
524+
525+
raf.current = requestAnimationFrame(() => {
526+
if (scrollRef.current) {
527+
scrollIntoView(scrollRef.current, element);
528+
}
529+
});
521530
// Avoid scroll in iOS VO, since it may cause overlay to close (i.e. RAC submenu)
522531
if (modality !== 'virtual') {
523532
scrollIntoViewport(element, {containingElement: ref.current});
@@ -534,6 +543,14 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
534543
didAutoFocusRef.current = false;
535544
});
536545

546+
useEffect(() => {
547+
return () => {
548+
if (raf.current) {
549+
cancelAnimationFrame(raf.current);
550+
}
551+
};
552+
}, []);
553+
537554
// Intercept FocusScope restoration since virtualized collections can reuse DOM nodes.
538555
useEvent(ref, 'react-aria-focus-scope-restore', e => {
539556
e.preventDefault();

packages/@react-spectrum/list/test/ListView.test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ describe('ListView', function () {
7373
afterEach(function () {
7474
fireEvent.keyDown(document.activeElement, {key: 'Escape'});
7575
fireEvent.keyUp(document.activeElement, {key: 'Escape'});
76+
act(() => {jest.runAllTimers();});
7677
jest.clearAllMocks();
7778
});
7879

@@ -1453,27 +1454,33 @@ describe('ListView', function () {
14531454

14541455
// scroll us down far enough that item 0 isn't in the view
14551456
moveFocus('ArrowDown');
1457+
act(() => jest.runAllTimers());
14561458
expect(scrollIntoView).toHaveBeenLastCalledWith(grid, getRow(tree, 'Item 1'));
14571459
grid.scrollTop = 40;
14581460
fireEvent.scroll(grid);
14591461
moveFocus('ArrowDown');
1462+
act(() => jest.runAllTimers());
14601463
expect(scrollIntoView).toHaveBeenLastCalledWith(grid, getRow(tree, 'Item 2'));
14611464
grid.scrollTop = 80;
14621465
fireEvent.scroll(grid);
14631466
moveFocus('ArrowDown');
1467+
act(() => jest.runAllTimers());
14641468
expect(scrollIntoView).toHaveBeenLastCalledWith(grid, getRow(tree, 'Item 3'));
14651469
grid.scrollTop = 120;
14661470
fireEvent.scroll(grid);
14671471

14681472
moveFocus('ArrowUp');
1473+
act(() => jest.runAllTimers());
14691474
expect(scrollIntoView).toHaveBeenLastCalledWith(grid, getRow(tree, 'Item 2'));
14701475
grid.scrollTop = 80;
14711476
fireEvent.scroll(grid);
14721477
moveFocus('ArrowUp');
1478+
act(() => jest.runAllTimers());
14731479
expect(scrollIntoView).toHaveBeenLastCalledWith(grid, getRow(tree, 'Item 1'));
14741480
grid.scrollTop = 40;
14751481
fireEvent.scroll(grid);
14761482
moveFocus('ArrowUp');
1483+
act(() => jest.runAllTimers());
14771484
expect(scrollIntoView).toHaveBeenLastCalledWith(grid, getRow(tree, 'Item 0'));
14781485
});
14791486

@@ -1506,6 +1513,7 @@ describe('ListView', function () {
15061513
});
15071514

15081515
focusRow(tree, 'Item 1');
1516+
act(() => jest.runAllTimers());
15091517
expect(document.activeElement).toBe(getRow(tree, 'Item 1'));
15101518
expect(scrollIntoView).toHaveBeenLastCalledWith(grid, document.activeElement);
15111519
});
@@ -1539,6 +1547,7 @@ describe('ListView', function () {
15391547

15401548
// Moving focus should scroll the new focused item into view
15411549
moveFocus('ArrowDown');
1550+
act(() => jest.runAllTimers());
15421551
expect(document.activeElement).toBe(getRow(tree, 'Item 1'));
15431552
expect(scrollIntoView).toHaveBeenLastCalledWith(body, document.activeElement);
15441553
});

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

Lines changed: 29 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -28,39 +28,35 @@ import {
2828
ListLayout,
2929
Provider,
3030
SectionProps,
31-
SeparatorContext,
32-
SeparatorProps,
3331
UNSTABLE_ListBoxLoadingSentinel,
34-
useContextProps,
3532
Virtualizer
3633
} from 'react-aria-components';
3734
import {AsyncLoadable, HelpTextProps, LoadingState, SpectrumLabelableProps} from '@react-types/shared';
3835
import {baseColor, edgeToText, focusRing, space, style} from '../style' with {type: 'macro'};
3936
import {centerBaseline} from './CenterBaseline';
40-
import {centerPadding, controlBorderRadius, controlFont, controlSize, field, fieldInput, getAllowedOverrides, StyleProps} from './style-utils' with {type: 'macro'};
37+
import {centerPadding, control, controlBorderRadius, controlFont, controlSize, field, fieldInput, getAllowedOverrides, StyleProps} from './style-utils' with {type: 'macro'};
4138
import {
4239
checkmark,
4340
description,
4441
icon,
4542
iconCenterWrapper,
46-
label
43+
label,
44+
sectionHeading
4745
} from './Menu';
4846
import CheckmarkIcon from '../ui-icons/Checkmark';
4947
import ChevronIcon from '../ui-icons/Chevron';
50-
import {createContext, CSSProperties, ElementType, ForwardedRef, forwardRef, ReactNode, Ref, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react';
48+
import {createContext, CSSProperties, ForwardedRef, forwardRef, ReactNode, Ref, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react';
5149
import {createFocusableRef} from '@react-spectrum/utils';
5250
import {createLeafComponent} from '@react-aria/collections';
53-
import {divider} from './Divider';
5451
import {FieldErrorIcon, FieldGroup, FieldLabel, HelpText, Input} from './Field';
55-
import {filterDOMProps, mergeRefs, useResizeObserver, useSlotId} from '@react-aria/utils';
5652
import {FormContext, useFormProps} from './Form';
5753
import {forwardRefType} from './types';
5854
import {HeaderContext, HeadingContext, Text, TextContext} from './Content';
5955
import {IconContext} from './Icon';
6056
// @ts-ignore
6157
import intlMessages from '../intl/*.json';
62-
import {mergeStyles} from '../style/runtime';
63-
import {Placement, useSeparator} from 'react-aria';
58+
import {mergeRefs, useResizeObserver, useSlotId} from '@react-aria/utils';
59+
import {Placement} from 'react-aria';
6460
import {PopoverBase} from './Popover';
6561
import {pressScale} from './pressScale';
6662
import {ProgressCircle} from './ProgressCircle';
@@ -210,38 +206,34 @@ export let listbox = style<{size: 'S' | 'M' | 'L' | 'XL'}>({
210206
// TODO: Might help with horizontal scrolling happening on Windows, will need to check somehow. Otherwise, revert back to overflow: auto
211207
overflowY: 'auto',
212208
overflowX: 'hidden',
213-
font: controlFont()
209+
fontFamily: 'sans',
210+
fontSize: controlFont()
214211
});
215212

216213
export let listboxItem = style({
217214
...focusRing(),
218-
...controlBorderRadius(),
219-
boxSizing: 'border-box',
220-
font: controlFont(),
221-
'--labelPadding': {
222-
type: 'paddingTop',
223-
value: centerPadding()
224-
},
215+
...control({shape: 'default', wrap: true, icon: true}),
216+
columnGap: 0,
217+
paddingX: 0,
225218
paddingBottom: '--labelPadding',
226219
backgroundColor: {
227220
default: 'transparent',
228221
isFocused: baseColor('gray-100').isFocusVisible
229222
},
230223
color: {
231-
default: 'neutral',
224+
default: baseColor('neutral'),
232225
isDisabled: {
233226
default: 'disabled',
234227
forcedColors: 'GrayText'
235228
}
236229
},
237230
position: 'relative',
238-
// each menu item should take up the entire width, the subgrid will handle within the item
239231
gridColumnStart: 1,
240232
gridColumnEnd: -1,
241233
display: 'grid',
242234
gridTemplateAreas: [
243-
'. checkmark icon label .',
244-
'. . . description .'
235+
'. checkmark icon label .',
236+
'. . . description .'
245237
],
246238
gridTemplateColumns: {
247239
size: {
@@ -285,20 +277,11 @@ export let listboxHeader = style<{size?: 'S' | 'M' | 'L' | 'XL'}>({
285277
}
286278
});
287279

288-
export let listboxHeading = style({
289-
fontSize: 'ui',
290-
fontWeight: 'bold',
291-
lineHeight: 'ui',
292-
margin: 0
293-
});
294-
295-
// not sure why edgeToText won't work...
296280
const separatorWrapper = style({
297281
display: {
298282
':is(:last-child > *)': 'none',
299283
default: 'flex'
300284
},
301-
// A workaround since edgeToText() returns undefined for some reason
302285
marginX: {
303286
size: {
304287
S: `[${edgeToText(24)}]`,
@@ -307,7 +290,18 @@ const separatorWrapper = style({
307290
XL: `[${edgeToText(48)}]`
308291
}
309292
},
310-
height: 12
293+
height: 12,
294+
alignItems: 'center'
295+
});
296+
297+
const dividerStyle = style({
298+
backgroundColor: {
299+
default: 'gray-200',
300+
forcedColors: 'ButtonBorder'
301+
},
302+
borderRadius: 'full',
303+
height: '[2px]',
304+
width: 'full'
311305
});
312306

313307
// Not from any design, just following the sizing of the existing rows
@@ -667,7 +661,7 @@ const ComboboxInner = forwardRef(function ComboboxInner(props: ComboBoxProps<any
667661
<Provider
668662
values={[
669663
[HeaderContext, {styles: listboxHeader({size})}],
670-
[HeadingContext, {styles: listboxHeading}],
664+
[HeadingContext, {styles: sectionHeading}],
671665
[TextContext, {
672666
slots: {
673667
'description': {styles: description({size})}
@@ -700,43 +694,10 @@ const ComboboxInner = forwardRef(function ComboboxInner(props: ComboBoxProps<any
700694
);
701695
});
702696

703-
export function Divider(props: SeparatorProps & {size?: 'S' | 'M' | 'L' | 'XL' | undefined}): ReactNode {
704-
return (
705-
<Separator
706-
{...props}
707-
className={mergeStyles(
708-
divider({
709-
size: 'M',
710-
orientation: 'horizontal',
711-
isStaticColor: false
712-
}, style({alignSelf: 'center', width: 'full'})))} />
713-
);
714-
}
715-
716-
const Separator = /*#__PURE__*/ createLeafComponent('separator', function Separator(props: SeparatorProps & {size?: 'S' | 'M' | 'L' | 'XL'}, ref: ForwardedRef<HTMLElement>) {
717-
[props, ref] = useContextProps(props, ref, SeparatorContext);
718-
719-
let {elementType, orientation, size, style, className, slot, ...otherProps} = props;
720-
let Element = (elementType as ElementType) || 'hr';
721-
if (Element === 'hr' && orientation === 'vertical') {
722-
Element = 'div';
723-
}
724-
725-
let {separatorProps} = useSeparator({
726-
...otherProps,
727-
elementType,
728-
orientation
729-
});
730-
697+
export const Divider = /*#__PURE__*/ createLeafComponent('separator', function Divider({size}: {size?: 'S' | 'M' | 'L' | 'XL'}, ref: ForwardedRef<HTMLDivElement>) {
731698
return (
732699
<div className={separatorWrapper({size})}>
733-
<Element
734-
{...filterDOMProps(props)}
735-
{...separatorProps}
736-
style={style}
737-
className={className ?? 'react-aria-Separator'}
738-
ref={ref}
739-
slot={slot || undefined} />
700+
<div ref={ref} className={dividerStyle} />
740701
</div>
741702
);
742703
});

0 commit comments

Comments
 (0)