Skip to content

feat: DatePicker (@internationalized/date + Base UI) + DataTable date filters#332

Open
interacsean wants to merge 37 commits into
mainfrom
feat/date-picker-baseui-pp-1093
Open

feat: DatePicker (@internationalized/date + Base UI) + DataTable date filters#332
interacsean wants to merge 37 commits into
mainfrom
feat/date-picker-baseui-pp-1093

Conversation

@interacsean

@interacsean interacsean commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds three accessible date components — DateField, DatePicker, and Calendar — built on @internationalized/date (value layer) and Base UI (Popover), and wires the DatePicker into the DataTable date-filter editor.

The segmented input and the APG calendar grid are hand-rolled, so the only net-new dependency is @internationalized/date (~11 KB gz) — Base UI is already in the bundle. This is the lighter-foundation option from the design proposal §9; docs/proposals/date-picker-impl-comparison.md records the measured bundle comparison against the react-aria variant (~11 KB vs ~74 KB) for the same public API and a11y contract.

Video walkthrough

date-picker-walkthrough.mp4

What's included

Components — DateField / DatePicker / Calendar

  • Locale-driven segment order, first-day-of-week, and localized month/weekday names (via DateFormatter)
  • Segmented spinbutton input: per-segment ↑/↓, type-to-fill with smart auto-advance (leading-zero 02 advances; 29 builds 29), Backspace to clear
  • Full APG calendar keyboard support: arrows, Home/End, PageUp/PageDown, Shift+PageUp/Down, Enter/Space; roving tabindex; visible focus rings
  • Arrow keys traverse through disabled/unavailable days (focus moves, selection stays blocked) — no dead ends
  • Popover auto-focuses the grid, contains Tab (prev → next → grid), keeps focus on the nav button across month changes, and left-aligns to the field (shifting inward near the viewport edge)
  • Value correctness: internal segment state stays synced with a controlled value, only complete & valid values emit, and the field never constructs an invalid date — out-of-range day entries clamp to the month's real length on blur (leap-year aware)
  • timeZone support on AppShell with useResolvedLocale() / useTimeZone() hooks; @internationalized/date helpers and types re-exported from the package (no separate install)

DataTable date filters

  • date-type filter editor renders the DatePicker (single value and between ranges)
  • Friendlier date operators — exact date / after / before / between (after/before inclusive; gt/lt/ne dropped). Scoped to date only; number/datetime/time operators unchanged. en + ja labels.
  • Filter chips display a locale-formatted date (e.g. 15 Jun 2026) instead of raw ISO

Examples & docs

  • /date-picker interactive demo page
  • /data-table page: DataTable + filters driven by useCollectionVariables and a promise-based async data source (GraphQL-query stub)
  • Component docs (date-picker, data-table), the design proposal + implementation-comparison docs, and a changeset

Testing

  • 1180 unit tests pass, covering behaviour and the DOM a11y contract: spinbutton segments, role="grid" cells with data-* state, role="dialog" popover, roving-focus keyboard nav, and the date-filter commit/clear/between + operator-label paths
  • type-check, lint, and build all clean
  • Verified end-to-end in the browser: segment typing/auto-advance, calendar navigation (including through disabled dates), selection, popover alignment, and the async-filtered table

Scope notes

  • This PR covers date granularity. The field already models datetime/time value types; surfacing them in the filter UI is a fast-follow.
  • Fast-follow — mobile/touch typing. The segments are non-contentEditable spinbutton <div>s read via keydown, so on-screen keyboards don't type into them (on mobile the calendar popover is the touch path; desktop keyboard + calendar work fully). Addressable by mirroring react-aria — contentEditable segments + inputmode="numeric" + a native beforeinput handler. The full approach is written up in the proposal (date-picker.md → "Post-v1 fast-follows → Mobile / touch text entry") so the thinking isn't lost; it needs real-device QA before sign-off.
  • Other known gaps vs the react-aria variant (in the comparison doc): RTL arrow flipping, non-Gregorian calendar systems, localized chrome strings, and a full screen-reader audit.

🤖 Generated with Claude Code

interacsean and others added 28 commits June 19, 2026 13:49
Proposes the DatePicker / DateField / Calendar API for AppShell:
react-aria-components + @internationalized/date wrapped in a thin
app-shell layer, with passed-through vs masked props, locale and
timezone wiring, alternatives analysis, and measured bundle costs.

Tracked at tailor-inc/platform-planning#1093.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tting

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r dep + re-export)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…zed/date + Base UI)

Implements the proposal's §9 lighter-foundation option: DateField, DatePicker,
and Calendar built on @internationalized/date (value layer) + Base UI (Popover),
with the segmented spinbutton input and APG calendar grid hand-rolled. Same public
API and a11y/DOM contract as the react-aria variant; net-new dependency is just
@internationalized/date (~11 KB gz) since Base UI is already bundled.

- Locale-driven segment ordering, first-day-of-week, localized month/weekday names
- Full APG keyboard: arrows, Home/End, PageUp/PageDown, Shift+PageUp/Down, Enter/Space
- Roving tabindex; popover auto-focuses the grid and contains Tab (prev → next → grid)
- Month-change via nav buttons keeps focus on the button (one-shot focus signal)
- Visible focus ring on nav buttons + day cells
- AppShell timeZone prop + useResolvedLocale()/useTimeZone(); @internationalized/date re-exports
- 25 tests (behaviour + DOM a11y contract), docs, changeset, example page, impl comparison

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wire the app-shell DatePicker into the DataTable date-filter editor (single
and between ranges), replacing the native date input, and add an example page
demonstrating DataTable + DataTable.Filters driven by useCollectionVariables
and a promise-based async data source (a stub for the GraphQL query).

DatePicker robustness fixes surfaced by controlled filter usage:
- useDateFieldState keeps internal segment state synced from a controlled value
  (no thrash/loss of in-progress entry on every keystroke)
- typing only emits a complete & valid value; clearing emits null
- first digit after a segment is focused replaces rather than accumulates
- composeValue guards reject out-of-range segments (no invalid CalendarDate)
- per-segment display formatting (never constructs a date from partial input)
- DatePicker/DateField gain an `aria-label` prop for compact, label-less inputs

Example page: dummy invoice dataset, async queryInvoices(variables) applying
filter/order/cursor-pagination, date column with `type: "date"` filter.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Segment auto-advance now also fires when the typed-digit count fills the
  field's width, so typing "02" completes the day and advances — while "2"
  then "9" still builds 29 (a leading zero caps the digit count).
- Anchor the calendar popover to the field group (not the calendar icon) with
  align="start", so its left edge aligns to the field's left edge and Base UI
  collision handling shifts/flips it inward near a viewport edge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r / before / between)

Date columns now offer a slimmer, plainer operator set instead of the numeric
comparators:
- eq → "exact date"
- gte → "after"  (inclusive)
- lte → "before" (inclusive)
- between → "between"
- dropped gt, lt, and ne (the inclusive after/before cover the intent)

Scoped to `date` columns only — number/datetime/time keep the full numeric
operator set and labels. Labels added for en + ja; chip labels and both the
add-filter and edit-chip operator selects use them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Date filter chips now render the value as a locale-appropriate medium date
(e.g. "15 Jun 2026" / "Jun 15, 2026") via @internationalized/date's
DateFormatter with the resolved AppShell locale, instead of the raw ISO
"2026-06-15". Formatted in UTC so the calendar date never shifts across zones.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Align with the add-component skill:
- Replace the inline JS focus-ring handlers (el.style.outline / chromeFocusProps)
  with the same `ring` utility Button/inputs use — focus-visible:ring on the nav
  buttons + trigger, and :focus:ring (with relative/z-10 so it sits above
  adjacent cells) on calendar day cells. No more CSS-in-JS.
- Add structural snapshot tests for DateField, DatePicker (closed), and
  Calendar, per the skill's testing convention.

The earlier "no visible focus" was a wrong-attribute bug (data-[focus-visible],
a react-aria attr our cells never emit), not a failure of `ring`; the compiled
utilities are present in dist and identical to Button's.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- data-table.md: date filters use the DatePicker input and the friendlier
  operator set (exact date / after / before / between); note locale-formatted
  chips and that datetime/time are unchanged.
- date-picker.md: add the `aria-label` prop.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…onstraint

The vite-app type-check (run by CI, not by esbuild) failed: an `interface`
doesn't satisfy `Record<string, unknown>` — createColumnHelper / useDataTable's
row constraint — because interfaces lack the implicit index signature that
object-literal `type` aliases have. Switch `interface Invoice` to `type`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… on blur

Two related date-validity fixes:

- Day segment max is 31 until a valid month is entered (was tied to the anchor
  month, so "31" collapsed to "1" in a 30-day current month — and the snapshot
  was month-dependent). Snapshots updated to the now-stable max.
- On blur, an impossible day for the entered month/year is clamped to that
  month's real length (e.g. 30/02/2026 → 28; 31/04 → 30). Leap years resolve
  correctly since the year is complete by blur — 29/02/2024 is kept, 29/02/2026
  becomes 28. composeValue still never emits an invalid CalendarDate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Roving focus could land on a disabled or unavailable calendar day, but the
arrow-key handler was only attached to selectable cells — so once focus
reached such a day there was no way to navigate off it.

Per APG, arrow keys traverse *through* disabled dates; they just can't be
selected. Attach onKeyDown to every in-month cell (gated on `focusable`,
not `interactive`) while keeping click + Enter/Space selection gated on
`interactive`. selectDate already rejects out-of-range/unavailable dates.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… just blur

An impossible day (e.g. 29 Feb in a non-leap year) could persist when the
field was left in ways that didn't fire the group's blur clamp — including
editing a previously-valid leap date's year (29/02/2024 → 2026).

Clamp the day to the month's real length inside `commit`, the moment the date
is fully specified (a 4-digit year). Partial years are left untouched so the
day isn't shrunk mid-typing before the final year's leap-ness is known. The
on-blur `clampDate` remains the backstop for the year-still-empty case.

This makes the correction blur-independent: typing 29/02/2026 self-corrects
to 28 as soon as the year lands, and re-typing the year of a valid leap date
re-validates immediately.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an "In a form (submit validation)" section to the date-picker demo page:
a standard Form + submit Button, with the DatePicker's required/past-date
checks run on submit. The DatePicker isn't a Base UI Field control, so the
error is surfaced through its own errorMessage/isInvalid props and clears as
soon as a valid date is picked.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…over

Opening the popover moves focus into the grid (and roving nav moves it between
cells). Those programmatic `.focus()` calls let the browser scroll the focused
cell into view, jumping the page even when the field was already visible.

Pass `{ preventScroll: true }` to every programmatic focus in the calendar
(popover-open auto-focus, roving-focus effect, Tab containment).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The "Week starts Sunday (default)" label was misleading: omitting
`firstDayOfWeek` follows the active locale (Sunday for en-US, Monday for
en-GB), so on a Monday-first locale it never showed Sunday. Replace with
explicit "Forced Sunday" / "Forced Monday" examples plus a "Locale default"
one, and a note explaining the behaviour.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…apse

The group inherits `w-full min-w-0` from the shared input classes, so in a
narrow or flex container it could shrink to nothing. Floor it at 142px —
enough for "dd / mm / yyyy" + the trigger icon plus padding. Content can still
exceed it, so wider locales (e.g. ja-JP) grow past the floor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rcing to eq

Date columns narrowed their operator set to eq/gte/lte/between (dropping
gt/lt/ne). But a saved view or `useCollectionVariables` config can still hold a
date filter on a dropped operator — the chip rendered fine, yet opening the
editor preselected `eq` and omitted the original operator, so hitting Apply
silently rewrote the filter's semantics (e.g. "after X" → "on X").

`resolveTemporalOperator` now keeps an incoming operator that's outside the
standard set as a selectable, preselected option (for that one filter), so
opening + re-applying never changes it. Applies to both the temporal and
numeric editors; truly unknown operators still fall back to eq.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…mobile gap

The proposal still recorded react-aria-components as the v1 decision while this
PR ships the §9 Base UI + @internationalized/date variant — a self-contradiction.
Add a dated Revision note: the foundation swap is proposed for v1 and *pending
sign-off*, with the original 2026-06-17 decision kept verbatim for the record.

Also surface the mobile/touch-typing limitation (spinbutton segments, no hidden
numeric input) and the not-yet-SR-audited caveat in the component docs and the
changeset — previously only in the comparison proposal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ecision

Foundation swap approved 2026-06-26. Update the proposal's Status and Revision
note from "pending sign-off" to a finalised decision: v1 builds on the §9
@internationalized/date + Base UI variant, superseding the original 2026-06-17
react-aria-components decision (kept verbatim below for the record).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…not a hidden input)

The comparison doc claimed react-aria enables mobile typing via a hidden
`<input inputmode="numeric">`. That's wrong: react-aria's segments are
`contentEditable` spans with `inputmode="numeric"` — the soft keyboard surfaces
because the focused element is editable. Ours are non-editable spinbutton divs
driven by keydown (which soft keyboards don't emit), hence no touch typing.

Correct the comparison, component doc, and changeset, and note the gap is
addressable by matching react-aria's contentEditable + beforeinput approach.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…the proposal

Add a "Post-v1 fast-follows" section detailing the contentEditable + inputmode +
beforeinput approach for touch typing (mirroring react-aria), plus a pointer to
the comparison doc's full gap inventory — so the implementation thinking is
recorded rather than living only in a PR thread.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… for all three

DateField/DatePicker/CalendarProps are now honest per-component tables reflecting
what this variant actually wires up. Move props that are accepted (for react-aria
parity) but not yet acted on into a "Proposed / not yet implemented" table:
- granularity beyond "day" + hourCycle (DateTime is the tracked fast-follow)
- hideTimeZone and isRequired (accepted but unused)

Also: DateField ignores minValue/maxValue/isDateUnavailable (no calendar), so
those now live under DatePicker/Calendar; drop the stale "12/24-hour display"
localization claim (time granularity isn't supported yet).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d.tsx

Name the public API file after its base component (DateField) rather than the
generic -standalone suffix — and avoid colliding with the internal
date-picker.tsx presentation layer. Pure rename + import-path updates; no API
or behaviour change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… folders

Components with supporting files (external hooks) now live in a folder named
after the component, each with {component, presentation, hook(s), test, index}:

  components/date-field/   DateField + DatePicker, date-input-group (field
                           presentation + popover), use-date-field-state, tests
  components/calendar/     Calendar, calendar-view (grid presentation),
                           use-calendar-state, tests

Calendar is now its own component/file for clarity (was bundled in the public
API file). The old shared presentation (date-picker.tsx) is split into each
folder's presentation file; DatePicker composes the calendar via ../calendar.
Pure reorg — no public API or behaviour change; barrels keep import paths
(`@/components/date-field`) working. oxlint a11y overrides re-globbed to the
new folders; test snapshots regenerated under the new paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@interacsean interacsean marked this pull request as ready for review July 1, 2026 06:16
@interacsean interacsean requested a review from a team as a code owner July 1, 2026 06:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new date input family to packages/core (DateField/DatePicker/Calendar) built on @internationalized/date + Base UI Popover, and integrates it into DataTable’s date filter editor with friendlier operators and localized chip display formatting. This also expands the AppShell context to expose a formatting locale (full BCP-47) and a default timezone for date/time components, plus re-exports common @internationalized/date helpers/types from the package entrypoint.

Changes:

  • Add DateField, DatePicker, and Calendar components (segmented spinbutton field + APG calendar grid + popover dialog) with unit tests and snapshots.
  • Extend AppShell i18n/timezone plumbing (detectBrowserFullLocale, useResolvedLocale, useTimeZone, AppShell.timeZone) and re-export @internationalized/date helpers/types from packages/core/src/index.ts.
  • Update DataTable date filters to use DatePicker, slim date operators (eq/gte/lte/between), and locale-formatted chip values; update tests/docs/examples accordingly.

Reviewed changes

Copilot reviewed 30 out of 31 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pnpm-lock.yaml Adds lockfile entries for @internationalized/date@3.12.2.
packages/core/src/lib/i18n.ts Adds detectBrowserFullLocale() for full BCP-47 detection.
packages/core/src/index.ts Exports new date components, AppShell hooks, and re-exports @internationalized/date helpers/types.
packages/core/src/contexts/appshell-context.tsx Adds resolvedLocale + timeZone config and new hooks useResolvedLocale() / useTimeZone().
packages/core/src/components/date-field/use-date-field-state.ts Implements segmented date field state engine (typing, increment/decrement, composition).
packages/core/src/components/date-field/index.ts Adds public barrel export for DateField / DatePicker.
packages/core/src/components/date-field/date-input-group.tsx Implements segmented spinbutton group UI and Base UI popover wrapper/trigger.
packages/core/src/components/date-field/date-field.tsx Implements DateField and DatePicker public components and wiring to calendar/state.
packages/core/src/components/date-field/date-field.test.tsx Adds behavior + DOM a11y contract tests for DateField/DatePicker.
packages/core/src/components/data-table/toolbar.tsx Wires DatePicker into date-type filter editor, updates operators, and formats date chips.
packages/core/src/components/data-table/toolbar.test.tsx Updates filter editor tests to drive segmented DatePicker UI and validate date operator/chip behavior.
packages/core/src/components/data-table/i18n.ts Adds date-specific operator label translations (en/ja).
packages/core/src/components/calendar/use-calendar-state.ts Implements calendar grid state engine (weeks, focus, APG keyboard nav, selection).
packages/core/src/components/calendar/index.ts Adds public barrel export for Calendar.
packages/core/src/components/calendar/calendar.tsx Implements standalone Calendar component using AppShell locale/timezone defaults.
packages/core/src/components/calendar/calendar.test.tsx Adds behavior + DOM a11y contract tests for Calendar.
packages/core/src/components/calendar/calendar-view.tsx Implements APG calendar grid markup/rendering and popover focus containment behavior.
packages/core/src/components/appshell.tsx Adds timeZone prop and passes it into configuration build/memoization.
packages/core/package.json Adds dependency on @internationalized/date.
packages/core/.oxlintrc.jsonc Adds targeted a11y lint overrides for APG role-based date components.
packages/core/snapshots/src__components__date-field__date-field.test.tsx.snap Adds snapshots for DateField/DatePicker structure.
packages/core/snapshots/src__components__calendar__calendar.test.tsx.snap Adds snapshot for Calendar structure.
examples/vite-app/src/routes.generated.ts Adds generated routes for new example pages.
examples/vite-app/src/pages/date-picker/page.tsx Adds interactive demo page for DateField/DatePicker/Calendar.
examples/vite-app/src/pages/data-table/page.tsx Adds DataTable + filters example using date filters with async/promise data source.
examples/vite-app/src/App.tsx Adds sidebar links to the new example pages.
docs/proposals/date-picker.md Adds/records the design proposal and implementation decision context.
docs/proposals/date-picker-impl-comparison.md Documents measured bundle and behavior comparisons vs react-aria variant.
docs/components/date-picker.md Adds component documentation and props/limitations notes for date components.
docs/components/data-table.md Updates DataTable docs for date filters, operators, and chip formatting.
.changeset/date-picker.md Adds a minor changeset describing new date components and AppShell additions.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/core/src/contexts/appshell-context.tsx
Comment thread packages/core/src/components/date-field/date-field.tsx
interacsean and others added 4 commits July 2, 2026 10:38
… blur

When focus leaves the field, assume the current month/year for a partial date —
typing just "2" ⇒ the 2nd of this month/year; "2 Aug" ⇒ 2 Aug this year. The
day is the trigger: backfill only ever fills COARSER fields (month, year) from a
provided finer one, never guesses the day, so a lone year (or month) is left
untouched. Renames the on-blur `clampDate` handler to `commitOnBlur`, which now
backfills then clamps in a single commit.

Also updates the DataTable filter test helper: clearing a date must now remove
the day (the backfill trigger), so `clearDateIn` clears all segments — otherwise
the on-blur backfill re-completes the date.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Regenerated by the app-shell vite plugin — sorts /dashboard/products into place
(the merge left it out of order). No routes added or removed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DatePicker passed the raw `timeZone` prop to useDateFieldState while the
calendar used the resolved zone (prop → AppShell → local). With no `timeZone`
prop the field fell back to UTC for its "today"/anchor (and would emit
UTC-zoned values for time granularities) while the calendar used the AppShell
zone — so the two disagreed. Pass `resolvedTz` to the field too.

Addresses a GitHub Copilot review comment on #332.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… UI strings

`buildConfigurations` put `options.locale` verbatim into both `locale` (used to
key i18n label tables) and `resolvedLocale` (formatting). A consumer passing a
full BCP-47 tag like "ja-JP" made `labels["ja-JP"]` miss → English fallback.

Normalize `locale` to its language subtag (`toLanguageSubtag`, e.g. "ja-JP" →
"ja") while keeping the full tag in `resolvedLocale` for Intl/date formatting.
Back-compatible: a subtag ("en"/"ja") — the documented, existing usage — is
unchanged; only off-doc full tags are corrected.

Addresses a GitHub Copilot review comment on #332.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@IzumiSy

IzumiSy commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

/review

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

API Design Review completed successfully!

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generated by API Design Review for issue #332 · 192.4 AIC · ⌖ 9.53 AIC · ⊞ 5.8K
Comment /review to run again

Comment thread packages/core/src/components/date-field/date-field.tsx Outdated
Comment thread packages/core/src/components/date-field/date-field.tsx Outdated
Comment thread packages/core/src/components/data-table/toolbar.tsx Outdated
Comment thread docs/components/date-picker.md Outdated
Comment thread packages/core/src/components/date-field/date-field.tsx
Comment thread packages/core/src/components/date-field/date-input-group.tsx
Comment thread packages/core/src/components/calendar/calendar-view.tsx Outdated
Comment thread packages/core/src/components/date-field/date-field.tsx Outdated
Comment thread packages/core/src/components/calendar/use-calendar-state.ts
Comment thread packages/core/src/components/date-field/use-date-field-state.ts
interacsean and others added 3 commits July 2, 2026 13:22
… path

- calendar: build the cell-label DateFormatter once per locale/timezone instead
  of a fresh one per rendered cell (~42 per grid render, per frame on held arrows).
- date-field: hoist the DateFormatter + two NumberFormats + formatToParts into a
  memo keyed on locale/granularity/hour-cycle/timezone, so a keystroke (which only
  changes `fields`) reuses them instead of rebuilding all four.

Addresses two GitHub review comments (erickteowarang) on #332.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`DateFilterPicker`'s aria-label was the raw field id (e.g. "created_at"); thread
the column's visible label (`column.label ?? field`) through TemporalFilterEditor
so the accessible name matches what sighted users see, including the between
"from"/"to" pickers.

Addresses a GitHub review comment (github-actions bot, 3/3) on #332.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…trings

Addresses the PR review round on #332:

- **Controlled `value={null}`** (High): pass `value` through to
  useDateFieldState / useControlledState instead of `value ?? undefined`, so
  `null` (controlled-empty) stays distinct from `undefined` (uncontrolled) —
  a parent clearing the field with `value={null}` now actually clears it.
- **isRequired**: wire it to `aria-required` on the spinbutton segments (ARIA
  doesn't allow aria-required on the role="group" wrapper), for both DateField
  and DatePicker. Docs move it from "proposed" to implemented.
- **Localized chrome**: the built-in aria-labels (Previous/Next month, Open
  calendar, Choose date, calendar dialog) now resolve via folder-local
  `defineI18nLabels` tables (en/ja), matching data-table's i18n pattern.

Adds tests for controlled-null clearing (DateField + DatePicker) and
aria-required.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread packages/core/src/components/date-field/use-date-field-state.ts Outdated
Comment thread packages/core/src/components/date-field/date-input-group.tsx Outdated
Sweep for hardcoded English beyond the strings already flagged in review:

- Segment accessible names (month/day/year/hour/minute/second/AM-PM) — moved
  out of the engine's `SEGMENT_LABELS` constant into the i18n table, resolved at
  the presentation layer (drops the now-unused `Segment.label`).
- The empty-segment `aria-valuetext` ("Empty").
- The `DatePopover` "Choose date" aria-label fallback.

en values are unchanged (so tests/snapshots are stable); ja added. Tests assert
ja resolution for the segment names, popover trigger, empty placeholder, and
calendar month-nav labels.

Deliberately left: the visual segment placeholders (yyyy/mm/dd — format tokens,
a separate design choice) and the AM/PM display (time granularity, unsupported).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants