From a9ff3dacd5d6aa4facbb352848e5f5f28adf1d7f Mon Sep 17 00:00:00 2001 From: interacsean Date: Thu, 8 Oct 2026 16:40:13 +1100 Subject: [PATCH] fix(date-field): show PM times correctly in 12-hour display fieldsFromValue copied the 0-23 hour straight into the segments and never set dayPeriod, while composeValue reads 12-hour segments as `hour % 12 + (pm ? 12 : 0)`. 18:00 showed as "18:00 AM" and any edit saved it as 06:xx. Split the hour into 1-12 + dayPeriod in 12-hour mode, and re-encode stored segments when the hour cycle flips on a mounted field (hourCycle prop or locale change). Refs tailor-inc/platform-planning#2039 Co-Authored-By: Claude Opus 5.5 --- .changeset/date-field-12-hour-pm.md | 5 + docs-manifest.json | 6 +- .../components/date-picker.docs.outline.md | 44 ++--- docs/components/date-picker.md | 44 ++--- .../components/date-field/date-field.test.tsx | 154 ++++++++++++++++++ .../src/components/date-field/date-field.tsx | 1 + .../date-field/date-range-picker.test.tsx | 26 ++- .../date-field/date-range-picker.tsx | 1 + .../date-field/use-date-field-state.ts | 48 ++++-- 9 files changed, 270 insertions(+), 59 deletions(-) create mode 100644 .changeset/date-field-12-hour-pm.md diff --git a/.changeset/date-field-12-hour-pm.md b/.changeset/date-field-12-hour-pm.md new file mode 100644 index 000000000..a47e84a2e --- /dev/null +++ b/.changeset/date-field-12-hour-pm.md @@ -0,0 +1,5 @@ +--- +"@tailor-platform/app-shell": patch +--- + +Fix 12-hour time display in `DateField`, `DatePicker` and `DateRangePicker`. With `granularity` set to `hour`, `minute` or `second` and a 12-hour cycle (`hourCycle={12}`, or a 12-hour locale such as `en-US`), afternoon values showed as e.g. "18:00 AM", and editing any segment saved them 12 hours early (06:xx). PM values now show as "06:00 PM", midnight and noon as 12 AM / 12 PM, and edits keep the correct hour. Changing `hourCycle` (or a locale change that flips the default cycle) on a mounted field now re-encodes the time segments instead of misreading them. Refs tailor-inc/platform-planning#2039. diff --git a/docs-manifest.json b/docs-manifest.json index fca243a66..4466b07c4 100644 --- a/docs-manifest.json +++ b/docs-manifest.json @@ -468,9 +468,9 @@ ], "hashes": { "typeSurface": "6b07d4169fa991df", - "outline": "85b4b50ff4dbc265", + "outline": "caab56e5766bdb72", "snapshot": null, - "outputMd": "33902be121ff69db", + "outputMd": "f39002ad79625dc4", "examples": null } }, @@ -1674,7 +1674,7 @@ "packages/core/skills/app-shell-patterns/references/components/command-palette.md": "7e5bc675a593791a", "packages/core/skills/app-shell-patterns/references/components/csv-importer.md": "53d3c795ca21b9dc", "packages/core/skills/app-shell-patterns/references/components/data-table.md": "dd2da884d7550daf", - "packages/core/skills/app-shell-patterns/references/components/date-picker.md": "33902be121ff69db", + "packages/core/skills/app-shell-patterns/references/components/date-picker.md": "f39002ad79625dc4", "packages/core/skills/app-shell-patterns/references/components/default-header.md": "375e55f4b12fa2be", "packages/core/skills/app-shell-patterns/references/components/default-sidebar.md": "3422388a0cc78571", "packages/core/skills/app-shell-patterns/references/components/description-card.md": "a347fd1f4ccd433e", diff --git a/docs-src/components/date-picker.docs.outline.md b/docs-src/components/date-picker.docs.outline.md index a1c219eda..81d3a8219 100644 --- a/docs-src/components/date-picker.docs.outline.md +++ b/docs-src/components/date-picker.docs.outline.md @@ -193,26 +193,28 @@ Locale and timezone come from AppShell automatically. Override per field with `l ### DateFieldProps -| Prop | Type | Description | -| -------------------------------- | ------------------------------------------------------------- | ---------------------------------------------------------- | -| `value` / `defaultValue` | `DateValue \| null` | Controlled / uncontrolled value | -| `onChange` | `(v: DateValue \| null) => void` | Fires when the value changes | -| `onBlur` | `() => void` | Fires when focus leaves the whole segmented control | -| `minValue` / `maxValue` | `DateValue` | Inclusive date range bounds | -| `isDateUnavailable` | `(date: DateValue) => boolean` | Marks specific dates unavailable | -| `isDisabled` | `boolean` | Disables interaction and form submission | -| `isReadOnly` | `boolean` | Allows focus/navigation without editing | -| `isRequired` | `boolean` | Marks the control required | -| `isInvalid` | `boolean` | Adds invalid styling / `aria-invalid` to the segmented UI | -| `placeholderValue` | `DateValue` | Seeds unset segments | -| `autoFocus` | `boolean` | Focus the first segment on mount | -| `locale` | `string` | BCP-47 locale override | -| `name` | `string` | Emits a form value through the proxy input | -| `id` | `string` | Proxy input id (use with external `