Skip to content

Commit b4841b5

Browse files
committed
[select] Refactor touch modality check
1 parent 02d0ab9 commit b4841b5

File tree

6 files changed

+35
-18
lines changed

6 files changed

+35
-18
lines changed

packages/react/src/select/list/SelectList.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const SelectList = React.forwardRef(function SelectList(
2626
const { alignItemWithTriggerActive } = useSelectPositionerContext();
2727

2828
const hasScrollArrows = useStore(store, selectors.hasScrollArrows);
29-
const touchModality = useStore(store, selectors.touchModality);
29+
const openMethod = useStore(store, selectors.openMethod);
3030
const multiple = useStore(store, selectors.multiple);
3131
const id = useStore(store, selectors.id);
3232

@@ -40,7 +40,8 @@ export const SelectList = React.forwardRef(function SelectList(
4040
...(alignItemWithTriggerActive && {
4141
style: LIST_FUNCTIONAL_STYLES,
4242
}),
43-
className: hasScrollArrows && !touchModality ? styleDisableScrollbar.className : undefined,
43+
className:
44+
hasScrollArrows && openMethod !== 'touch' ? styleDisableScrollbar.className : undefined,
4445
};
4546

4647
const setListElement = useStableCallback((element: HTMLElement | null) => {

packages/react/src/select/positioner/SelectPositioner.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export const SelectPositioner = React.forwardRef(function SelectPositioner(
6868
const mounted = useStore(store, selectors.mounted);
6969
const modal = useStore(store, selectors.modal);
7070
const value = useStore(store, selectors.value);
71-
const touchModality = useStore(store, selectors.touchModality);
71+
const openMethod = useStore(store, selectors.openMethod);
7272
const positionerElement = useStore(store, selectors.positionerElement);
7373
const triggerElement = useStore(store, selectors.triggerElement);
7474
const isItemEqualToValue = useStore(store, selectors.isItemEqualToValue);
@@ -78,7 +78,8 @@ export const SelectPositioner = React.forwardRef(function SelectPositioner(
7878

7979
const [controlledAlignItemWithTrigger, setControlledAlignItemWithTrigger] =
8080
React.useState(alignItemWithTrigger);
81-
const alignItemWithTriggerActive = mounted && controlledAlignItemWithTrigger && !touchModality;
81+
const alignItemWithTriggerActive =
82+
mounted && controlledAlignItemWithTrigger && openMethod !== 'touch';
8283

8384
if (!mounted && controlledAlignItemWithTrigger !== alignItemWithTrigger) {
8485
setControlledAlignItemWithTrigger(alignItemWithTrigger);
@@ -97,7 +98,10 @@ export const SelectPositioner = React.forwardRef(function SelectPositioner(
9798

9899
React.useImperativeHandle(alignItemWithTriggerActiveRef, () => alignItemWithTriggerActive);
99100

100-
useScrollLock((alignItemWithTriggerActive || modal) && open && !touchModality, triggerElement);
101+
useScrollLock(
102+
(alignItemWithTriggerActive || modal) && open && openMethod !== 'touch',
103+
triggerElement,
104+
);
101105

102106
const positioning = useAnchorPositioning({
103107
anchor,

packages/react/src/select/root/SelectRoot.tsx

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ import { stringifyAsValue } from '../../utils/resolveValueLabel';
3535
import { EMPTY_ARRAY } from '../../utils/constants';
3636
import { defaultItemEquality, findItemIndex } from '../../utils/itemEquality';
3737
import { useValueChanged } from '../../utils/useValueChanged';
38+
import { useOpenInteractionType } from '../../utils/useOpenInteractionType';
39+
import { mergeProps } from '../../merge-props';
3840

3941
/**
4042
* Groups all parts of the select.
@@ -118,6 +120,11 @@ export function SelectRoot<Value, Multiple extends boolean | undefined = false>(
118120
const alignItemWithTriggerActiveRef = React.useRef(false);
119121

120122
const { mounted, setMounted, transitionStatus } = useTransitionStatus(open);
123+
const {
124+
openMethod,
125+
triggerProps: interactionTypeProps,
126+
reset: resetOpenInteractionType,
127+
} = useOpenInteractionType(open);
121128

122129
const store = useRefWithInit(
123130
() =>
@@ -134,7 +141,7 @@ export function SelectRoot<Value, Multiple extends boolean | undefined = false>(
134141
transitionStatus,
135142
items,
136143
forceMount: false,
137-
touchModality: false,
144+
openMethod: null,
138145
activeIndex: null,
139146
selectedIndex: null,
140147
popupProps: {},
@@ -257,6 +264,7 @@ export function SelectRoot<Value, Multiple extends boolean | undefined = false>(
257264
const handleUnmount = useStableCallback(() => {
258265
setMounted(false);
259266
store.set('activeIndex', null);
267+
resetOpenInteractionType();
260268
onOpenChangeComplete?.(false);
261269
});
262270

@@ -367,10 +375,15 @@ export function SelectRoot<Value, Multiple extends boolean | undefined = false>(
367375
typeahead,
368376
]);
369377

378+
const mergedTriggerProps = React.useMemo(
379+
() => mergeProps(getReferenceProps(), interactionTypeProps),
380+
[getReferenceProps, interactionTypeProps],
381+
);
382+
370383
useOnFirstRender(() => {
371384
store.update({
372385
popupProps: getFloatingProps(),
373-
triggerProps: getReferenceProps(),
386+
triggerProps: mergedTriggerProps,
374387
});
375388
});
376389

@@ -384,11 +397,12 @@ export function SelectRoot<Value, Multiple extends boolean | undefined = false>(
384397
mounted,
385398
transitionStatus,
386399
popupProps: getFloatingProps(),
387-
triggerProps: getReferenceProps(),
400+
triggerProps: mergedTriggerProps,
388401
items,
389402
itemToStringLabel,
390403
itemToStringValue,
391404
isItemEqualToValue,
405+
openMethod,
392406
});
393407
}, [
394408
store,
@@ -400,11 +414,12 @@ export function SelectRoot<Value, Multiple extends boolean | undefined = false>(
400414
mounted,
401415
transitionStatus,
402416
getFloatingProps,
403-
getReferenceProps,
417+
mergedTriggerProps,
404418
items,
405419
itemToStringLabel,
406420
itemToStringValue,
407421
isItemEqualToValue,
422+
openMethod,
408423
]);
409424

410425
const contextValue: SelectRootContext = React.useMemo(

packages/react/src/select/scroll-arrow/SelectScrollArrow.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ export const SelectScrollArrow = React.forwardRef(function SelectScrollArrow(
2929
direction === 'up' ? selectors.scrollUpArrowVisible : selectors.scrollDownArrowVisible;
3030

3131
const stateVisible = useStore(store, visibleSelector);
32-
const touchModality = useStore(store, selectors.touchModality);
32+
const openMethod = useStore(store, selectors.openMethod);
3333

3434
// Scroll arrows are disabled for touch modality as they are a hover-only element.
35-
const visible = stateVisible && !touchModality;
35+
const visible = stateVisible && openMethod !== 'touch';
3636

3737
const timeout = useTimeout();
3838

packages/react/src/select/store.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Store, createSelector } from '@base-ui/utils/store';
2+
import { type InteractionType } from '@base-ui/utils/useEnhancedClickHandler';
23
import type { TransitionStatus } from '../utils/useTransitionStatus';
34
import type { HTMLProps } from '../utils/types';
45
import { compareItemEquality } from '../utils/itemEquality';
@@ -23,7 +24,7 @@ export type State = {
2324
mounted: boolean;
2425
forceMount: boolean;
2526
transitionStatus: TransitionStatus;
26-
touchModality: boolean;
27+
openMethod: InteractionType | null;
2728

2829
activeIndex: number | null;
2930
selectedIndex: number | null;
@@ -57,7 +58,7 @@ export const selectors = {
5758
mounted: createSelector((state: State) => state.mounted),
5859
forceMount: createSelector((state: State) => state.forceMount),
5960
transitionStatus: createSelector((state: State) => state.transitionStatus),
60-
touchModality: createSelector((state: State) => state.touchModality),
61+
openMethod: createSelector((state: State) => state.openMethod),
6162

6263
activeIndex: createSelector((state: State) => state.activeIndex),
6364
selectedIndex: createSelector((state: State) => state.selectedIndex),

packages/react/src/select/trigger/SelectTrigger.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,8 @@ export const SelectTrigger = React.forwardRef(function SelectTrigger(
169169
validation.commit(value);
170170
}
171171
},
172-
onPointerMove({ pointerType }) {
172+
onPointerMove() {
173173
keyboardActiveRef.current = false;
174-
store.set('touchModality', pointerType === 'touch');
175-
},
176-
onPointerDown({ pointerType }) {
177-
store.set('touchModality', pointerType === 'touch');
178174
},
179175
onKeyDown() {
180176
keyboardActiveRef.current = true;

0 commit comments

Comments
 (0)