@lekoala/date-picker 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,6 +14,10 @@ export declare class DatePickerElement extends HTMLElement {
14
14
  /** @type {DateRangeController | null} */
15
15
  _range: DateRangeController | null;
16
16
  _orderTags: Set<any>;
17
+ /** Native time companions, [start, end]. @type {[HTMLInputElement | null, HTMLInputElement | null]} */
18
+ _timeFields: [HTMLInputElement | null, HTMLInputElement | null];
19
+ /** Time inputs currently holding our order error. @type {Set<HTMLInputElement>} */
20
+ _timeOrderOwned: Set<HTMLInputElement>;
17
21
  /** @type {"" | "start" | "end"} */
18
22
  _lastFocusEndpoint: "" | "start" | "end";
19
23
  _rangeCommitId: number;
@@ -64,6 +68,12 @@ export declare class DatePickerElement extends HTMLElement {
64
68
  _rangeMode(): boolean;
65
69
  connectedCallback(): void;
66
70
  _connectSingle(): void;
71
+ /**
72
+ * Find optional native time companions. They stay fully native (no hidden
73
+ * input, no field controller); the picker only coordinates from/to order.
74
+ * A bad composition never breaks the date picker: warn and leave times alone.
75
+ */
76
+ _discoverTimeFields(): void;
67
77
  _connectRange(): void;
68
78
  disconnectedCallback(): void;
69
79
  /** @param {DateFieldController | null} field */
@@ -89,6 +99,9 @@ export declare class DatePickerElement extends HTMLElement {
89
99
  /** @public */
90
100
  get locale(): string;
91
101
  set locale(value: string);
102
+ /** @public Visible month-name style forwarded to the popup calendar (`long` | `short`); anything else falls back to `long`. */
103
+ get monthFormat(): "long" | "short";
104
+ set monthFormat(value: string);
92
105
  /** @public */
93
106
  get min(): string;
94
107
  set min(value: string);
@@ -232,6 +245,17 @@ export declare class DatePickerElement extends HTMLElement {
232
245
  * @param {"start" | "end"} which
233
246
  */
234
247
  _revalidateRange(which: "start" | "end"): void;
248
+ /**
249
+ * Single-mode from/to order on the shared date: `start <= end`.
250
+ * The order error is attributed to the bound that was just modified; the
251
+ * other bound only loses a stale order error, never its native validity.
252
+ * Missing, empty or disabled times fall back to no order constraint: times
253
+ * are never implicitly required. Equality stays valid (duration rules are
254
+ * application-owned).
255
+ * @param {"start" | "end"} which
256
+ */
257
+ _revalidateTimeOrder(which: "start" | "end"): void;
258
+ _clearTimeOrderValidity(): void;
235
259
  _restoreDefault(): void;
236
260
  _restoreRangeDefault(): void;
237
261
  /** @param {"start" | "end"} which */
@@ -1 +1 @@
1
- {"version":3,"file":"date-picker.d.ts","sourceRoot":"","sources":["../../src/date-picker.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"date-picker.d.ts","sourceRoot":"","sources":["../../src/date-picker.js"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@ export * as dates from "./date.js";
3
3
  export { DateCalendarElement } from "./date-calendar.js";
4
4
  export { DatePickerElement } from "./date-picker.js";
5
5
  export { linkDateRange, normalizeRange, rangePosition } from "./date-range.js";
6
- export { createDateAdapter, formatLongDate, formatMonthYear, monthNames, resolveLocale, weekdayNames, } from "./intl.js";
6
+ export { createDateAdapter, formatLongDate, formatMonthYear, monthNames, monthYearOrder, resolveLocale, weekdayNames, } from "./intl.js";
7
7
  export { DEFAULT_MESSAGES, getDefaultMessages, setDefaultMessages } from "./messages.js";
8
8
  export { createFetchSource, normalizeDateStates } from "./source.js";
9
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,KAAK,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,UAAU,EACV,aAAa,EACb,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,KAAK,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,UAAU,EACV,cAAc,EACd,aAAa,EACb,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
@@ -4,6 +4,15 @@ export declare function resolveLocale(locale?: string): string;
4
4
  export declare function formatLongDate(value: string, locale?: string): string;
5
5
  /** @param {string} value @param {string} [locale] */
6
6
  export declare function formatMonthYear(value: string, locale?: string): string;
7
+ /**
8
+ * Locale order of the visible month/year controls, derived from `Intl` so no
9
+ * `showMonthAfterYear`-style option is needed. Year-like parts cover the
10
+ * `relatedYear` / `yearName` variants some calendars expose; anything
11
+ * unrecognized falls back to month-then-year. This is independent of `dir`:
12
+ * the locale decides the linguistic order, direction only mirrors the layout.
13
+ * @param {string} [locale] @returns {["month", "year"] | ["year", "month"]}
14
+ */
15
+ export declare function monthYearOrder(locale?: string): ["month", "year"] | ["year", "month"];
7
16
  /** @param {string} [locale] @param {"long"|"short"} [style] */
8
17
  export declare function monthNames(locale?: string, style?: "long" | "short"): string[];
9
18
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"intl.d.ts","sourceRoot":"","sources":["../../src/intl.js"],"names":[],"mappings":"AAIA,+BAA+B;AAC/B,wBAAgB,aAAa,CAAC,MAAM,AADhC,CAAwB,EAAhB,MAC6B,UAKxC;AAmBD,qDAAqD;AACrD,wBAAgB,cAAc,CAAC,KAAK,EADxB,MACwB,EAAE,MAAM,AADlB,CAAwB,EAAhB,MACe,UAUhD;AAED,qDAAqD;AACrD,wBAAgB,eAAe,CAAC,KAAK,EADzB,MACyB,EAAE,MAAM,AADnB,CAAwB,EAAhB,MACgB,UAQjD;AAED,+DAA+D;AAC/D,wBAAgB,UAAU,CAAC,MAAM,AAD7B,CAAyB,EAAjB,MAC0B,EAAE,KAAK,AADhB,CAA+B,EAAvB,MAAM,GAAC,OACU,YAMrD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,AAJhC,CACA,EADQ,MAI6B,EAAE,QAAQ,AAH/C,CACA,EADQ,MAG2C,EAAE,KAAK,AAF1D,CAAwC,EAAhC,MAAM,GAAC,OAAO,GAAC,QAE6C,YAetE;AAOD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,AAFrC,CAAwB,EAAhB,MAEkC;;;IAiCzC,4BAA4B;kBAAhB,MAAM;IAKlB,6CAA6C;gBAAjC,MAAM,GAAiB,MAAM;EAmB5C;AAED,4BAA4B;AAC5B,wBAAgB,SAAS,CAAC,KAAK,EADnB,MACmB;;;;SAE9B"}
1
+ {"version":3,"file":"intl.d.ts","sourceRoot":"","sources":["../../src/intl.js"],"names":[],"mappings":"AAIA,+BAA+B;AAC/B,wBAAgB,aAAa,CAAC,MAAM,AADhC,CAAwB,EAAhB,MAC6B,UAKxC;AAmBD,qDAAqD;AACrD,wBAAgB,cAAc,CAAC,KAAK,EADxB,MACwB,EAAE,MAAM,AADlB,CAAwB,EAAhB,MACe,UAUhD;AAED,qDAAqD;AACrD,wBAAgB,eAAe,CAAC,KAAK,EADzB,MACyB,EAAE,MAAM,AADnB,CAAwB,EAAhB,MACgB,UAQjD;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,AAFlC,CAAyB,EAAjB,MAE+B,GAFJ,CAAC,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CA2B1E;AAED,+DAA+D;AAC/D,wBAAgB,UAAU,CAAC,MAAM,AAD7B,CAAyB,EAAjB,MAC0B,EAAE,KAAK,AADhB,CAA+B,EAAvB,MAAM,GAAC,OACU,YAMrD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,AAJhC,CACA,EADQ,MAI6B,EAAE,QAAQ,AAH/C,CACA,EADQ,MAG2C,EAAE,KAAK,AAF1D,CAAwC,EAAhC,MAAM,GAAC,OAAO,GAAC,QAE6C,YAetE;AAOD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,AAFrC,CAAwB,EAAhB,MAEkC;;;IAiCzC,4BAA4B;kBAAhB,MAAM;IAKlB,6CAA6C;gBAAjC,MAAM,GAAiB,MAAM;EAmB5C;AAED,4BAA4B;AAC5B,wBAAgB,SAAS,CAAC,KAAK,EADnB,MACmB;;;;SAE9B"}
@@ -0,0 +1,8 @@
1
+ /** Civil time check for canonical `input[type=time]` values. @param {string} value */
2
+ export declare function isTime(value: string): boolean;
3
+ /**
4
+ * Compare two canonical time values. `09:30` equals `09:30:00`.
5
+ * @param {string} a @param {string} b
6
+ */
7
+ export declare function compareTimes(a: string, b: string): -1 | 0 | 1;
8
+ //# sourceMappingURL=time.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../../src/time.js"],"names":[],"mappings":"AAkBA,sFAAsF;AACtF,wBAAgB,MAAM,CAAC,KAAK,EAD0C,MAC1C,WAE3B;AAOD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAFnB,MAEmB,EAAE,CAAC,EAFJ,MAEI,cAMhC"}
package/docs/API.md CHANGED
@@ -14,6 +14,7 @@ The public surface — flat event names, `selection` values, `--dp-*` styling to
14
14
  | `max` | `YYYY-MM-DD` | `""` | Latest activatable date. |
15
15
  | `first-day` | `0..6` (`7` alias) | `1` | First weekday; Sunday=0, Monday=1. `7` is accepted as an ISO-style alias of Sunday (`@lekoala/calendar` uses 1..7) and never shifts the grid. Other values fall back to Monday. |
16
16
  | `locale` | BCP 47 string | document/navigator | `Intl` locale. |
17
+ | `month-format` | `long \| short` | `long` | Visible month-name style in the month select; anything else falls back to `long`. The accessible grid heading always keeps the long month/year form. |
17
18
  | `selection` | `single \| none` | `single` | Whether accepted activation updates `value`. |
18
19
  | `fixed-weeks` | boolean | false | Render six rows; date math itself stays 4–6. |
19
20
  | `show-week-numbers` | boolean | false | Show ISO week numbers. The column renders only when `first-day === 1` (Monday-first): the ISO week and the displayed week only coincide then. With Sunday-first (`0`/`7`) the column is silently withheld. |
@@ -132,6 +133,7 @@ The direct child text input is required. On enhancement its original `name` move
132
133
  - `min`;
133
134
  - `max`;
134
135
  - `open-on-focus` — boolean (default `true`): open the popover when the input receives focus without moving focus; `open-on-focus="false"` keeps focus alone passive;
136
+ - `month-format` — `long | short` (default `long`): visible month-name style forwarded to the popup calendar;
135
137
  - `open` — read-only: whether the popover is shown;
136
138
  - `openOnFocus` — property form of `open-on-focus`.
137
139
 
@@ -173,6 +175,51 @@ await picker.validate();
173
175
 
174
176
  Calendar selection also dispatches normal bubbling `input` and `change` events on the visible input.
175
177
 
178
+ ### Time companions
179
+
180
+ Date with one time:
181
+
182
+ ```html
183
+ <date-picker>
184
+ <input name="appointment[date]">
185
+ <input type="time" data-time-start name="appointment[time]">
186
+ </date-picker>
187
+ ```
188
+
189
+ ```text
190
+ appointment[date] = 2026-09-10
191
+ appointment[time] = 09:30
192
+ ```
193
+
194
+ Date with from/to times on the same day:
195
+
196
+ ```html
197
+ <date-picker>
198
+ <input name="appointment[date]">
199
+ <input type="time" data-time-start name="appointment[from]">
200
+ <input type="time" data-time-end name="appointment[to]">
201
+ </date-picker>
202
+ ```
203
+
204
+ ```text
205
+ appointment[date] = 2026-09-10
206
+ appointment[from] = 09:30
207
+ appointment[to] = 11:00
208
+ ```
209
+
210
+ The submit contract is: `date-picker` owns the civil date selection, the time inputs own their civil time values, the authored HTML `name`s own the submitted structure, and the server/application owns datetime composition plus timezone. The picker never constructs a combined datetime, timestamp or timezone-bearing value.
211
+
212
+ Future range + time projection (not supported yet — range mode leaves marked times native with a console warning):
213
+
214
+ ```text
215
+ period[start][date]
216
+ period[start][time]
217
+ period[end][date]
218
+ period[end][time]
219
+ ```
220
+
221
+ Optional native time companions (one or both). They are direct children, fixed at connect time, and stay fully native: no hidden input, no `picker.time` property, no `timechange` event — their `input`/`change` events bubble like the date field's. `value` stays a `YYYY-MM-DD` date. The picker only enforces from/to order (`start <= end`, equality allowed, see [D5](DECISIONS.md)); a missing, empty or `disabled` time lifts the constraint, and `validate()` aggregates date validity, native time validity and that order. Range mode does not support time companions yet: marked times there are left native with a console warning.
222
+
176
223
  ## `<date-picker range>` — shared range surface
177
224
 
178
225
  ```html
package/docs/DECISIONS.md CHANGED
@@ -37,4 +37,11 @@ Context: DOM-backed styling hooks become API the moment they are documented —
37
37
  - Opening on focus **never steals keyboard focus**: the user can start typing immediately. The grid takes focus only on ArrowDown, on the calendar trigger, or after the user moves the pointer into the popup.
38
38
  - `show()` / `hide()` are the control surface. `open` is a **read-only getter** reflecting the popover. There is no `open` attribute: the popover element is the single machine of truth and a second state machine would only drift.
39
39
  - `readonly` mirrors native semantics: the field is non-editable, the value is still submitted, and the picker cannot change it — the calendar trigger is disabled. `disabled` additionally unsubmits the field. `readonly` is never used to mean "no typing, but calendar selection allowed".
40
- - Clearing the editable input clears the canonical value (the component renders no internal clear button). Form resets follow the native `defaultValue` contract. This matches the Open UI datepicker `clear` concept: clearing is a text-editing action, not a component-owned affordance.
40
+ - Clearing the editable input clears the canonical value (the component renders no internal clear button). Form resets follow the native `defaultValue` contract. This matches the Open UI datepicker `clear` concept: clearing is a text-editing action, not a component-owned affordance.
41
+
42
+ ## D5 — Time is a native companion, not picker state
43
+
44
+ - Time fields are authored native `input[type=time]` marked `[data-time-start]` / `[data-time-end]`; `name`, `value`, `required`, `min`, `max`, `step` and submission stay native. There is no hidden time input and no time field controller.
45
+ - `picker.value` / `picker.range` remain date-only (`YYYY-MM-DD`); the picker never constructs a datetime, a timestamp or a timezone-bearing value.
46
+ - The picker only coordinates from/to order (`start <= end`, equality allowed); duration rules stay application-owned.
47
+ - Custom time UI and slot picking stay outside the package.
package/docs/ROADMAP.md CHANGED
@@ -50,7 +50,8 @@ Use Formidable/Flatpickr cases as migration fixtures:
50
50
 
51
51
  These should require a separate proposal, not opportunistic growth:
52
52
 
53
- - time picker / datetime picker;
53
+ - custom time-picker UI;
54
+ - combined datetime values;
54
55
  - single-grid visual **selection** interaction (the band itself is core presentation via `calendar.highlightedRange`);
55
56
  - month-as-value picker;
56
57
  - multi-date;
@@ -86,7 +87,7 @@ Cross-check our coverage against the Open UI datepicker research: <https://open-
86
87
  | `range` | core | `<date-picker range>` two-field shared surface (U9); `linkDateRange()` stays external (U5). |
87
88
  | `range selected` | deferred | selection interaction needs its own proposal; `highlightedRange` covers band presentation only. |
88
89
  | `range presets` | deferred | application-owned. |
89
- | `date-time picker` | deferred | time/datetime is explicitly out of scope. |
90
+ | `date-time picker` | contract boundary | native `input[type=time]` companions only (D5); custom time-picker UI, combined datetime values and timezone-aware values stay deferred. |
90
91
  | `side by side` | deferred | maps to "multiple visible months". |
91
92
  | `footer` | deferred | not part of the grid contract. |
92
93
  | `shape`, `size`, `compact`, `subtle`, `light`, `borderless`, `no icon` | app-owned | styling via public `--dp-*` tokens (D3), not a component API. |
package/docs/USE_CASES.md CHANGED
@@ -35,7 +35,8 @@ Acceptance:
35
35
  - activating a date dispatches `dateactivate` and the application calls `calendarView.gotoDate(date)`;
36
36
  - outside-month days remain activatable;
37
37
  - six-row height is available as presentation, not baked into month math;
38
- - ISO week numbers are available.
38
+ - ISO week numbers are available;
39
+ - a narrow/compact presentation can use short month names (`month-format="short"`).
39
40
 
40
41
  ## U4 — Constrained dates
41
42
 
@@ -112,6 +113,18 @@ Acceptance:
112
113
  - a stale async availability response arriving after the active endpoint changed never commits a value or closes the popup;
113
114
  - only the bounds are validated; per-night availability stays application-owned.
114
115
 
116
+ ## U10 — Date with native time companions
117
+
118
+ A form pairs a date with one or two native times (appointment at `09:30`, from/to on the same day).
119
+
120
+ Acceptance:
121
+
122
+ - times stay native `input[type=time]` fields with their own names and submission;
123
+ - `value` stays a `YYYY-MM-DD` date;
124
+ - an inverted from/to surfaces an order error on the modified bound;
125
+ - a missing or disabled time lifts the order constraint;
126
+ - calendar selection and form reset keep the entered times.
127
+
115
128
  ## Not a use case for this package
116
129
 
117
130
  Do not grow the API to cover these without a separate design:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lekoala/date-picker",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Native-first date picker and inline calendar primitives",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -143,7 +143,7 @@
143
143
  "typecheck": "tsc -p jsconfig.json",
144
144
  "types": "tsc -p tsconfig.types.json",
145
145
  "test": "bun test test/unit",
146
- "test:syntax": "node --check src/date.js && node --check src/intl.js && node --check src/calendar-model.js && node --check src/source.js && node --check src/messages.js && node --check src/date-calendar.js && node --check src/date-field.js && node --check src/date-picker.js && node --check src/date-range.js && node --check src/index.js && node --check src/define.js",
146
+ "test:syntax": "node --check src/date.js && node --check src/intl.js && node --check src/calendar-model.js && node --check src/source.js && node --check src/messages.js && node --check src/date-calendar.js && node --check src/date-field.js && node --check src/date-picker.js && node --check src/date-range.js && node --check src/time.js && node --check src/index.js && node --check src/define.js",
147
147
  "test:types": "tsc -p test/types/tsconfig.json",
148
148
  "test:browser": "playwright test browser --project chromium",
149
149
  "test:browser:accessibility": "playwright test test/browser/picker.spec.js test/browser/focus.spec.js test/browser/calendar.spec.js test/browser/form-state.spec.js test/browser/surfaces.spec.js",
@@ -11,7 +11,14 @@ import {
11
11
  todayISO,
12
12
  } from "./date.js";
13
13
  import { normalizeRange, rangePosition } from "./date-range.js";
14
- import { formatLongDate, formatMonthYear, monthNames, resolveLocale, weekdayNames } from "./intl.js";
14
+ import {
15
+ formatLongDate,
16
+ formatMonthYear,
17
+ monthNames,
18
+ monthYearOrder,
19
+ resolveLocale,
20
+ weekdayNames,
21
+ } from "./intl.js";
15
22
  import { getDefaultMessages } from "./messages.js";
16
23
  import { normalizeDateStates } from "./source.js";
17
24
 
@@ -93,6 +100,7 @@ export class DateCalendarElement extends HTMLElement {
93
100
  "fixed-weeks",
94
101
  "show-week-numbers",
95
102
  "selection",
103
+ "month-format",
96
104
  ];
97
105
 
98
106
  constructor() {
@@ -237,6 +245,16 @@ export class DateCalendarElement extends HTMLElement {
237
245
  this.setAttribute("selection", value === "none" ? "none" : "single");
238
246
  }
239
247
 
248
+ /** @public Visible month-name style in the month select (`long` | `short`); anything else falls back to `long`. The accessible grid heading always keeps the long month/year form. */
249
+ get monthFormat() {
250
+ return this.getAttribute("month-format") === "short" ? "short" : "long";
251
+ }
252
+
253
+ set monthFormat(value) {
254
+ if (value === "short") this.setAttribute("month-format", "short");
255
+ else this.removeAttribute("month-format");
256
+ }
257
+
240
258
  /** @public */
241
259
  get highlightedRange() {
242
260
  return { ...this._highlightedRange };
@@ -688,7 +706,7 @@ export class DateCalendarElement extends HTMLElement {
688
706
  const display = this.display;
689
707
  const displayYear = yearOf(display);
690
708
  const displayMonth = Number(display.slice(5, 7));
691
- const names = monthNames(locale, "long");
709
+ const names = monthNames(locale, this.monthFormat);
692
710
  const weekdayShort = weekdayNames(locale, this.firstDay, "short");
693
711
  const weekdayLong = weekdayNames(locale, this.firstDay, "long");
694
712
  const weeks = this._weeks();
@@ -758,14 +776,22 @@ export class DateCalendarElement extends HTMLElement {
758
776
  ? this._focusTargetKey(focusedElement)
759
777
  : "";
760
778
 
779
+ // Visible month/year controls follow the locale order (Intl-derived, never
780
+ // direction-derived); the flexible header track stays under the month
781
+ // select via `data-year-first`.
782
+ const yearFirst = monthYearOrder(locale)[0] === "year";
783
+ this.toggleAttribute("data-year-first", yearFirst);
784
+ const monthControl = `<label class="dp-visually-hidden" for="${this._id}-month">${escapeHtml(this._messages.month)}</label>
785
+ <select id="${this._id}-month" class="dp-month-select" aria-label="${escapeHtml(this._messages.month)}">${monthOptions}</select>`;
786
+ const yearControl = `<label class="dp-visually-hidden" for="${this._id}-year">${escapeHtml(this._messages.year)}</label>
787
+ <input id="${this._id}-year" class="dp-year-input" type="number" inputmode="numeric" value="${displayYear}"${minYearAttr}${maxYearAttr} aria-label="${escapeHtml(this._messages.year)}">`;
788
+
761
789
  this._rendering = true;
762
790
  this.innerHTML = `
763
791
  <div class="dp-calendar-shell">
764
792
  <div class="dp-calendar-header">
765
- <label class="dp-visually-hidden" for="${this._id}-month">${escapeHtml(this._messages.month)}</label>
766
- <select id="${this._id}-month" class="dp-month-select" aria-label="${escapeHtml(this._messages.month)}">${monthOptions}</select>
767
- <label class="dp-visually-hidden" for="${this._id}-year">${escapeHtml(this._messages.year)}</label>
768
- <input id="${this._id}-year" class="dp-year-input" type="number" inputmode="numeric" value="${displayYear}"${minYearAttr}${maxYearAttr} aria-label="${escapeHtml(this._messages.year)}">
793
+ ${yearFirst ? yearControl : monthControl}
794
+ ${yearFirst ? monthControl : yearControl}
769
795
  <button type="button" class="dp-nav dp-prev" data-calendar-action="previous" aria-label="${escapeHtml(this._messages.previousMonth)}"${prevDisabled ? " disabled" : ""}><svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="m10 4-4 4 4 4"/></svg></button>
770
796
  <button type="button" class="dp-nav dp-next" data-calendar-action="next" aria-label="${escapeHtml(this._messages.nextMonth)}"${nextDisabled ? " disabled" : ""}><svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="m6 4 4 4-4 4"/></svg></button>
771
797
  </div>
@@ -779,7 +805,16 @@ export class DateCalendarElement extends HTMLElement {
779
805
 
780
806
  if (focusKey) {
781
807
  queueMicrotask(() => {
782
- const target = this.querySelector(focusKey);
808
+ let selector = focusKey;
809
+ // A day-cell key goes stale across display changes: the old date can
810
+ // reappear as outside-month padding in the new month (fixed-weeks or
811
+ // overlapping edge weeks). Restoring it would yank keyboard focus back
812
+ // onto the date the user just navigated away from, so retarget day
813
+ // cells to the current keyboard position. Controls keep exact restore.
814
+ if (selector.startsWith(".dp-day[data-date=")) {
815
+ selector = `.dp-day[data-date="${CSS.escape(this._model.focused)}"]`;
816
+ }
817
+ const target = this.querySelector(selector);
783
818
  if (target instanceof HTMLElement) target.focus();
784
819
  });
785
820
  }
@@ -9,6 +9,11 @@
9
9
  --dp-radius: 0.5rem;
10
10
  --dp-day-size: 2.75rem;
11
11
  --dp-gap: 0.25rem;
12
+ --dp-header-control-size: 2.25rem;
13
+ --dp-header-block-gap: 0.4rem;
14
+ --dp-nav-gap: calc(var(--dp-gap) * 2.5);
15
+ --dp-year-inline-size: 5.5rem;
16
+ --dp-day-radius: calc(var(--dp-radius) * 0.75);
12
17
  color: var(--dp-fg);
13
18
  font: inherit;
14
19
  }
@@ -39,22 +44,46 @@ date-calendar {
39
44
  .dp-calendar-header {
40
45
  display: grid;
41
46
  grid-template-columns: minmax(0, 1fr) auto auto auto;
42
- align-items: center;
47
+ /* Stretch (not center): once a UA natural height exceeds
48
+ --dp-header-control-size, the row grows to the tallest control and the
49
+ others stretch to match, so month/year/nav stay equal. */
50
+ align-items: stretch;
43
51
  gap: var(--dp-gap);
44
- margin-block-end: 0.4rem;
52
+ margin-block-end: var(--dp-header-block-gap);
53
+ }
54
+
55
+ /* Locale year-first order (Intl-derived, direction-independent): the flexible
56
+ track stays under the month select so the fixed-width year input never
57
+ stretches. Visual mirroring itself is left to the inherited `dir`. */
58
+ date-calendar[data-year-first] .dp-calendar-header {
59
+ grid-template-columns: auto minmax(0, 1fr) auto auto;
45
60
  }
46
61
 
47
62
  .dp-calendar-header .dp-prev {
48
- margin-inline-start: calc(var(--dp-gap) * 2.5);
63
+ margin-inline-start: var(--dp-nav-gap);
49
64
  }
50
65
 
51
66
  .dp-calendar-header :where(button, select, input) {
52
- min-block-size: 2.25rem;
67
+ min-block-size: var(--dp-header-control-size);
68
+ box-sizing: border-box;
69
+ /* Shared vertical metrics: UA default padding/line-height differ per control
70
+ (up to ~13px apart), which only shows once --dp-header-control-size drops
71
+ below content size. */
72
+ padding-block: 0.15rem;
53
73
  border: 1px solid var(--dp-border);
54
74
  border-radius: calc(var(--dp-radius) * 0.75);
55
75
  background: var(--dp-bg);
56
76
  color: var(--dp-fg);
57
77
  font: inherit;
78
+ line-height: 1.2;
79
+ }
80
+
81
+ /* The select menulist carries UA-internal leading that author padding only
82
+ adds to (and it ignores line-height), so it gets zero author padding.
83
+ Equal outer heights come from the header grid's stretch alignment: the row
84
+ sizes to the tallest control and the others stretch to match. */
85
+ .dp-calendar-header select {
86
+ padding-block: 0;
58
87
  }
59
88
 
60
89
  .dp-calendar-header select,
@@ -65,16 +94,20 @@ date-calendar {
65
94
 
66
95
  .dp-month-select {
67
96
  inline-size: 100%;
97
+ /* Long month names in a narrow track (compact consumers, long locales)
98
+ would paint under the native caret: truncate with an ellipsis instead. */
99
+ overflow: hidden;
100
+ text-overflow: ellipsis;
68
101
  }
69
102
 
70
103
  .dp-year-input {
71
- inline-size: 5.5rem;
104
+ inline-size: var(--dp-year-inline-size);
72
105
  }
73
106
 
74
107
  .dp-nav {
75
108
  display: grid;
76
109
  place-items: center;
77
- inline-size: 2.25rem;
110
+ inline-size: var(--dp-header-control-size);
78
111
  padding: 0;
79
112
  font-size: 1.35rem;
80
113
  line-height: 1;
@@ -88,6 +121,14 @@ date-calendar {
88
121
  pointer-events: none;
89
122
  }
90
123
 
124
+ /* Inherited RTL mirrors the header layout via the grid; mirror the nav glyphs
125
+ so previous/next keep their visual sense. Actions stay chronological: no
126
+ button swap, no keyboard remapping. */
127
+ [dir="rtl"] .dp-nav svg,
128
+ html[dir="rtl"] .dp-nav svg {
129
+ transform: scaleX(-1);
130
+ }
131
+
91
132
  .dp-calendar-header :where(button, select, input):disabled,
92
133
  .dp-picker-button:disabled {
93
134
  cursor: not-allowed;
@@ -133,7 +174,7 @@ date-calendar {
133
174
  .dp-day {
134
175
  position: relative;
135
176
  border: 1px solid transparent;
136
- border-radius: calc(var(--dp-radius) * 0.75);
177
+ border-radius: var(--dp-day-radius);
137
178
  cursor: pointer;
138
179
  outline: none;
139
180
  vertical-align: middle;
@@ -142,10 +183,21 @@ date-calendar {
142
183
 
143
184
  .dp-day:focus-visible {
144
185
  outline: 2px solid var(--dp-accent);
145
- outline-offset: 1px;
186
+ outline-offset: 2px;
187
+ /* Separation gap between the cell fill and the ring: invisible on plain
188
+ days, but keeps the ring readable on accent-filled days (selected, range
189
+ endpoints) where an accent-on-accent outline would disappear. */
190
+ box-shadow: 0 0 0 2px var(--dp-bg);
146
191
  z-index: 1;
147
192
  }
148
193
 
194
+ /* Base tint for days outside the displayed month. It stays before the
195
+ selection states so selected/range endpoints keep their accent-contrast
196
+ text on the accent fill (equal specificity, source order decides). */
197
+ .dp-day[data-outside-month="true"] {
198
+ color: var(--dp-muted);
199
+ }
200
+
149
201
  .dp-day[data-selected="true"] {
150
202
  background: var(--dp-accent);
151
203
  color: var(--dp-accent-fg);
@@ -155,10 +207,6 @@ date-calendar {
155
207
  border-color: var(--dp-accent);
156
208
  }
157
209
 
158
- .dp-day[data-outside-month="true"] {
159
- color: var(--dp-muted);
160
- }
161
-
162
210
  .dp-day[data-disabled="true"] {
163
211
  cursor: not-allowed;
164
212
  opacity: 0.42;
@@ -201,6 +249,17 @@ date-calendar {
201
249
  font-variant-numeric: tabular-nums;
202
250
  }
203
251
 
252
+ /* A focused disabled day stays discoverable by keyboard: restore full opacity
253
+ so the focus outline renders at full strength, and mark the number with the
254
+ muted tone (same language as outside-month days) instead of the wash-out. */
255
+ .dp-day[data-disabled="true"]:focus-visible {
256
+ opacity: 1;
257
+ }
258
+
259
+ .dp-day[data-disabled="true"]:focus-visible .dp-day-number {
260
+ color: var(--dp-muted);
261
+ }
262
+
204
263
  .dp-day-extra {
205
264
  position: absolute;
206
265
  inset-inline: 2px;
@@ -235,16 +294,56 @@ date-picker > input:not([type="hidden"]) {
235
294
  min-inline-size: 0;
236
295
  }
237
296
 
297
+ /* Optional native time companions share the date row; authored inputs stay
298
+ consumer-styled, the picker only reserves their grid cells. Time tracks are
299
+ flexible (never `auto`) so a wide UA time control cannot squeeze the date. */
300
+ date-picker:has(> [data-time-start], > [data-time-end]) {
301
+ grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
302
+ }
303
+
304
+ date-picker:has(> [data-time-start]):has(> [data-time-end]) {
305
+ grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) minmax(0, 1fr);
306
+ }
307
+
308
+ date-picker > input[data-time-start] {
309
+ grid-column: 3;
310
+ grid-row: 1;
311
+ min-inline-size: 0;
312
+ inline-size: 100%;
313
+ margin-inline-start: var(--dp-gap);
314
+ }
315
+
316
+ date-picker > input[data-time-end] {
317
+ grid-column: 4;
318
+ grid-row: 1;
319
+ min-inline-size: 0;
320
+ inline-size: 100%;
321
+ }
322
+
323
+ /* From/to read as one joined control: square the inner corners, but only
324
+ when both companions are present so a lone time keeps its own radius. */
325
+ date-picker:has(> [data-time-start]):has(> [data-time-end]) > input[data-time-start] {
326
+ border-start-end-radius: 0;
327
+ border-end-end-radius: 0;
328
+ }
329
+
330
+ date-picker:has(> [data-time-start]):has(> [data-time-end]) > input[data-time-end] {
331
+ border-start-start-radius: 0;
332
+ border-end-start-radius: 0;
333
+ }
334
+
238
335
  date-picker[range] > input:not([type="hidden"]) {
239
336
  grid-column: 1;
240
337
  }
241
338
 
242
339
  date-picker[range] > input[data-range-start] {
243
340
  grid-row: 1;
341
+ border-end-start-radius: 0;
244
342
  }
245
343
 
246
344
  date-picker[range] > input[data-range-end] {
247
345
  grid-row: 2;
346
+ border-start-start-radius: 0;
248
347
  }
249
348
 
250
349
  .dp-picker-button {