Skip to content

Commit 3a59bac

Browse files
authored
fix(DateField): fallback to infer hour cycle from locale (#1859)
1 parent 25df757 commit 3a59bac

File tree

5 files changed

+37
-50
lines changed

5 files changed

+37
-50
lines changed

.changeset/some-baboons-trade.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"bits-ui": patch
3+
---
4+
5+
fix(DateField): fallback to infer hour cycle from locale

packages/bits-ui/src/lib/bits/date-field/date-field.svelte.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import { type Announcer, getAnnouncer } from "$lib/internal/date-time/announcer.
4747
import {
4848
areAllSegmentsFilled,
4949
createContent,
50+
getDefaultHourCycle,
5051
getValueFromSegments,
5152
inferGranularity,
5253
initSegmentStates,
@@ -128,9 +129,10 @@ const SEGMENT_CONFIGS: Record<
128129
min: (root) => (root.hourCycle.current === 12 ? 1 : 0),
129130
max: (root) => {
130131
if (root.hourCycle.current === 24) return 23;
131-
if ("dayPeriod" in root.segmentValues && root.segmentValues.dayPeriod !== null)
132-
return 12;
133-
return 23;
132+
if (root.hourCycle.current === 12) return 12;
133+
// if hourCycle is undefined, infer from locale
134+
const inferredHourCycle = getDefaultHourCycle(root.locale.current);
135+
return inferredHourCycle === 12 ? 12 : 23;
134136
},
135137
cycle: 1,
136138
canBeZero: true,

packages/bits-ui/src/lib/internal/date-time/field/helpers.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,10 @@ function createContentObj(props: CreateContentObjProps) {
9696
* If we're operating in a 12 hour clock and the part is an hour, we handle
9797
* the conversion to 12 hour format with 2 digit hours and leading zeros here.
9898
*/
99-
if (part === "hour" && "dayPeriod" in segmentValues && props.hourCycle !== 24) {
99+
const is12HourMode =
100+
props.hourCycle === 12 ||
101+
(props.hourCycle === undefined && getDefaultHourCycle(locale) === 12);
102+
if (part === "hour" && is12HourMode) {
100103
/**
101104
* If the value is over 12, we convert to 12 hour format and add leading
102105
* zeroes if the value is less than 10.

packages/bits-ui/src/lib/internal/date-time/field/time-helpers.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { styleToString } from "svelte-toolbelt";
1717
import { useId } from "$lib/internal/use-id.js";
1818
import { getPlaceholder } from "../placeholders.js";
1919
import { isZonedDateTime } from "../utils.js";
20+
import { getDefaultHourCycle } from "./helpers.js";
2021

2122
export function initializeSegmentValues() {
2223
const initialParts = EDITABLE_TIME_SEGMENT_PARTS.map((part) => {
@@ -81,7 +82,10 @@ function createTimeContentObj(props: CreateTimeContentObjProps) {
8182
* If we're operating in a 12 hour clock and the part is an hour, we handle
8283
* the conversion to 12 hour format with 2 digit hours and leading zeros here.
8384
*/
84-
if (part === "hour" && "dayPeriod" in segmentValues && props.hourCycle !== 24) {
85+
const is12HourMode =
86+
props.hourCycle === 12 ||
87+
(props.hourCycle === undefined && getDefaultHourCycle(locale) === 12);
88+
if (part === "hour" && is12HourMode) {
8589
/**
8690
* If the value is over 12, we convert to 12 hour format and add leading
8791
* zeroes if the value is less than 10.

tests/src/tests/date-picker/date-picker.browser.test.ts

Lines changed: 18 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -579,47 +579,30 @@ it("should not close popover when closeOnDateSelect is false", async () => {
579579

580580
describe("date picker - 24-hour format with locales", () => {
581581
it("should allow typing hours 0-23 with non en-US locales that use 24-hour format", async () => {
582-
if (navigator.userAgent.includes("WebKit")) {
583-
expect(true);
584-
return;
585-
}
586-
587-
setup({
582+
const t = setup({
588583
granularity: "minute",
589-
locale: "de-DE", // german uses 24-hour format
584+
locale: "nl-NL", // dutch uses 24-hour format
590585
});
591586

592-
const { getHour } = getTimeSegments(page.getByTestId);
593-
const hour = getHour();
594-
595-
// should not have dayPeriod for 24-hour locales
596-
await expectNotExists(page.getByTestId("dayPeriod"));
597-
598-
// test typing single digit hours > 2 (issue: these get clamped to 12-hour format)
599-
await hour.click();
600-
await userEvent.keyboard("3");
601-
await expect.element(hour).toHaveTextContent("03");
602-
603-
// test typing hours 13-23 (issue: these should work but currently clamp)
604-
await hour.click();
605-
await userEvent.keyboard("15");
606-
await expect.element(hour).toHaveTextContent("15");
607-
608-
await hour.click();
609-
await userEvent.keyboard("23");
610-
await expect.element(hour).toHaveTextContent("23");
611-
612-
await hour.click();
613-
await userEvent.keyboard("18");
614-
await expect.element(hour).toHaveTextContent("18");
587+
const { getHour, getMinute } = getTimeSegments(page.getByTestId);
588+
589+
await t.day.click();
590+
await userEvent.keyboard("9");
591+
592+
await expect.element(t.day).toHaveTextContent("09");
593+
await expect.element(t.month).toHaveFocus();
594+
await userEvent.keyboard("9");
595+
await expect.element(t.month).toHaveTextContent("09");
596+
await expect.element(t.year).toHaveFocus();
597+
await userEvent.keyboard("1234");
598+
await expect.element(t.year).toHaveTextContent("1234");
599+
await expect.element(getHour()).toHaveFocus();
600+
await userEvent.keyboard("22");
601+
await expect.element(getHour()).toHaveTextContent("22");
602+
await expect.element(getMinute()).toHaveFocus();
615603
});
616604

617605
it("should allow arrow key navigation through full 0-23 range with 24-hour locales", async () => {
618-
if (navigator.userAgent.includes("WebKit")) {
619-
expect(true);
620-
return;
621-
}
622-
623606
const value = new CalendarDateTime(2023, 10, 12, 14, 30, 30, 0);
624607
setup({
625608
value,
@@ -653,11 +636,6 @@ describe("date picker - 24-hour format with locales", () => {
653636
});
654637

655638
it("should display and allow typing hours > 12 with sv-SE locale (24-hour format)", async () => {
656-
if (navigator.userAgent.includes("WebKit")) {
657-
expect(true);
658-
return;
659-
}
660-
661639
const value = new CalendarDateTime(2023, 10, 12, 18, 30, 30, 0);
662640
setup({
663641
value,
@@ -686,11 +664,6 @@ describe("date picker - 24-hour format with locales", () => {
686664
});
687665

688666
it("should handle ja-JP locale (24-hour format) correctly", async () => {
689-
if (navigator.userAgent.includes("WebKit")) {
690-
expect(true);
691-
return;
692-
}
693-
694667
const value = new CalendarDateTime(2023, 10, 12, 16, 30, 0, 0);
695668
setup({
696669
value,

0 commit comments

Comments
 (0)