@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.
- package/README.md +27 -4
- package/custom-elements.json +44 -0
- package/dist/date-picker.css +111 -12
- package/dist/date-picker.js +162 -13
- package/dist/date-picker.min.css +1 -1
- package/dist/date-picker.min.js +13 -13
- package/dist/date-picker.standalone.min.js +125 -26
- package/dist/types/date-calendar.d.ts +3 -0
- package/dist/types/date-calendar.d.ts.map +1 -1
- package/dist/types/date-picker.d.ts +24 -0
- package/dist/types/date-picker.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/intl.d.ts +9 -0
- package/dist/types/intl.d.ts.map +1 -1
- package/dist/types/time.d.ts +8 -0
- package/dist/types/time.d.ts.map +1 -0
- package/docs/API.md +47 -0
- package/docs/DECISIONS.md +8 -1
- package/docs/ROADMAP.md +3 -2
- package/docs/USE_CASES.md +14 -1
- package/package.json +2 -2
- package/src/date-calendar.js +42 -7
- package/src/date-picker.css +111 -12
- package/src/date-picker.js +108 -5
- package/src/index.js +1 -0
- package/src/intl.js +35 -0
- package/src/time.js +39 -0
|
@@ -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":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAkB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"date-picker.d.ts","sourceRoot":"","sources":["../../src/date-picker.js"],"names":[],"mappings":"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"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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"}
|
package/dist/types/intl.d.ts
CHANGED
|
@@ -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
|
/**
|
package/dist/types/intl.d.ts.map
CHANGED
|
@@ -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
|
|
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` |
|
|
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.
|
|
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",
|
package/src/date-calendar.js
CHANGED
|
@@ -11,7 +11,14 @@ import {
|
|
|
11
11
|
todayISO,
|
|
12
12
|
} from "./date.js";
|
|
13
13
|
import { normalizeRange, rangePosition } from "./date-range.js";
|
|
14
|
-
import {
|
|
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,
|
|
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
|
-
|
|
766
|
-
|
|
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
|
-
|
|
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
|
}
|
package/src/date-picker.css
CHANGED
|
@@ -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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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 {
|