Skip to content

Commit

Permalink
Fix initial focus selection
Browse files Browse the repository at this point in the history
  • Loading branch information
atomiks committed Apr 10, 2024
1 parent 4e66442 commit bc7b09e
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 6 deletions.
30 changes: 30 additions & 0 deletions packages/mui-base/src/NumberField/NumberFieldInput.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { expect } from 'chai';
import { act, createRenderer, screen } from '@mui/internal-test-utils';
import { NumberField } from '@base_ui/react/NumberField';
import { fireEvent } from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';
import { describeConformance } from '../../test/describeConformance';
import { NumberFieldContext, NumberFieldContextValue } from './NumberFieldContext';

Expand Down Expand Up @@ -193,4 +194,33 @@ describe('<NumberField.Group />', () => {
fireEvent.blur(input);
expect(input).to.have.value('4');
});

it('should set selection to the logical end of the input on first focus', async () => {
if (/jsdom/.test(window.navigator.userAgent)) {
// JSDOM does not support selectionStart/selectionEnd
return;
}

render(
<NumberField id="test" defaultValue={100}>
<label htmlFor="test">label</label>
<NumberField.Input />
</NumberField>,
);
const input = screen.getByRole<HTMLInputElement>('textbox');
const label = screen.getByLabelText('label');

await userEvent.click(label);

expect(input.selectionStart).to.equal(3);
expect(input.selectionEnd).to.equal(3);

input.setSelectionRange(0, 3);

await userEvent.click(document.body);
await userEvent.click(label);

expect(input.selectionStart).to.equal(0);
expect(input.selectionEnd).to.equal(3);
});
});
26 changes: 20 additions & 6 deletions packages/mui-base/src/useNumberField/useNumberField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ export function useNumberField(params: NumberFieldProps): UseNumberFieldReturnVa
const movesAfterTouchRef = React.useRef(0);
const allowInputSyncRef = React.useRef(true);
const unsubscribeFromGlobalContextMenuRef = React.useRef<() => void>(() => {});
const isTouchingRef = React.useRef(false);
const isTouchingButtonRef = React.useRef(false);
const hasTouchedInputRef = React.useRef(false);

const [valueUnwrapped, setValueUnwrapped] = useControlled<number | null>({
controlled: externalValue,
Expand Down Expand Up @@ -361,10 +362,10 @@ export function useNumberField(params: NumberFieldProps): UseNumberFieldReturnVa
userSelect: 'none',
},
onTouchStart() {
isTouchingRef.current = true;
isTouchingButtonRef.current = true;
},
onTouchEnd() {
isTouchingRef.current = false;
isTouchingButtonRef.current = false;
},
onClick(event) {
const isDisabled = disabled || readOnly || (isIncrement ? isMax : isMin);
Expand Down Expand Up @@ -434,22 +435,22 @@ export function useNumberField(params: NumberFieldProps): UseNumberFieldReturnVa
event.defaultPrevented ||
isDisabled ||
!isPressedRef.current ||
isTouchingRef.current
isTouchingButtonRef.current
) {
return;
}

startAutoChange(isIncrement);
},
onMouseLeave() {
if (isTouchingRef.current) {
if (isTouchingButtonRef.current) {
return;
}

stopAutoChange();
},
onMouseUp() {
if (isTouchingRef.current) {
if (isTouchingButtonRef.current) {
return;
}

Expand Down Expand Up @@ -498,6 +499,19 @@ export function useNumberField(params: NumberFieldProps): UseNumberFieldReturnVa
spellCheck: 'false',
'aria-roledescription': 'Number field',
'aria-invalid': invalid || undefined,
onFocus(event) {
if (event.defaultPrevented || readOnly || disabled || hasTouchedInputRef.current) {
return;
}

hasTouchedInputRef.current = true;

// Browsers set selection at the start of the input field by default. We want to set it at
// the end for the first focus.
const target = event.currentTarget;
const length = target.value.length;
target.setSelectionRange(length, length);
},
onBlur(event) {
if (event.defaultPrevented || readOnly || disabled) {
return;
Expand Down

0 comments on commit bc7b09e

Please sign in to comment.