@lilydesignsystem/angular-date-time-picker 0.1.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 +281 -0
- package/fesm2022/lilydesignsystem-angular-date-time-picker.mjs +2153 -0
- package/fesm2022/lilydesignsystem-angular-date-time-picker.mjs.map +1 -0
- package/package.json +48 -0
- package/types/lilydesignsystem-angular-date-time-picker.d.ts +558 -0
- package/types/lilydesignsystem-angular-date-time-picker.d.ts.map +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# Lily Design System™ — Angular DateTimePicker
|
|
2
|
+
|
|
3
|
+
A headless Angular 20 control for collecting a **date**, a **time**, or
|
|
4
|
+
**both**. A text field you can type into, plus an icon button that opens a
|
|
5
|
+
WAI-ARIA APG date-picker dialog with a full keyboard contract.
|
|
6
|
+
|
|
7
|
+
Ships zero CSS, zero icons, and zero hardcoded strings. Locale-correct by
|
|
8
|
+
construction: month names, weekday names, first day of week, numeric field
|
|
9
|
+
order, 12- vs 24-hour clock and AM/PM names all come from `Intl`.
|
|
10
|
+
|
|
11
|
+
Canonical contract: [spec/index.md](./spec/index.md). This package is the
|
|
12
|
+
Angular port of the Svelte-canonical
|
|
13
|
+
[`@lilydesignsystem/svelte-date-time-picker`](../../lily-design-system-svelte-helpers/lily-design-system-svelte-date-time-picker/).
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm install @lilydesignsystem/angular-date-time-picker
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Use it
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { Component } from "@angular/core";
|
|
25
|
+
import { DateTimePicker } from "@lilydesignsystem/angular-date-time-picker";
|
|
26
|
+
|
|
27
|
+
@Component({
|
|
28
|
+
selector: "app-booking",
|
|
29
|
+
standalone: true,
|
|
30
|
+
imports: [DateTimePicker],
|
|
31
|
+
template: `
|
|
32
|
+
<label for="appointment">Appointment date</label>
|
|
33
|
+
<lily-date-time-picker
|
|
34
|
+
inputId="appointment"
|
|
35
|
+
name="appointment"
|
|
36
|
+
label="Choose an appointment date"
|
|
37
|
+
locale="en-GB"
|
|
38
|
+
[(value)]="appointment"
|
|
39
|
+
[labels]="labels"
|
|
40
|
+
/>
|
|
41
|
+
`,
|
|
42
|
+
})
|
|
43
|
+
export class BookingComponent {
|
|
44
|
+
appointment = "";
|
|
45
|
+
|
|
46
|
+
readonly labels = {
|
|
47
|
+
previousYear: "Previous year",
|
|
48
|
+
previousMonth: "Previous month",
|
|
49
|
+
previousWeek: "Previous week",
|
|
50
|
+
previousDay: "Previous day",
|
|
51
|
+
nextDay: "Next day",
|
|
52
|
+
nextWeek: "Next week",
|
|
53
|
+
nextMonth: "Next month",
|
|
54
|
+
nextYear: "Next year",
|
|
55
|
+
confirm: "OK",
|
|
56
|
+
cancel: "Cancel",
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`appointment` is now an ISO string: `"2026-03-15"`.
|
|
62
|
+
|
|
63
|
+
## The value is always ISO
|
|
64
|
+
|
|
65
|
+
| `mode` | `value` |
|
|
66
|
+
| ------ | ------- |
|
|
67
|
+
| `"date"` (default) | `"2026-03-15"` |
|
|
68
|
+
| `"time"` | `"09:30"` |
|
|
69
|
+
| `"datetime"` | `"2026-03-15T09:30"` |
|
|
70
|
+
|
|
71
|
+
Sortable as a string, unambiguous in every locale, and identical to what
|
|
72
|
+
`<input type="date">` posts — so you can swap the native control in or out
|
|
73
|
+
without touching your backend.
|
|
74
|
+
|
|
75
|
+
**No time zone is attached.** A date here is a civil date and a time is a
|
|
76
|
+
wall-clock time. If you need an instant, combine the value with a zone in
|
|
77
|
+
your own code, deliberately.
|
|
78
|
+
|
|
79
|
+
## Everything it does
|
|
80
|
+
|
|
81
|
+
### Constrain what can be picked
|
|
82
|
+
|
|
83
|
+
```html
|
|
84
|
+
<lily-date-time-picker
|
|
85
|
+
[label]="label"
|
|
86
|
+
[labels]="labels"
|
|
87
|
+
min="2026-03-01"
|
|
88
|
+
max="2026-09-30"
|
|
89
|
+
[isDateDisabled]="isClosed"
|
|
90
|
+
/>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
isClosed = (iso: string) => weekdayOf(iso) === 0 || weekdayOf(iso) === 6;
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`min` / `max` are inclusive. `isDateDisabled` vetoes anything else — closed
|
|
98
|
+
days, fully-booked slots, bank holidays. Blocked days render
|
|
99
|
+
`aria-disabled="true"` (plus `data-disabled` for your CSS) rather than the
|
|
100
|
+
`disabled` attribute, so they stay focusable: the keyboard cursor can
|
|
101
|
+
cross them — a screen reader announces each as unavailable instead of
|
|
102
|
+
going silent — but they refuse selection.
|
|
103
|
+
|
|
104
|
+
### Quick picks
|
|
105
|
+
|
|
106
|
+
```html
|
|
107
|
+
<lily-date-time-picker
|
|
108
|
+
[label]="label"
|
|
109
|
+
[labels]="labels"
|
|
110
|
+
[shortcuts]="shortcuts"
|
|
111
|
+
(shortcut)="onShortcut($event)"
|
|
112
|
+
/>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
readonly shortcuts = [
|
|
117
|
+
{ id: "today", label: "Today", days: 0 },
|
|
118
|
+
{ id: "week", label: "In 1 week", days: 7 },
|
|
119
|
+
{ id: "month", label: "In 1 month", months: 1 },
|
|
120
|
+
{ id: "review", label: "Review date", date: "2026-09-01" },
|
|
121
|
+
];
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`months` uses calendar months, not 30 days — "+1 month" from 31 January is
|
|
125
|
+
28 February, not 2 March. A shortcut that resolves to a blocked date does
|
|
126
|
+
nothing rather than landing near it.
|
|
127
|
+
|
|
128
|
+
### Time, and date-and-time
|
|
129
|
+
|
|
130
|
+
```html
|
|
131
|
+
<lily-date-time-picker
|
|
132
|
+
mode="datetime"
|
|
133
|
+
[minuteStep]="15"
|
|
134
|
+
[label]="label"
|
|
135
|
+
[labels]="{ ...labels, hour: 'Hour', minute: 'Minute' }"
|
|
136
|
+
/>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
In `"datetime"` mode a day click sets the pending date only — the user
|
|
140
|
+
still has a time to choose — so the dialog waits for Confirm. An
|
|
141
|
+
incomplete datetime is never committed.
|
|
142
|
+
|
|
143
|
+
### Week numbers
|
|
144
|
+
|
|
145
|
+
```html
|
|
146
|
+
<lily-date-time-picker
|
|
147
|
+
[label]="label"
|
|
148
|
+
[labels]="{ ...labels, week: 'Wk' }"
|
|
149
|
+
[showWeekNumbers]="true"
|
|
150
|
+
/>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Real ISO-8601 week numbers, with the Thursday rule — so the week
|
|
154
|
+
containing 1 January 2021 is week 53, not week 1.
|
|
155
|
+
|
|
156
|
+
### Typing
|
|
157
|
+
|
|
158
|
+
The field accepts, in this order: ISO `2026-03-15`; a numeric form in the
|
|
159
|
+
locale's own field order (`03/04/2026` is 3 April in `en-GB`, 4 March in
|
|
160
|
+
`en-US`); and a written month (`27-Jun-2025`, `27 June 2025`, `Sept 5
|
|
161
|
+
2025`) matched against the locale's month names.
|
|
162
|
+
|
|
163
|
+
Text that will not parse — or that parses outside `min`/`max` — stays in
|
|
164
|
+
the field, sets `aria-invalid="true"`, and fires `(invalidInput)`. It is
|
|
165
|
+
never silently snapped to a nearby legal date. Supply `[parseInput]` to
|
|
166
|
+
plug in your own parser. `Escape` discards a pending edit and shows the
|
|
167
|
+
committed value again.
|
|
168
|
+
|
|
169
|
+
### Announce refusals, and explain the keyboard
|
|
170
|
+
|
|
171
|
+
Two optional labels make the control markedly better with a screen
|
|
172
|
+
reader; supply both:
|
|
173
|
+
|
|
174
|
+
```html
|
|
175
|
+
<lily-date-time-picker
|
|
176
|
+
[label]="label"
|
|
177
|
+
[labels]="{
|
|
178
|
+
...labels,
|
|
179
|
+
invalid: 'Enter a date like 21 3 2026',
|
|
180
|
+
instructions: 'Use the arrow keys to choose a date, Enter to select',
|
|
181
|
+
}"
|
|
182
|
+
/>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`invalid` renders a `role="status"` live region (class hook
|
|
186
|
+
`date-time-picker-status`) that announces when typed text is refused, and
|
|
187
|
+
is wired to the field via `aria-errormessage` and `aria-describedby`.
|
|
188
|
+
Without it, `aria-invalid` flips silently. `instructions` renders keyboard
|
|
189
|
+
help inside the dialog (class hook `date-time-picker-instructions`) that
|
|
190
|
+
the dialog references via `aria-describedby`, so a screen reader speaks it
|
|
191
|
+
once on open — hide it visually with your own CSS if you prefer.
|
|
192
|
+
|
|
193
|
+
### Replace the glyph
|
|
194
|
+
|
|
195
|
+
```html
|
|
196
|
+
<lily-date-time-picker [label]="label" [labels]="labels">
|
|
197
|
+
<ng-template lilyDateTimePickerIcon let-args>
|
|
198
|
+
<my-calendar-icon [expanded]="args.open" />
|
|
199
|
+
<span class="visually-hidden">{{ args.display }}</span>
|
|
200
|
+
</ng-template>
|
|
201
|
+
</lily-date-time-picker>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The projected template replaces the glyph inside the button, not the
|
|
205
|
+
dialog.
|
|
206
|
+
|
|
207
|
+
## Keyboard
|
|
208
|
+
|
|
209
|
+
**Field**: `Enter` resolves typed text. `Alt` + `↓` opens the dialog — the
|
|
210
|
+
same shortcut the native `<input type="date">` uses. `Escape` discards a
|
|
211
|
+
pending edit.
|
|
212
|
+
|
|
213
|
+
**Grid**: `←` `→` move a day; `↑` `↓` move a week; `Home` / `End` jump to
|
|
214
|
+
the ends of the week (respecting the locale's first weekday); `Page Up` /
|
|
215
|
+
`Page Down` page the month; add `Shift` to page the year; `Enter` / `Space`
|
|
216
|
+
select.
|
|
217
|
+
|
|
218
|
+
**Anywhere in the dialog**: `Escape` closes without committing; `Tab` and
|
|
219
|
+
`Shift+Tab` cycle inside the dialog. Closing returns focus to whichever
|
|
220
|
+
element opened the dialog — the button, or the field after `Alt` + `↓`.
|
|
221
|
+
|
|
222
|
+
## You must supply the CSS
|
|
223
|
+
|
|
224
|
+
The package is headless. Nothing positions the dialog for you — without
|
|
225
|
+
your CSS it renders in normal flow rather than as an overlay:
|
|
226
|
+
|
|
227
|
+
```css
|
|
228
|
+
.date-time-picker {
|
|
229
|
+
position: relative;
|
|
230
|
+
}
|
|
231
|
+
.date-time-picker-dialog {
|
|
232
|
+
position: absolute;
|
|
233
|
+
z-index: 10;
|
|
234
|
+
inset-inline-start: 0;
|
|
235
|
+
}
|
|
236
|
+
.date-time-picker-dialog[hidden] {
|
|
237
|
+
display: none;
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Class hooks: `date-time-picker`, `-field`, `-input`, `-button`, `-icon`,
|
|
242
|
+
`-status`, `-dialog`, `-instructions`, `-header`, `-previous-year`,
|
|
243
|
+
`-previous-month`, `-previous-week`, `-previous-day`, `-period`,
|
|
244
|
+
`-next-day`, `-next-week`, `-next-month`, `-next-year`, `-time-zone`,
|
|
245
|
+
`-time-zone-label`, `-time-zone-select`, `-calendar`,
|
|
246
|
+
`-weekday`, `-week-heading`, `-week`, `-day`, `-time`, `-time-label`,
|
|
247
|
+
`-hour`, `-minute`, `-meridiem`, `-shortcuts`, `-shortcut`, `-footer`,
|
|
248
|
+
`-clear`, `-cancel`, `-confirm`.
|
|
249
|
+
|
|
250
|
+
Day cells carry `data-today`, `data-outside`, `data-selected`,
|
|
251
|
+
`data-disabled`, and the root carries `data-mode`, so variants need no
|
|
252
|
+
extra classes.
|
|
253
|
+
|
|
254
|
+
## Should you use this at all?
|
|
255
|
+
|
|
256
|
+
Often, no. `<input type="date">` is smaller, better supported by assistive
|
|
257
|
+
technology, and gets the platform's own picker for free. Reach for this one
|
|
258
|
+
when you need what the native control cannot do: `isDateDisabled`,
|
|
259
|
+
shortcuts, week numbers, a consistent look across browsers, or a locale
|
|
260
|
+
that differs from the user's OS setting.
|
|
261
|
+
|
|
262
|
+
For a date the user knows by heart — a date of birth — use three separate
|
|
263
|
+
number fields instead. That is the NHS and GOV.UK guidance and it is right:
|
|
264
|
+
nobody wants to page a calendar back forty years.
|
|
265
|
+
|
|
266
|
+
## Related
|
|
267
|
+
|
|
268
|
+
- [`@lilydesignsystem/angular-theme-picker`](../lily-design-system-angular-theme-picker/)
|
|
269
|
+
- [`@lilydesignsystem/angular-locale-picker`](../lily-design-system-angular-locale-picker/)
|
|
270
|
+
- [`@lilydesignsystem/angular-text-size-picker`](../lily-design-system-angular-text-size-picker/)
|
|
271
|
+
- [`@lilydesignsystem/angular-share-picker`](../lily-design-system-angular-share-picker/)
|
|
272
|
+
- [`@lilydesignsystem/svelte-date-time-picker`](../../lily-design-system-svelte-helpers/lily-design-system-svelte-date-time-picker/) — the canonical Svelte original.
|
|
273
|
+
|
|
274
|
+
## License
|
|
275
|
+
|
|
276
|
+
MIT or Apache-2.0 or GPL-2.0 or GPL-3.0 or BSD-3-Clause. Contact
|
|
277
|
+
joel@joelparkerhenderson.com for other terms.
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
Lily™ and Lily Design System™ are trademarks.
|