diff --git a/.changeset/regional-dates-show-day-of-week.md b/.changeset/regional-dates-show-day-of-week.md new file mode 100644 index 00000000..ad61df66 --- /dev/null +++ b/.changeset/regional-dates-show-day-of-week.md @@ -0,0 +1,14 @@ +--- +"@tailor-platform/app-shell": minor +--- + +Add `dateFormat` and `showDayOfWeek` to `DateField`, `DatePicker`, and `DateRangePicker`, plus an app-wide default on `AppShell` via `dateInputDateFormat`. + +- `dateFormat="regional"` lays the segments out in the locale's written business form wherever that form keeps the month numeric — `2025年12月19日` for ja / zh, `2025년 12월 19일` for ko. Locales whose written form spells the month as a word (en, de, fr, …) stay numeric, so a single app-wide setting is safe for multi-locale apps. The default remains `"numeric"`, so existing screens are unchanged. The default is planned to become `"regional"` in a future major release; set `"numeric"` explicitly to keep the numeric layout across that upgrade. +- `showDayOfWeek` appends the locale's short day of the week (`2025年12月19日(金)`, `Fri, 12/19/2025`). It is read-only, derived from the entered date, holds the previous day of the week while a date segment is mid-entry (so typing `25` never flashes the 2nd's), and is announced to screen readers with each date segment's value. + +```tsx + + + +``` diff --git a/docs-manifest.json b/docs-manifest.json index ff7b8e2a..800aea2c 100644 --- a/docs-manifest.json +++ b/docs-manifest.json @@ -97,10 +97,10 @@ "claims": [], "symbols": ["AppShell", "AppShellProps"], "hashes": { - "typeSurface": "51313066e142afc2", - "outline": "05d3544ec249692f", + "typeSurface": "eb9f3d56e647a63e", + "outline": "bc57fd4f036b1ab3", "snapshot": null, - "outputMd": "081e4c7bb61db191", + "outputMd": "aa2cbe86153db2a0", "examples": null } }, @@ -470,10 +470,10 @@ "DateRangePickerProps" ], "hashes": { - "typeSurface": "6b07d4169fa991df", - "outline": "caab56e5766bdb72", + "typeSurface": "97f771503044256f", + "outline": "d1009e13680a1f70", "snapshot": null, - "outputMd": "f39002ad79625dc4", + "outputMd": "4ef526c25046a94e", "examples": null } }, @@ -1664,7 +1664,7 @@ "packages/core/skills/app-shell-patterns/references/components/activity-card.md": "4f386e49380fb0b0", "packages/core/skills/app-shell-patterns/references/components/ai-chat.md": "824d1aa36bb7f194", "packages/core/skills/app-shell-patterns/references/components/alert.md": "db2c4388ca783a75", - "packages/core/skills/app-shell-patterns/references/components/app-shell.md": "081e4c7bb61db191", + "packages/core/skills/app-shell-patterns/references/components/app-shell.md": "aa2cbe86153db2a0", "packages/core/skills/app-shell-patterns/references/components/appearance-switcher.md": "b55f1d538651d467", "packages/core/skills/app-shell-patterns/references/components/attachment.md": "35bebce540d6ac28", "packages/core/skills/app-shell-patterns/references/components/autocomplete.md": "bd6ae01bf39d1ad6", @@ -1677,7 +1677,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": "97ae28f7a98c5d97", - "packages/core/skills/app-shell-patterns/references/components/date-picker.md": "f39002ad79625dc4", + "packages/core/skills/app-shell-patterns/references/components/date-picker.md": "4ef526c25046a94e", "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/app-shell.docs.outline.md b/docs-src/components/app-shell.docs.outline.md index 01cf2206..ea426383 100644 --- a/docs-src/components/app-shell.docs.outline.md +++ b/docs-src/components/app-shell.docs.outline.md @@ -226,6 +226,20 @@ Supported locales: `en`, `ja` ``` +### dateInputDateFormat + +- **Type:** `"numeric" | "regional"` (optional) +- **Default:** `"numeric"` (planned to become `"regional"` — see below) +- **Description:** Default segment layout for `DateField`, `DatePicker`, and `DateRangePicker`. `"numeric"` uses the locale's numeric form (`2025/12/19`). `"regional"` uses the locale's written business form where it keeps the month numeric (`2025年12月19日` for ja / zh, `2025년 12월 19일` for ko) and stays numeric for every other locale. Each component's own `dateFormat` prop overrides it. + +```tsx + + {/* ... */} + +``` + +> **Planned default change:** the default is planned to become `"regional"` in a future major release. Apps that want to keep the numeric layout should set `"numeric"` explicitly now; apps already on `"regional"` won't be affected. + Access the configured timezone in components using [`useTimeZone`](../api/use-time-zone.md). ### errorBoundary diff --git a/docs-src/components/date-picker.docs.outline.md b/docs-src/components/date-picker.docs.outline.md index 81d3a821..bd5dc38d 100644 --- a/docs-src/components/date-picker.docs.outline.md +++ b/docs-src/components/date-picker.docs.outline.md @@ -183,6 +183,28 @@ Locale and timezone come from AppShell automatically. Override per field with `l ``` +### Date format + +By default the segments follow the locale's **numeric** form (`2025/12/19` for ja-JP, `12/19/2025` for en-US). `dateFormat="regional"` switches to the locale's written business form wherever that form keeps the month numeric — `2025年12月19日` for ja / zh, `2025년 12월 19일` for ko. Locales whose written form spells the month as a word (en, de, fr, …) stay numeric, so one setting is safe for a multi-locale app. + +Set it once for the whole app with `AppShell`'s `dateInputDateFormat`, or per field with `dateFormat` (the prop wins): + +```tsx + + + +``` + +> **Planned default change:** the default is planned to become `"regional"` in a future major release. Apps that want to keep the numeric layout should set `"numeric"` explicitly now; apps already on `"regional"` won't be affected. + +### Day of the week + +`showDayOfWeek` adds the locale's short day of the week where the locale places it — `2025年12月19日(金)` for ja-JP, `Fri, 12/19/2025` for en-US. It is read-only and derived from the entered date: it shows a placeholder until the date is complete, and while a date segment is mid-entry it keeps the previous day of the week (muted), so typing `25` into the day never flashes the 2nd's. Screen readers hear the full day name with each date segment's value. + +```tsx + +``` + ## Keyboard - **Segments:** `↑`/`↓` increment/decrement, digits type-to-fill (auto-advance), `←`/`→` move between segments, `Backspace` clears, `/` commits the current segment and advances. @@ -193,28 +215,30 @@ 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 | -| `granularity` | `"day" \| "hour" \| "minute" \| "second"` | Smallest editable unit; time granularities add time segments | -| `hourCycle` | `12 \| 24` | Force 12- or 24-hour time; defaults to the locale | -| `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 ` ``` +### dateInputDateFormat + +- **Type:** `"numeric" | "regional"` (optional) +- **Default:** `"numeric"` (planned to become `"regional"` — see below) +- **Description:** Default segment layout for `DateField`, `DatePicker`, and `DateRangePicker`. `"numeric"` uses the locale's numeric form (`2025/12/19`). `"regional"` uses the locale's written business form where it keeps the month numeric (`2025年12月19日` for ja / zh, `2025년 12월 19일` for ko) and stays numeric for every other locale. Each component's own `dateFormat` prop overrides it. + +```tsx + + {/* ... */} + +``` + +> **Planned default change:** the default is planned to become `"regional"` in a future major release. Apps that want to keep the numeric layout should set `"numeric"` explicitly now; apps already on `"regional"` won't be affected. + Access the configured timezone in components using [`useTimeZone`](../api/use-time-zone.md). ### errorBoundary diff --git a/docs/components/date-picker.md b/docs/components/date-picker.md index 9d3bcab5..11093a27 100644 --- a/docs/components/date-picker.md +++ b/docs/components/date-picker.md @@ -181,6 +181,28 @@ Locale and timezone come from AppShell automatically. Override per field with `l ``` +### Date format + +By default the segments follow the locale's **numeric** form (`2025/12/19` for ja-JP, `12/19/2025` for en-US). `dateFormat="regional"` switches to the locale's written business form wherever that form keeps the month numeric — `2025年12月19日` for ja / zh, `2025년 12월 19일` for ko. Locales whose written form spells the month as a word (en, de, fr, …) stay numeric, so one setting is safe for a multi-locale app. + +Set it once for the whole app with `AppShell`'s `dateInputDateFormat`, or per field with `dateFormat` (the prop wins): + +```tsx + + + +``` + +> **Planned default change:** the default is planned to become `"regional"` in a future major release. Apps that want to keep the numeric layout should set `"numeric"` explicitly now; apps already on `"regional"` won't be affected. + +### Day of the week + +`showDayOfWeek` adds the locale's short day of the week where the locale places it — `2025年12月19日(金)` for ja-JP, `Fri, 12/19/2025` for en-US. It is read-only and derived from the entered date: it shows a placeholder until the date is complete, and while a date segment is mid-entry it keeps the previous day of the week (muted), so typing `25` into the day never flashes the 2nd's. Screen readers hear the full day name with each date segment's value. + +```tsx + +``` + ## Keyboard - **Segments:** `↑`/`↓` increment/decrement, digits type-to-fill (auto-advance), `←`/`→` move between segments, `Backspace` clears, `/` commits the current segment and advances. @@ -191,28 +213,30 @@ 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 | -| `granularity` | `"day" \| "hour" \| "minute" \| "second"` | Smallest editable unit; time granularities add time segments | -| `hourCycle` | `12 \| 24` | Force 12- or 24-hour time; defaults to the locale | -| `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 `