Skip to content

Commit 563e19d

Browse files
committed
[select] Refactor touch modality check
1 parent d77690a commit 563e19d

File tree

6 files changed

+34
-18
lines changed

6 files changed

+34
-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: 6 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,7 @@ 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 = mounted && controlledAlignItemWithTrigger && openMethod !== 'touch';
8282

8383
if (!mounted && controlledAlignItemWithTrigger !== alignItemWithTrigger) {
8484
setControlledAlignItemWithTrigger(alignItemWithTrigger);
@@ -97,7 +97,10 @@ export const SelectPositioner = React.forwardRef(function SelectPositioner(
9797

9898
React.useImperativeHandle(alignItemWithTriggerActiveRef, () => alignItemWithTriggerActive);
9999

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

102105
const positioning = useAnchorPositioning({
103106
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: {},
@@ -250,6 +257,7 @@ export function SelectRoot<Value, Multiple extends boolean | undefined = false>(
250257
const handleUnmount = useStableCallback(() => {
251258
setMounted(false);
252259
store.set('activeIndex', null);
260+
resetOpenInteractionType();
253261
onOpenChangeComplete?.(false);
254262
});
255263

@@ -360,10 +368,15 @@ export function SelectRoot<Value, Multiple extends boolean | undefined = false>(
360368
typeahead,
361369
]);
362370

371+
const mergedTriggerProps = React.useMemo(
372+
() => mergeProps(getReferenceProps(), interactionTypeProps),
373+
[getReferenceProps, interactionTypeProps],
374+
);
375+
363376
useOnFirstRender(() => {
364377
store.update({
365378
popupProps: getFloatingProps(),
366-
triggerProps: getReferenceProps(),
379+
triggerProps: mergedTriggerProps,
367380
});
368381
});
369382

@@ -377,11 +390,12 @@ export function SelectRoot<Value, Multiple extends boolean | undefined = false>(
377390
mounted,
378391
transitionStatus,
379392
popupProps: getFloatingProps(),
380-
triggerProps: getReferenceProps(),
393+
triggerProps: mergedTriggerProps,
381394
items,
382395
itemToStringLabel,
383396
itemToStringValue,
384397
isItemEqualToValue,
398+
openMethod,
385399
});
386400
}, [
387401
store,
@@ -393,11 +407,12 @@ export function SelectRoot<Value, Multiple extends boolean | undefined = false>(
393407
mounted,
394408
transitionStatus,
395409
getFloatingProps,
396-
getReferenceProps,
410+
mergedTriggerProps,
397411
items,
398412
itemToStringLabel,
399413
itemToStringValue,
400414
isItemEqualToValue,
415+
openMethod,
401416
]);
402417

403418
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-components/utils/store';
2+
import { type InteractionType } from '@base-ui-components/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)