Skip to content

Commit c73bebd

Browse files
YumiChensnowystingerdevongovett
authored
Feat: add shouldSelectOnPressUp prop to collection components (#7922)
* Add shouldSelectOnPressUp prop to GridList * Add shouldSelectOnPressUp to GridList story * Fix lint issue * Add GridList shouldSelectOnPressUp prop unit tests * Fix typos * add story for use case * Add to ListBox, Table, Tree, and TagGroup too --------- Co-authored-by: Robert Snow <[email protected]> Co-authored-by: Devon Govett <[email protected]>
1 parent 7292285 commit c73bebd

File tree

17 files changed

+345
-23
lines changed

17 files changed

+345
-23
lines changed

packages/@react-aria/grid/src/useGrid.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ export interface GridProps extends DOMProps, AriaLabelingProps {
6262
* trigger selection clearing contextually.
6363
* @default 'clearSelection'
6464
*/
65-
escapeKeyBehavior?: 'clearSelection' | 'none'
65+
escapeKeyBehavior?: 'clearSelection' | 'none',
66+
/** Whether selection should occur on press up instead of press down. */
67+
shouldSelectOnPressUp?: boolean
6668
}
6769

6870
export interface GridAria {
@@ -87,7 +89,8 @@ export function useGrid<T>(props: GridProps, state: GridState<T, GridCollection<
8789
getRowText,
8890
onRowAction,
8991
onCellAction,
90-
escapeKeyBehavior = 'clearSelection'
92+
escapeKeyBehavior = 'clearSelection',
93+
shouldSelectOnPressUp
9194
} = props;
9295
let {selectionManager: manager} = state;
9396

@@ -121,7 +124,7 @@ export function useGrid<T>(props: GridProps, state: GridState<T, GridCollection<
121124
});
122125

123126
let id = useId(props.id);
124-
gridMap.set(state, {keyboardDelegate: delegate, actions: {onRowAction, onCellAction}});
127+
gridMap.set(state, {keyboardDelegate: delegate, actions: {onRowAction, onCellAction}, shouldSelectOnPressUp});
125128

126129
let descriptionProps = useHighlightSelectionDescription({
127130
selectionManager: manager,

packages/@react-aria/grid/src/useGridRow.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ export function useGridRow<T, C extends GridCollection<T>, S extends GridState<T
5252
onAction
5353
} = props;
5454

55-
let {actions} = gridMap.get(state)!;
55+
let {actions, shouldSelectOnPressUp: gridShouldSelectOnPressUp} = gridMap.get(state)!;
5656
let onRowAction = actions.onRowAction ? () => actions.onRowAction?.(node.key) : onAction;
5757
let {itemProps, ...states} = useSelectableItem({
5858
selectionManager: state.selectionManager,
5959
key: node.key,
6060
ref,
6161
isVirtualized,
62-
shouldSelectOnPressUp,
62+
shouldSelectOnPressUp: gridShouldSelectOnPressUp || shouldSelectOnPressUp,
6363
onAction: onRowAction || node?.props?.onAction ? chain(node?.props?.onAction, onRowAction) : undefined,
6464
isDisabled: state.collection.size === 0
6565
});

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ interface GridMapShared {
1919
actions: {
2020
onRowAction?: (key: Key) => void,
2121
onCellAction?: (key: Key) => void
22-
}
22+
},
23+
shouldSelectOnPressUp?: boolean
2324
}
2425

2526
// Used to share:

packages/@react-aria/gridlist/src/useGridList.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ export interface GridListProps<T> extends CollectionBase<T>, MultipleSelection {
3939
*/
4040
onAction?: (key: Key) => void,
4141
/** Whether `disabledKeys` applies to all interactions, or only selection. */
42-
disabledBehavior?: DisabledBehavior
42+
disabledBehavior?: DisabledBehavior,
43+
/** Whether selection should occur on press up instead of press down. */
44+
shouldSelectOnPressUp?: boolean
4345
}
4446

4547
export interface AriaGridListProps<T> extends GridListProps<T>, DOMProps, AriaLabelingProps {
@@ -115,7 +117,8 @@ export function useGridList<T>(props: AriaGridListOptions<T>, state: ListState<T
115117
disallowTypeAhead,
116118
linkBehavior = 'action',
117119
keyboardNavigationBehavior = 'arrow',
118-
escapeKeyBehavior = 'clearSelection'
120+
escapeKeyBehavior = 'clearSelection',
121+
shouldSelectOnPressUp
119122
} = props;
120123

121124
if (!props['aria-label'] && !props['aria-labelledby']) {
@@ -139,7 +142,7 @@ export function useGridList<T>(props: AriaGridListOptions<T>, state: ListState<T
139142
});
140143

141144
let id = useId(props.id);
142-
listMap.set(state, {id, onAction, linkBehavior, keyboardNavigationBehavior});
145+
listMap.set(state, {id, onAction, linkBehavior, keyboardNavigationBehavior, shouldSelectOnPressUp});
143146

144147
let descriptionProps = useHighlightSelectionDescription({
145148
selectionManager: state.selectionManager,

packages/@react-aria/gridlist/src/useGridListItem.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,12 @@ export function useGridListItem<T>(props: AriaGridListItemOptions, state: ListSt
6363
// Copied from useGridCell + some modifications to make it not so grid specific
6464
let {
6565
node,
66-
isVirtualized,
67-
shouldSelectOnPressUp
66+
isVirtualized
6867
} = props;
6968

7069
// let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/gridlist');
7170
let {direction} = useLocale();
72-
let {onAction, linkBehavior, keyboardNavigationBehavior} = listMap.get(state)!;
71+
let {onAction, linkBehavior, keyboardNavigationBehavior, shouldSelectOnPressUp} = listMap.get(state)!;
7372
let descriptionId = useSlotId();
7473

7574
// We need to track the key of the item at the time it was last focused so that we force
@@ -125,7 +124,7 @@ export function useGridListItem<T>(props: AriaGridListItemOptions, state: ListSt
125124
key: node.key,
126125
ref,
127126
isVirtualized,
128-
shouldSelectOnPressUp,
127+
shouldSelectOnPressUp: props.shouldSelectOnPressUp || shouldSelectOnPressUp,
129128
onAction: onAction || node.props?.onAction ? chain(node.props?.onAction, onAction ? () => onAction(node.key) : undefined) : undefined,
130129
focus,
131130
linkBehavior

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ interface ListMapShared {
1717
id: string,
1818
onAction?: (key: Key) => void,
1919
linkBehavior?: 'action' | 'selection' | 'override',
20-
keyboardNavigationBehavior: 'arrow' | 'tab'
20+
keyboardNavigationBehavior: 'arrow' | 'tab',
21+
shouldSelectOnPressUp?: boolean
2122
}
2223

2324
// Used to share:

packages/@react-aria/listbox/src/useListBox.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,6 @@ export interface AriaListBoxOptions<T> extends Omit<AriaListBoxProps<T>, 'childr
4848
*/
4949
shouldUseVirtualFocus?: boolean,
5050

51-
/** Whether selection should occur on press up instead of press down. */
52-
shouldSelectOnPressUp?: boolean,
53-
5451
/** Whether options should be focused when the user hovers over them. */
5552
shouldFocusOnHover?: boolean,
5653

packages/@react-aria/tag/src/useTagGroup.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ export interface TagGroupAria {
3434
export interface AriaTagGroupProps<T> extends CollectionBase<T>, MultipleSelection, DOMProps, LabelableProps, AriaLabelingProps, Omit<HelpTextProps, 'errorMessage'> {
3535
/** How multiple selection should behave in the collection. */
3636
selectionBehavior?: SelectionBehavior,
37+
/** Whether selection should occur on press up instead of press down. */
38+
shouldSelectOnPressUp?: boolean,
3739
/** Handler that is called when a user deletes a tag. */
3840
onRemove?: (keys: Set<Key>) => void,
3941
/** An error message for the field. */

packages/@react-types/listbox/src/index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ export interface AriaListBoxProps<T> extends AriaListBoxPropsBase<T> {
3838
label?: ReactNode,
3939
/** How multiple selection should behave in the collection. */
4040
selectionBehavior?: SelectionBehavior,
41+
/** Whether selection should occur on press up instead of press down. */
42+
shouldSelectOnPressUp?: boolean,
4143
/**
4244
* Handler that is called when a user performs an action on an item. The exact user event depends on
4345
* the collection's `selectionBehavior` prop and the interaction modality.

packages/@react-types/table/src/index.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ export interface TableProps<T> extends MultipleSelection, Sortable {
3838
* trigger selection clearing contextually.
3939
* @default 'clearSelection'
4040
*/
41-
escapeKeyBehavior?: 'clearSelection' | 'none'
41+
escapeKeyBehavior?: 'clearSelection' | 'none',
42+
/** Whether selection should occur on press up instead of press down. */
43+
shouldSelectOnPressUp?: boolean
4244
}
4345

4446
/**

0 commit comments

Comments
 (0)