Skip to content

Commit 263db83

Browse files
authored
React Aria API improvements (#3264)
1 parent f0c9a59 commit 263db83

File tree

26 files changed

+227
-125
lines changed

26 files changed

+227
-125
lines changed

packages/@adobe/spectrum-css-temp/components/slider/index.css

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,6 @@ governing permissions and limitations under the License.
243243

244244
.spectrum-Slider-handle {
245245
position: absolute;
246-
inset-inline-start: 0;
247246
inset-block-start: calc(var(--spectrum-slider-height) / 2);
248247
z-index: 2;
249248

@@ -253,9 +252,6 @@ governing permissions and limitations under the License.
253252
inline-size: var(--spectrum-slider-handle-width);
254253
block-size: var(--spectrum-slider-handle-height);
255254

256-
margin-block: var(--spectrum-slider-handle-margin-top) 0;
257-
margin-inline: calc(var(--spectrum-slider-handle-width) / -2) 0;
258-
259255
border-width: var(--spectrum-slider-handle-border-size);
260256
border-style: solid;
261257

packages/@react-aria/breadcrumbs/src/useBreadcrumbs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ interface BreadcrumbsAria {
2626
* Provides the behavior and accessibility implementation for a breadcrumbs component.
2727
* Breadcrumbs display a heirarchy of links to the current page or resource in an application.
2828
*/
29-
export function useBreadcrumbs<T>(props: AriaBreadcrumbsProps<T>): BreadcrumbsAria {
29+
export function useBreadcrumbs(props: AriaBreadcrumbsProps): BreadcrumbsAria {
3030
let {
3131
'aria-label': ariaLabel,
3232
...otherProps

packages/@react-aria/color/src/useColorSlider.ts

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -99,30 +99,16 @@ export function useColorSlider(props: ColorSliderAriaOptions, state: ColorSlider
9999
}
100100
};
101101

102-
let thumbPosition = state.getThumbPercent(0);
103-
if (orientation === 'vertical' || direction === 'rtl') {
104-
thumbPosition = 1 - thumbPosition;
105-
}
106-
107102
return {
108103
trackProps: {
109104
...mergeProps(groupProps, trackProps),
110105
style: {
111-
position: 'relative',
112-
touchAction: 'none',
106+
...trackProps.style,
113107
background: generateBackground()
114108
}
115109
},
116110
inputProps,
117-
thumbProps: {
118-
...thumbProps,
119-
style: {
120-
touchAction: 'none',
121-
position: 'absolute',
122-
[orientation === 'vertical' ? 'top' : 'left']: `${thumbPosition * 100}%`,
123-
transform: 'translate(-50%, -50%)'
124-
}
125-
},
111+
thumbProps,
126112
labelProps,
127113
outputProps
128114
};

packages/@react-aria/combobox/src/useComboBox.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export function useComboBox<T>(props: AriaComboBoxOptions<T>, state: ComboBoxSta
7575
} = props;
7676

7777
let formatMessage = useMessageFormatter(intlMessages);
78-
let {menuTriggerProps, menuProps} = useMenuTrigger(
78+
let {menuTriggerProps, menuProps} = useMenuTrigger<T>(
7979
{
8080
type: 'listbox',
8181
isDisabled: isDisabled || isReadOnly

packages/@react-aria/menu/docs/useMenuTrigger.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ the implementation of the button and popup menu respectively.
6161
`useMenuTrigger` returns props that you should spread onto the appropriate element:
6262

6363
<TypeContext.Provider value={docs.links}>
64-
<InterfaceType properties={docs.links[docs.exports.useMenuTrigger.return.id].properties} />
64+
<InterfaceType properties={docs.links[(docs.exports.useMenuTrigger.return.base ?? docs.exports.useMenuTrigger.return).id].properties} />
6565
</TypeContext.Provider>
6666

6767
State is managed by the <TypeLink links={statelyDocs.links} type={statelyDocs.exports.useMenuTriggerState} />

packages/@react-aria/menu/src/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212

13-
export * from './useMenuTrigger';
14-
export * from './useMenu';
15-
export * from './useMenuItem';
16-
export * from './useMenuSection';
13+
export {useMenuTrigger} from './useMenuTrigger';
14+
export {useMenu} from './useMenu';
15+
export {useMenuItem} from './useMenuItem';
16+
export {useMenuSection} from './useMenuSection';

packages/@react-aria/menu/src/useMenu.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
import {AriaMenuProps} from '@react-types/menu';
1414
import {filterDOMProps, mergeProps} from '@react-aria/utils';
15-
import {HTMLAttributes, RefObject} from 'react';
15+
import {HTMLAttributes, Key, RefObject} from 'react';
1616
import {KeyboardDelegate} from '@react-types/shared';
1717
import {TreeState} from '@react-stately/tree';
1818
import {useSelectableList} from '@react-aria/selection';
@@ -22,7 +22,7 @@ interface MenuAria {
2222
menuProps: HTMLAttributes<HTMLElement>
2323
}
2424

25-
interface AriaMenuOptions<T> extends AriaMenuProps<T> {
25+
export interface AriaMenuOptions<T> extends Omit<AriaMenuProps<T>, 'children'> {
2626
/** Whether the menu uses virtual scrolling. */
2727
isVirtualized?: boolean,
2828

@@ -33,6 +33,13 @@ interface AriaMenuOptions<T> extends AriaMenuProps<T> {
3333
keyboardDelegate?: KeyboardDelegate
3434
}
3535

36+
interface MenuData {
37+
onClose?: () => void,
38+
onAction?: (key: Key) => void
39+
}
40+
41+
export const menuData = new WeakMap<TreeState<unknown>, MenuData>();
42+
3643
/**
3744
* Provides the behavior and accessibility implementation for a menu component.
3845
* A menu displays a list of actions or options that a user can choose.
@@ -59,6 +66,11 @@ export function useMenu<T>(props: AriaMenuOptions<T>, state: TreeState<T>, ref:
5966
shouldFocusWrap
6067
});
6168

69+
menuData.set(state, {
70+
onClose: props.onClose,
71+
onAction: props.onAction
72+
});
73+
6274
return {
6375
menuProps: mergeProps(domProps, {
6476
role: 'menu',

packages/@react-aria/menu/src/useMenuItem.ts

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import {getItemCount} from '@react-stately/collections';
1414
import {HTMLAttributes, Key, RefObject} from 'react';
1515
import {isFocusVisible, useHover, usePress} from '@react-aria/interactions';
16+
import {menuData} from './useMenu';
1617
import {mergeProps, useSlotId} from '@react-aria/utils';
1718
import {PressEvent} from '@react-types/shared';
1819
import {TreeState} from '@react-stately/tree';
@@ -29,14 +30,29 @@ interface MenuItemAria {
2930
descriptionProps: HTMLAttributes<HTMLElement>,
3031

3132
/** Props for the keyboard shortcut text element inside the item, if any. */
32-
keyboardShortcutProps: HTMLAttributes<HTMLElement>
33+
keyboardShortcutProps: HTMLAttributes<HTMLElement>,
34+
35+
/** Whether the item is currently focused. */
36+
isFocused: boolean,
37+
/** Whether the item is currently selected. */
38+
isSelected: boolean,
39+
/** Whether the item is currently in a pressed state. */
40+
isPressed: boolean,
41+
/** Whether the item is disabled. */
42+
isDisabled: boolean
3343
}
3444

3545
interface AriaMenuItemProps {
36-
/** Whether the menu item is disabled. */
46+
/**
47+
* Whether the menu item is disabled.
48+
* @deprecated - pass disabledKeys to useTreeState instead.
49+
*/
3750
isDisabled?: boolean,
3851

39-
/** Whether the menu item is selected. */
52+
/**
53+
* Whether the menu item is selected.
54+
* @deprecated - pass selectedKeys to useTreeState instead.
55+
*/
4056
isSelected?: boolean,
4157

4258
/** A screen reader only label for the menu item. */
@@ -45,7 +61,10 @@ interface AriaMenuItemProps {
4561
/** The unique key for the menu item. */
4662
key?: Key,
4763

48-
/** Handler that is called when the menu should close after selecting an item. */
64+
/**
65+
* Handler that is called when the menu should close after selecting an item.
66+
* @deprecated - pass to the menu instead.
67+
*/
4968
onClose?: () => void,
5069

5170
/**
@@ -57,7 +76,10 @@ interface AriaMenuItemProps {
5776
/** Whether the menu item is contained in a virtual scrolling menu. */
5877
isVirtualized?: boolean,
5978

60-
/** Handler that is called when the user activates the item. */
79+
/**
80+
* Handler that is called when the user activates the item.
81+
* @deprecated - pass to the menu instead.
82+
*/
6183
onAction?: (key: Key) => void
6284
}
6385

@@ -69,15 +91,19 @@ interface AriaMenuItemProps {
6991
*/
7092
export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, ref: RefObject<HTMLElement>): MenuItemAria {
7193
let {
72-
isSelected,
73-
isDisabled,
7494
key,
75-
onClose,
7695
closeOnSelect,
77-
isVirtualized,
78-
onAction
96+
isVirtualized
7997
} = props;
8098

99+
let isDisabled = props.isDisabled ?? state.disabledKeys.has(key);
100+
let isSelected = props.isSelected ?? state.selectionManager.isSelected(key);
101+
let isFocused = state.selectionManager.focusedKey === key;
102+
103+
let data = menuData.get(state);
104+
let onClose = props.onClose || data.onClose;
105+
let onAction = props.onAction || data.onAction;
106+
81107
let role = 'menuitem';
82108
if (state.selectionManager.selectionMode === 'single') {
83109
role = 'menuitemradio';
@@ -156,7 +182,7 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
156182
allowsDifferentPressOrigin: true
157183
});
158184

159-
let {pressProps} = usePress({onPressStart, onPressUp, isDisabled});
185+
let {pressProps, isPressed} = usePress({onPressStart, onPressUp, isDisabled});
160186
let {hoverProps} = useHover({
161187
isDisabled,
162188
onHoverStart() {
@@ -180,6 +206,10 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
180206
},
181207
keyboardShortcutProps: {
182208
id: keyboardId
183-
}
209+
},
210+
isFocused,
211+
isSelected,
212+
isPressed,
213+
isDisabled
184214
};
185215
}

packages/@react-aria/menu/src/useMenuTrigger.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@
1111
*/
1212

1313
import {AriaButtonProps} from '@react-types/button';
14-
import {HTMLAttributes, RefObject} from 'react';
14+
import {AriaMenuOptions} from './useMenu';
1515
// @ts-ignore
1616
import intlMessages from '../intl/*.json';
1717
import {MenuTriggerState} from '@react-stately/menu';
1818
import {MenuTriggerType} from '@react-types/menu';
19-
import {mergeProps, useId} from '@react-aria/utils';
19+
import {RefObject} from 'react';
20+
import {useId} from '@react-aria/utils';
2021
import {useLongPress} from '@react-aria/interactions';
2122
import {useMessageFormatter} from '@react-aria/i18n';
2223
import {useOverlayTrigger} from '@react-aria/overlays';
@@ -30,20 +31,20 @@ interface MenuTriggerAriaProps {
3031
trigger?: MenuTriggerType
3132
}
3233

33-
interface MenuTriggerAria {
34+
interface MenuTriggerAria<T> {
3435
/** Props for the menu trigger element. */
3536
menuTriggerProps: AriaButtonProps,
3637

3738
/** Props for the menu. */
38-
menuProps: HTMLAttributes<HTMLElement>
39+
menuProps: AriaMenuOptions<T>
3940
}
4041

4142
/**
4243
* Provides the behavior and accessibility implementation for a menu trigger.
4344
* @param props - Props for the menu trigger.
4445
* @param state - State for the menu trigger.
4546
*/
46-
export function useMenuTrigger(props: MenuTriggerAriaProps, state: MenuTriggerState, ref: RefObject<HTMLElement>): MenuTriggerAria {
47+
export function useMenuTrigger<T>(props: MenuTriggerAriaProps, state: MenuTriggerState, ref: RefObject<HTMLElement>): MenuTriggerAria<T> {
4748
let {
4849
type = 'menu' as MenuTriggerAriaProps['type'],
4950
isDisabled,
@@ -117,17 +118,18 @@ export function useMenuTrigger(props: MenuTriggerAriaProps, state: MenuTriggerSt
117118
}
118119
};
119120

120-
triggerProps = mergeProps(triggerProps, trigger === 'press' ? pressProps : longPressProps);
121-
122121
return {
123122
menuTriggerProps: {
124123
...triggerProps,
124+
...(trigger === 'press' ? pressProps : longPressProps),
125125
id: menuTriggerId,
126126
onKeyDown
127127
},
128128
menuProps: {
129129
...overlayProps,
130-
'aria-labelledby': menuTriggerId
130+
'aria-labelledby': menuTriggerId,
131+
autoFocus: state.focusStrategy,
132+
onClose: state.close
131133
}
132134
};
133135
}

packages/@react-aria/overlays/src/useOverlayTrigger.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ export function useOverlayTrigger(props: OverlayTriggerProps, state: OverlayTrig
6161
triggerProps: {
6262
'aria-haspopup': ariaHasPopup,
6363
'aria-expanded': isOpen,
64-
'aria-controls': isOpen ? overlayId : null
64+
'aria-controls': isOpen ? overlayId : null,
65+
onPress: state.toggle
6566
},
6667
overlayProps: {
6768
id: overlayId

0 commit comments

Comments
 (0)