@lekoala/date-picker 0.1.0 → 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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"}
@@ -40,6 +40,12 @@ export declare function startOfMonth(value: string): string;
40
40
  export declare function endOfMonth(value: string): string;
41
41
  /** 0=Sunday ... 6=Saturday. @param {string} value */
42
42
  export declare function dayOfWeek(value: string): number;
43
+ /**
44
+ * Canonical first weekday. 7 is the ISO-style Sunday alias of 0; values 1..6
45
+ * keep their current meaning. Any other value throws.
46
+ * @param {number} firstDay
47
+ */
48
+ export declare function normalizeFirstDay(firstDay: number): number;
43
49
  /** @param {string} value @param {number} firstDay */
44
50
  export declare function startOfWeek(value: string, firstDay?: number): string;
45
51
  /** @param {string} value @param {number} firstDay */
@@ -1 +1 @@
1
- {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../src/date.js"],"names":[],"mappings":"AAGA,2BAA2B;AAC3B,wBAAgB,UAAU,CAAC,IAAI,EADnB,MACmB,WAE9B;AAED,iDAAiD;AACjD,wBAAgB,WAAW,CAAC,IAAI,EADpB,MACoB,EAAE,KAAK,EADN,MACM,qBAGtC;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAHpB,MAGoB,GAFlB;IAAC,IAAI,EAAC,MAAM,CAAC;IAAC,KAAK,EAAC,MAAM,CAAC;IAAC,GAAG,EAAC,MAAM,CAAA;CAAC,GAAG,IAAI,CAW1D;AAED,4BAA4B;AAC5B,wBAAgB,MAAM,CAAC,KAAK,EADhB,MACgB,WAE3B;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAHnB,MAGmB,GAFjB,MAAM,CAYlB;AAED,qEAAqE;AACrE,wBAAgB,SAAS,CAAC,IAAI,EADlB,MACkB,EAAE,KAAK,EADJ,MACI,EAAE,GAAG,EADa,MACb,UAIzC;AAeD,4BAA4B;AAC5B,wBAAgB,UAAU,CAAC,KAAK,EADpB,MACoB,QAI/B;AAED,0CAA0C;AAC1C,wBAAgB,YAAY,CAAC,CAAC,EADlB,MACkB,EAAE,CAAC,EADH,MACG,cAGhC;AAED,mDAAmD;AACnD,wBAAgB,OAAO,CAAC,KAAK,EADjB,MACiB,EAAE,MAAM,EADH,MACG,UAOpC;AAED,mDAAmD;AACnD,wBAAgB,SAAS,CAAC,KAAK,EADnB,MACmB,EAAE,MAAM,EADL,MACK,UAUtC;AAED,mDAAmD;AACnD,wBAAgB,QAAQ,CAAC,KAAK,EADlB,MACkB,EAAE,MAAM,EADJ,MACI,UAOrC;AAED,mDAAmD;AACnD,wBAAgB,UAAU,CAAC,KAAK,EADpB,MACoB,EAAE,MAAM,EADN,MACM,UAGvC;AAED,4BAA4B;AAC5B,wBAAgB,YAAY,CAAC,KAAK,EADtB,MACsB,UAEjC;AAED,4BAA4B;AAC5B,wBAAgB,UAAU,CAAC,KAAK,EADpB,MACoB,UAI/B;AAED,qDAAqD;AACrD,wBAAgB,SAAS,CAAC,KAAK,EADM,MACN,UAI9B;AAED,qDAAqD;AACrD,wBAAgB,WAAW,CAAC,KAAK,EADrB,MACqB,EAAE,QAAQ,GADT,MACa,UAK9C;AAED,qDAAqD;AACrD,wBAAgB,SAAS,CAAC,KAAK,EADnB,MACmB,EAAE,QAAQ,GADP,MACW,UAE5C;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAHxB,MAGwB,EAAE,OAAO,AAFzC,CAAsC,EAA9B;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAEoB,cAchD;AAED,wEAAwE;AACxE,wBAAgB,SAAS,CAAC,KAAK,EADnB,MACmB,EAAE,GAAG,AADV,CAAsB,EAAd,MACO,EAAE,GAAG,AADE,CAAqB,EAAb,MACL,UAKlD;AAED,2EAA2E;AAC3E,wBAAgB,QAAQ,WAGvB;AAED,kDAAkD;AAClD,wBAAgB,aAAa,CAAC,KAAK,EADD,MACC,UAUlC"}
1
+ {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../src/date.js"],"names":[],"mappings":"AAGA,2BAA2B;AAC3B,wBAAgB,UAAU,CAAC,IAAI,EADnB,MACmB,WAE9B;AAED,iDAAiD;AACjD,wBAAgB,WAAW,CAAC,IAAI,EADpB,MACoB,EAAE,KAAK,EADN,MACM,qBAGtC;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAHpB,MAGoB,GAFlB;IAAC,IAAI,EAAC,MAAM,CAAC;IAAC,KAAK,EAAC,MAAM,CAAC;IAAC,GAAG,EAAC,MAAM,CAAA;CAAC,GAAG,IAAI,CAW1D;AAED,4BAA4B;AAC5B,wBAAgB,MAAM,CAAC,KAAK,EADhB,MACgB,WAE3B;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAHnB,MAGmB,GAFjB,MAAM,CAYlB;AAED,qEAAqE;AACrE,wBAAgB,SAAS,CAAC,IAAI,EADlB,MACkB,EAAE,KAAK,EADJ,MACI,EAAE,GAAG,EADa,MACb,UAIzC;AAeD,4BAA4B;AAC5B,wBAAgB,UAAU,CAAC,KAAK,EADpB,MACoB,QAI/B;AAED,0CAA0C;AAC1C,wBAAgB,YAAY,CAAC,CAAC,EADlB,MACkB,EAAE,CAAC,EADH,MACG,cAGhC;AAED,mDAAmD;AACnD,wBAAgB,OAAO,CAAC,KAAK,EADjB,MACiB,EAAE,MAAM,EADH,MACG,UAOpC;AAED,mDAAmD;AACnD,wBAAgB,SAAS,CAAC,KAAK,EADnB,MACmB,EAAE,MAAM,EADL,MACK,UAUtC;AAED,mDAAmD;AACnD,wBAAgB,QAAQ,CAAC,KAAK,EADlB,MACkB,EAAE,MAAM,EADJ,MACI,UAOrC;AAED,mDAAmD;AACnD,wBAAgB,UAAU,CAAC,KAAK,EADpB,MACoB,EAAE,MAAM,EADN,MACM,UAGvC;AAED,4BAA4B;AAC5B,wBAAgB,YAAY,CAAC,KAAK,EADtB,MACsB,UAEjC;AAED,4BAA4B;AAC5B,wBAAgB,UAAU,CAAC,KAAK,EADpB,MACoB,UAI/B;AAED,qDAAqD;AACrD,wBAAgB,SAAS,CAAC,KAAK,EADM,MACN,UAI9B;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAF/B,MAE+B,UAKzC;AAED,qDAAqD;AACrD,wBAAgB,WAAW,CAAC,KAAK,EADrB,MACqB,EAAE,QAAQ,GADT,MACa,UAG9C;AAED,qDAAqD;AACrD,wBAAgB,SAAS,CAAC,KAAK,EADnB,MACmB,EAAE,QAAQ,GADP,MACW,UAE5C;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAHxB,MAGwB,EAAE,OAAO,AAFzC,CAAsC,EAA9B;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAEoB,cAchD;AAED,wEAAwE;AACxE,wBAAgB,SAAS,CAAC,KAAK,EADnB,MACmB,EAAE,GAAG,AADV,CAAsB,EAAd,MACO,EAAE,GAAG,AADE,CAAqB,EAAb,MACL,UAKlD;AAED,2EAA2E;AAC3E,wBAAgB,QAAQ,WAGvB;AAED,kDAAkD;AAClD,wBAAgB,aAAa,CAAC,KAAK,EADD,MACC,UAUlC"}
@@ -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,YActE;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
@@ -12,11 +12,12 @@ The public surface — flat event names, `selection` values, `--dp-*` styling to
12
12
  | `display` | `YYYY-MM` | value/today month | Month being rendered. |
13
13
  | `min` | `YYYY-MM-DD` | `""` | Earliest activatable date. |
14
14
  | `max` | `YYYY-MM-DD` | `""` | Latest activatable date. |
15
- | `first-day` | `0..6` | `1` | First weekday; Sunday=0, Monday=1. |
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
- | `show-week-numbers` | boolean | false | Show ISO week numbers. |
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. |
20
21
 
21
22
  `focusedDate` and `highlightedRange` are properties rather than reflected attributes.
22
23
 
@@ -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
@@ -283,7 +330,10 @@ Public helpers:
283
330
  - `dayOfWeek`
284
331
  - `startOfWeek`
285
332
  - `endOfWeek`
333
+ - `normalizeFirstDay`
286
334
  - `getMonthWeeks`
287
335
  - `clampDate`
288
336
  - `todayISO`
289
337
  - `isoWeekNumber`
338
+
339
+ `normalizeFirstDay(firstDay)` maps `7` to `0` (Sunday) and returns `0..6` unchanged; any other value throws a `RangeError`. It backs `startOfWeek`, `getMonthWeeks` and `weekdayNames`, so those accept `7` as the ISO-style Sunday alias `@lekoala/calendar` uses while `2..6` keep their current meaning.
@@ -25,21 +25,27 @@ A minimal sidebar navigator therefore looks like this:
25
25
  const mini = document.querySelector("#mini");
26
26
  const agenda = document.querySelector("#agenda");
27
27
 
28
- mini.display = agenda.date.toString().slice(0, 7);
29
- mini.focusedDate = agenda.date.toString();
28
+ // The agenda anchor stays application state, not a model property.
29
+ let anchorDate = agenda.getAttribute("date");
30
+
31
+ mini.dateState = (date) => ({
32
+ description: date === anchorDate ? "Shown in the agenda" : "Navigate to this date",
33
+ anchor: date === anchorDate,
34
+ });
30
35
 
31
36
  mini.addEventListener("dateactivate", (event) => {
32
37
  agenda.gotoDate(event.detail.date);
33
38
  });
34
39
 
35
40
  agenda.addEventListener("calendar:datechange", (event) => {
36
- const date = event.detail.date.toString();
37
- mini.display = date.slice(0, 7);
38
- mini.focusedDate = date;
41
+ anchorDate = event.detail.date.toString();
42
+ mini.display = anchorDate.slice(0, 7);
39
43
  });
40
44
  ```
41
45
 
42
- Notice what is missing: the mini calendar does not need a selected value. The agenda anchor is application/calendar state, not form selection state.
46
+ Do not anchor the mini calendar with `mini.focusedDate = date`. `display` and `focusedDate` are deliberately coupled: `setDisplay` re-clamps the focused day into the rendered month (`calendar-model.js`), because the roving-tabbable grid cell must stay visible (ARIA grid contract). So `focusedDate` is the keyboard target, never an application anchor. Keep the anchor in your own state and decorate it through the existing `dateState` / `renderDay` seams.
47
+
48
+ Notice what else is missing: the mini calendar does not need a selected value. The agenda anchor is application/calendar state, not form selection state.
43
49
 
44
50
  ## Active week / availability decoration
45
51
 
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.0",
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",
@@ -5,6 +5,7 @@ import {
5
5
  endOfWeek,
6
6
  isDate,
7
7
  monthKey,
8
+ normalizeFirstDay,
8
9
  shiftMonth,
9
10
  startOfWeek,
10
11
  todayISO,
@@ -16,7 +17,7 @@ export class CalendarModel {
16
17
  */
17
18
  constructor(options = {}) {
18
19
  const today = todayISO();
19
- this.firstDay = options.firstDay ?? 1;
20
+ this.firstDay = normalizeFirstDay(options.firstDay ?? 1);
20
21
  this.value = options.value && isDate(options.value) ? options.value : "";
21
22
  this.focused = options.focused && isDate(options.focused) ? options.focused : this.value || today;
22
23
  this.display = options.display ? monthKey(options.display) : monthKey(this.focused);
@@ -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
 
@@ -30,6 +37,7 @@ function escapeHtml(value) {
30
37
  /** @param {string} value */
31
38
  function parseFirstDay(value) {
32
39
  const parsed = Number(value);
40
+ if (parsed === 7) return 0;
33
41
  return Number.isInteger(parsed) && parsed >= 0 && parsed <= 6 ? parsed : 1;
34
42
  }
35
43
 
@@ -92,6 +100,7 @@ export class DateCalendarElement extends HTMLElement {
92
100
  "fixed-weeks",
93
101
  "show-week-numbers",
94
102
  "selection",
103
+ "month-format",
95
104
  ];
96
105
 
97
106
  constructor() {
@@ -236,6 +245,16 @@ export class DateCalendarElement extends HTMLElement {
236
245
  this.setAttribute("selection", value === "none" ? "none" : "single");
237
246
  }
238
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
+
239
258
  /** @public */
240
259
  get highlightedRange() {
241
260
  return { ...this._highlightedRange };
@@ -687,7 +706,7 @@ export class DateCalendarElement extends HTMLElement {
687
706
  const display = this.display;
688
707
  const displayYear = yearOf(display);
689
708
  const displayMonth = Number(display.slice(5, 7));
690
- const names = monthNames(locale, "long");
709
+ const names = monthNames(locale, this.monthFormat);
691
710
  const weekdayShort = weekdayNames(locale, this.firstDay, "short");
692
711
  const weekdayLong = weekdayNames(locale, this.firstDay, "long");
693
712
  const weeks = this._weeks();
@@ -757,18 +776,26 @@ export class DateCalendarElement extends HTMLElement {
757
776
  ? this._focusTargetKey(focusedElement)
758
777
  : "";
759
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
+
760
789
  this._rendering = true;
761
790
  this.innerHTML = `
762
791
  <div class="dp-calendar-shell">
763
792
  <div class="dp-calendar-header">
764
- <label class="dp-visually-hidden" for="${this._id}-month">${escapeHtml(this._messages.month)}</label>
765
- <select id="${this._id}-month" class="dp-month-select" aria-label="${escapeHtml(this._messages.month)}">${monthOptions}</select>
766
- <label class="dp-visually-hidden" for="${this._id}-year">${escapeHtml(this._messages.year)}</label>
767
- <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}
768
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>
769
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>
770
797
  </div>
771
- <h2 id="${headingId}" class="dp-calendar-heading" aria-live="polite">${escapeHtml(formatMonthYear(`${display}-15`, locale))}</h2>
798
+ <h2 id="${headingId}" class="dp-calendar-heading dp-visually-hidden" aria-live="polite">${escapeHtml(formatMonthYear(`${display}-15`, locale))}</h2>
772
799
  <table id="${gridId}" class="dp-grid" role="grid" aria-labelledby="${headingId}">
773
800
  <thead><tr>${weekHeader}${dayHeaders}</tr></thead>
774
801
  <tbody>${rows}</tbody>
@@ -778,7 +805,16 @@ export class DateCalendarElement extends HTMLElement {
778
805
 
779
806
  if (focusKey) {
780
807
  queueMicrotask(() => {
781
- 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);
782
818
  if (target instanceof HTMLElement) target.focus();
783
819
  });
784
820
  }