Skip to content

Commit 7e14ffa

Browse files
authored
fix: ignore typing leading zeros in DateField segments (#8447)
* ignore typing leading zeros in all datefield segements * update description
1 parent 7b35299 commit 7e14ffa

File tree

4 files changed

+64
-14
lines changed

4 files changed

+64
-14
lines changed

packages/@react-aria/datepicker/src/useDateSegment.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,8 @@ export function useDateSegment(segment: DateSegment, state: DateFieldState, ref:
256256
if (shouldSetValue) {
257257
focusManager.focusNext();
258258
}
259-
} else {
259+
} else if (shouldSetValue) {
260+
// Don't accept leading zeros except for fields that accept 0 as a entire value (aka 00 for minutes/seconds/etc)
260261
enteredKeys.current = newValue;
261262
}
262263
break;
@@ -325,7 +326,6 @@ export function useDateSegment(segment: DateSegment, state: DateFieldState, ref:
325326
if (ref.current) {
326327
ref.current.textContent = compositionRef.current;
327328
}
328-
329329
// Android sometimes fires key presses of letters as composition events. Need to handle am/pm keys here too.
330330
// Can also happen e.g. with Pinyin keyboard on iOS.
331331
if (data != null && (startsWith(am, data) || startsWith(pm, data))) {
@@ -387,9 +387,9 @@ export function useDateSegment(segment: DateSegment, state: DateFieldState, ref:
387387

388388
let segmentStyle: CSSProperties = {caretColor: 'transparent'};
389389
if (direction === 'rtl') {
390-
// While the bidirectional algorithm seems to work properly on inline elements with actual values, it returns different results for placeholder strings.
390+
// While the bidirectional algorithm seems to work properly on inline elements with actual values, it returns different results for placeholder strings.
391391
// To ensure placeholder render in correct format, we apply the CSS equivalent of LRE (left-to-right embedding). See https://www.unicode.org/reports/tr9/#Explicit_Directional_Embeddings.
392-
// However, we apply this to both placeholders and date segments with an actual value because the date segments will shift around when deleting otherwise.
392+
// However, we apply this to both placeholders and date segments with an actual value because the date segments will shift around when deleting otherwise.
393393
segmentStyle.unicodeBidi = 'embed';
394394
let format = options[segment.type];
395395
if (format === 'numeric' || format === '2-digit') {

packages/@react-spectrum/datepicker/test/DateField.test.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,11 @@ describe('DateField', function () {
235235
errorMessage="Date unavailable." />
236236
);
237237
await user.tab();
238-
await user.keyboard('01011980');
238+
await user.keyboard('1');
239+
await user.keyboard('[ArrowRight]');
240+
await user.keyboard('1');
241+
await user.keyboard('[ArrowRight]');
242+
await user.keyboard('1980');
239243
expect(tree.getByText('Date unavailable.')).toBeInTheDocument();
240244
});
241245

@@ -245,7 +249,7 @@ describe('DateField', function () {
245249
<DateField label="Date" showFormatHelpText />
246250
</Provider>
247251
);
248-
252+
249253
let segments = Array.from(getByRole('group').querySelectorAll('[data-testid]'));
250254
let segmentTypes = segments.map(s => s.getAttribute('data-testid'));
251255
expect(segmentTypes).toEqual(['year', 'month', 'day']);

packages/@react-spectrum/datepicker/test/DatePicker.test.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1426,7 +1426,8 @@ describe('DatePicker', function () {
14261426

14271427
it('should support typing into the month segment', function () {
14281428
testInput('month,', new CalendarDate(2019, 2, 3), '1', new CalendarDate(2019, 1, 3), false);
1429-
testInput('month,', new CalendarDate(2019, 2, 3), '01', new CalendarDate(2019, 1, 3), true);
1429+
testInput('month,', new CalendarDate(2019, 2, 3), '01', new CalendarDate(2019, 1, 3), false);
1430+
testInput('month,', new CalendarDate(2019, 2, 3), '012', new CalendarDate(2019, 12, 3), true);
14301431
testInput('month,', new CalendarDate(2019, 2, 3), '12', new CalendarDate(2019, 12, 3), true);
14311432
testInput('month,', new CalendarDate(2019, 2, 3), '4', new CalendarDate(2019, 4, 3), true);
14321433
testIgnored('month,', new CalendarDate(2019, 2, 3), '0');
@@ -1435,7 +1436,8 @@ describe('DatePicker', function () {
14351436

14361437
it('should support typing into the day segment', function () {
14371438
testInput('day,', new CalendarDate(2019, 2, 3), '1', new CalendarDate(2019, 2, 1), false);
1438-
testInput('day,', new CalendarDate(2019, 2, 3), '01', new CalendarDate(2019, 2, 1), true);
1439+
testInput('day,', new CalendarDate(2019, 2, 3), '01', new CalendarDate(2019, 2, 1), false);
1440+
testInput('day,', new CalendarDate(2019, 2, 3), '012', new CalendarDate(2019, 2, 12), true);
14391441
testInput('day,', new CalendarDate(2019, 2, 3), '12', new CalendarDate(2019, 2, 12), true);
14401442
testInput('day,', new CalendarDate(2019, 2, 3), '4', new CalendarDate(2019, 2, 4), true);
14411443
testIgnored('day,', new CalendarDate(2019, 2, 3), '0');
@@ -1444,22 +1446,28 @@ describe('DatePicker', function () {
14441446

14451447
it('should support typing into the year segment', function () {
14461448
testInput('year,', new CalendarDate(2019, 2, 3), '1993', new CalendarDate(1993, 2, 3), false);
1449+
testInput('year,', new CalendarDate(2019, 2, 3), '0199', new CalendarDate(199, 2, 3), false);
1450+
testInput('year,', new CalendarDate(2019, 2, 3), '01993', new CalendarDate(1993, 2, 3), false);
1451+
testInput('year,', new CalendarDateTime(2019, 2, 3, 8), '0199', new CalendarDateTime(199, 2, 3, 8), false);
14471452
testInput('year,', new CalendarDateTime(2019, 2, 3, 8), '1993', new CalendarDateTime(1993, 2, 3, 8), true);
1453+
testInput('year,', new CalendarDateTime(2019, 2, 3, 8), '01993', new CalendarDateTime(1993, 2, 3, 8), true);
14481454
testIgnored('year,', new CalendarDate(2019, 2, 3), '0');
14491455
});
14501456

14511457
it('should support typing into the hour segment in 12 hour time', function () {
14521458
// AM
14531459
testInput('hour,', new CalendarDateTime(2019, 2, 3, 8), '1', new CalendarDateTime(2019, 2, 3, 1), false);
1454-
testInput('hour,', new CalendarDateTime(2019, 2, 3, 8), '01', new CalendarDateTime(2019, 2, 3, 1), true);
1460+
testInput('hour,', new CalendarDateTime(2019, 2, 3, 8), '01', new CalendarDateTime(2019, 2, 3, 1), false);
1461+
testInput('hour,', new CalendarDateTime(2019, 2, 3, 8), '011', new CalendarDateTime(2019, 2, 3, 11), true);
14551462
testInput('hour,', new CalendarDateTime(2019, 2, 3, 8), '11', new CalendarDateTime(2019, 2, 3, 11), true);
14561463
testInput('hour,', new CalendarDateTime(2019, 2, 3, 8), '12', new CalendarDateTime(2019, 2, 3, 0), true);
14571464
testInput('hour,', new CalendarDateTime(2019, 2, 3, 8), '4', new CalendarDateTime(2019, 2, 3, 4), true);
14581465
testIgnored('hour,', new CalendarDateTime(2019, 2, 3, 8), '0');
14591466

14601467
// PM
14611468
testInput('hour,', new CalendarDateTime(2019, 2, 3, 20), '1', new CalendarDateTime(2019, 2, 3, 13), false);
1462-
testInput('hour,', new CalendarDateTime(2019, 2, 3, 20), '01', new CalendarDateTime(2019, 2, 3, 13), true);
1469+
testInput('hour,', new CalendarDateTime(2019, 2, 3, 20), '01', new CalendarDateTime(2019, 2, 3, 13), false);
1470+
testInput('hour,', new CalendarDateTime(2019, 2, 3, 20), '011', new CalendarDateTime(2019, 2, 3, 23), true);
14631471
testInput('hour,', new CalendarDateTime(2019, 2, 3, 20), '11', new CalendarDateTime(2019, 2, 3, 23), true);
14641472
testInput('hour,', new CalendarDateTime(2019, 2, 3, 20), '12', new CalendarDateTime(2019, 2, 3, 12), true);
14651473
testInput('hour,', new CalendarDateTime(2019, 2, 3, 20), '4', new CalendarDateTime(2019, 2, 3, 16), true);

packages/react-aria-components/test/DateField.test.js

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,12 @@ describe('DateField', () => {
204204
{({isDisabled}) => (
205205
<>
206206
<Label>Birth date</Label>
207-
<DateInput
207+
<DateInput
208208
data-disabled-state={isDisabled ? 'disabled' : null}>
209209
{segment => <DateSegment segment={segment} />}
210210
</DateInput>
211211
</>
212-
)}
212+
)}
213213
</DateField>
214214
);
215215
let group = getByRole('group');
@@ -317,7 +317,7 @@ describe('DateField', () => {
317317
</DateInput>
318318
</DateField>
319319
);
320-
320+
321321
let segments = getAllByRole('spinbutton');
322322
await user.click(segments[2]);
323323
expect(document.activeElement).toBe(segments[2]);
@@ -348,7 +348,7 @@ describe('DateField', () => {
348348
</DateInput>
349349
</DateField>
350350
);
351-
351+
352352
let segments = getAllByRole('spinbutton');
353353
await user.click(segments[2]);
354354
expect(segments[2]).toHaveFocus();
@@ -372,4 +372,42 @@ describe('DateField', () => {
372372
let segmentTypes = segments.map(s => s.getAttribute('data-type'));
373373
expect(segmentTypes).toEqual(['year', 'literal', 'month', 'day']);
374374
});
375+
376+
it('should not store leading zeros when typing into the segments', async () => {
377+
let {getAllByRole} = render(
378+
<DateField>
379+
<Label>Date</Label>
380+
<DateInput>
381+
{segment => <DateSegment segment={segment} />}
382+
</DateInput>
383+
</DateField>
384+
);
385+
386+
let segements = getAllByRole('spinbutton');
387+
let monthSegment = segements[0];
388+
await user.click(monthSegment);
389+
expect(monthSegment).toHaveFocus();
390+
await user.keyboard('11');
391+
expect(monthSegment).toHaveTextContent('11');
392+
await user.click(monthSegment);
393+
await user.keyboard('012');
394+
expect(monthSegment).toHaveTextContent('12');
395+
396+
let daysSegment = segements[1];
397+
await user.click(daysSegment);
398+
expect(daysSegment).toHaveFocus();
399+
await user.keyboard('11');
400+
expect(daysSegment).toHaveTextContent('11');
401+
await user.click(daysSegment);
402+
await user.keyboard('012');
403+
expect(daysSegment).toHaveTextContent('12');
404+
405+
let yearsSegment = segements[2];
406+
await user.click(yearsSegment);
407+
expect(yearsSegment).toHaveFocus();
408+
await user.keyboard('1111');
409+
expect(yearsSegment).toHaveTextContent('1111');
410+
await user.keyboard('002222');
411+
expect(yearsSegment).toHaveTextContent('2222');
412+
});
375413
});

0 commit comments

Comments
 (0)