Skip to content

Commit

Permalink
Update the Select
Browse files Browse the repository at this point in the history
  • Loading branch information
Vlad Moroz committed Jun 5, 2024
1 parent c62d71c commit 41fd430
Showing 1 changed file with 36 additions and 10 deletions.
46 changes: 36 additions & 10 deletions packages/react/select/src/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ const SelectTrigger = React.forwardRef<SelectTriggerElement, SelectTriggerProps>
const isDisabled = context.disabled || disabled;
const composedRefs = useComposedRefs(forwardedRef, context.onTriggerChange);
const getItems = useCollection(__scopeSelect);
const pointerTypeRef = React.useRef<React.PointerEvent['pointerType']>('touch');

const [searchRef, handleTypeaheadSearch, resetTypeahead] = useTypeaheadSearch((search) => {
const enabledItems = getItems().filter((item) => !item.disabled);
Expand All @@ -230,12 +231,19 @@ const SelectTrigger = React.forwardRef<SelectTriggerElement, SelectTriggerProps>
}
});

const handleOpen = () => {
const handleOpen = (pointerEvent?: React.MouseEvent | React.PointerEvent) => {
if (!isDisabled) {
context.onOpenChange(true);
// reset typeahead when we open
resetTypeahead();
}

if (pointerEvent) {
context.triggerPointerDownPosRef.current = {
x: Math.round(pointerEvent.pageX),
y: Math.round(pointerEvent.pageY),
};
}
};

return (
Expand All @@ -262,8 +270,15 @@ const SelectTrigger = React.forwardRef<SelectTriggerElement, SelectTriggerProps>
// because we are preventing default in `onPointerDown` so effectively
// this only runs for a label "click"
event.currentTarget.focus();

// Open on click when using a touch or pen device
if (pointerTypeRef.current !== 'mouse') {
handleOpen(event);
}
})}
onPointerDown={composeEventHandlers(triggerProps.onPointerDown, (event) => {
pointerTypeRef.current = event.pointerType;

// prevent implicit pointer capture
// https://www.w3.org/TR/pointerevents3/#implicit-pointer-capture
const target = event.target as HTMLElement;
Expand All @@ -272,13 +287,10 @@ const SelectTrigger = React.forwardRef<SelectTriggerElement, SelectTriggerProps>
}

// only call handler if it's the left button (mousedown gets triggered by all mouse buttons)
// but not when the control key is pressed (avoiding MacOS right click)
if (event.button === 0 && event.ctrlKey === false) {
handleOpen();
context.triggerPointerDownPosRef.current = {
x: Math.round(event.pageX),
y: Math.round(event.pageY),
};
// but not when the control key is pressed (avoiding MacOS right click); also not for touch
// devices because that would open the menu on scroll. (pen devices behave as touch on iOS).
if (event.button === 0 && event.ctrlKey === false && event.pointerType === 'mouse') {
handleOpen(event);
// prevent trigger from stealing focus from the active item after opening.
event.preventDefault();
}
Expand Down Expand Up @@ -1197,6 +1209,7 @@ const SelectItem = React.forwardRef<SelectItemElement, SelectItemProps>(
contentContext.itemRefCallback?.(node, value, disabled)
);
const textId = useId();
const pointerTypeRef = React.useRef<React.PointerEvent['pointerType']>('touch');

const handleSelect = () => {
if (!disabled) {
Expand Down Expand Up @@ -1242,11 +1255,24 @@ const SelectItem = React.forwardRef<SelectItemElement, SelectItemProps>(
ref={composedRefs}
onFocus={composeEventHandlers(itemProps.onFocus, () => setIsFocused(true))}
onBlur={composeEventHandlers(itemProps.onBlur, () => setIsFocused(false))}
onPointerUp={composeEventHandlers(itemProps.onPointerUp, handleSelect)}
onClick={composeEventHandlers(itemProps.onClick, () => {
// Open on click when using a touch or pen device
if (pointerTypeRef.current !== 'mouse') handleSelect();
})}
onPointerUp={composeEventHandlers(itemProps.onPointerUp, () => {
// Using a mouse you should be able to do pointer down, move through
// the list, and release the pointer over the item to select it.
if (pointerTypeRef.current === 'mouse') handleSelect();
})}
onPointerDown={composeEventHandlers(itemProps.onPointerDown, (event) => {
pointerTypeRef.current = event.pointerType;
})}
onPointerMove={composeEventHandlers(itemProps.onPointerMove, (event) => {
// Remember pointer type when sliding over to this item from another one
pointerTypeRef.current = event.pointerType;
if (disabled) {
contentContext.onItemLeave?.();
} else {
} else if (pointerTypeRef.current === 'mouse') {
// even though safari doesn't support this option, it's acceptable
// as it only means it might scroll a few pixels when using the pointer.
event.currentTarget.focus({ preventScroll: true });
Expand Down

0 comments on commit 41fd430

Please sign in to comment.