@0001-labs/design-system-1 0.3.0-alpha.23 → 0.3.0-alpha.24
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/DS1/0-face/translations/da.json +5 -0
- package/DS1/0-face/translations/de.json +5 -0
- package/DS1/0-face/translations/en.json +5 -0
- package/DS1/0-face/translations/es.json +5 -0
- package/DS1/0-face/translations/fi.json +5 -0
- package/DS1/0-face/translations/fr.json +5 -0
- package/DS1/0-face/translations/is.json +5 -0
- package/DS1/0-face/translations/it.json +5 -0
- package/DS1/0-face/translations/ja.json +5 -0
- package/DS1/0-face/translations/ko.json +5 -0
- package/DS1/0-face/translations/nb.json +5 -0
- package/DS1/0-face/translations/pt-BR.json +5 -0
- package/DS1/0-face/translations/pt.json +5 -0
- package/DS1/0-face/translations/sv.json +5 -0
- package/DS1/0-face/translations/zh.json +5 -0
- package/DS1/1-root/cjk.css +1 -1
- package/DS1/1-root/fonts.css +1 -1
- package/DS1/1-root/one.css +1 -1
- package/DS1/1-root/one.semantic.css +1 -1
- package/DS1/3-unit/ds-calendar.ts +230 -14
- package/DS1/3-unit/styles/ds-calendar.css +111 -6
- package/dist/0-face/translations/da.json +5 -0
- package/dist/0-face/translations/de.json +5 -0
- package/dist/0-face/translations/en.json +5 -0
- package/dist/0-face/translations/es.json +5 -0
- package/dist/0-face/translations/fi.json +5 -0
- package/dist/0-face/translations/fr.json +5 -0
- package/dist/0-face/translations/is.json +5 -0
- package/dist/0-face/translations/it.json +5 -0
- package/dist/0-face/translations/ja.json +5 -0
- package/dist/0-face/translations/ko.json +5 -0
- package/dist/0-face/translations/nb.json +5 -0
- package/dist/0-face/translations/pt-BR.json +5 -0
- package/dist/0-face/translations/pt.json +5 -0
- package/dist/0-face/translations/sv.json +5 -0
- package/dist/0-face/translations/zh.json +5 -0
- package/dist/3-unit/ds-calendar.d.ts +47 -2
- package/dist/3-unit/ds-calendar.d.ts.map +1 -1
- package/dist/3-unit/ds-calendar.js +225 -15
- package/dist/design-system-1.bundle.js +225 -15
- package/dist/design-system-1.bundle.js.map +1 -1
- package/dist/design-system-1.bundle.min.js +1183 -1048
- package/dist/design-system-1.bundle.min.js.map +1 -1
- package/dist/{shared-words-DAVSET4Z.js → shared-words-BDyeT1zO.js} +89 -14
- package/dist/shared-words-BDyeT1zO.js.map +1 -0
- package/dist/{shared-words-CyZYc_De.js → shared-words-LuszeoCp.js} +76 -1
- package/dist/shared-words-LuszeoCp.js.map +1 -0
- package/package.json +1 -1
- package/dist/shared-words-CyZYc_De.js.map +0 -1
- package/dist/shared-words-DAVSET4Z.js.map +0 -1
|
@@ -111,6 +111,11 @@
|
|
|
111
111
|
"key.pagedown": "Page Down",
|
|
112
112
|
"Previous month": "Forrige måned",
|
|
113
113
|
"Next month": "Næste måned",
|
|
114
|
+
"Previous year": "Forrige år",
|
|
115
|
+
"Next year": "Næste år",
|
|
116
|
+
"Earlier years": "Tidligere år",
|
|
117
|
+
"Later years": "Senere år",
|
|
118
|
+
"Choose a month and year": "Vælg måned og år",
|
|
114
119
|
"Choose a date": "Vælg en dato",
|
|
115
120
|
"Date": "Dato",
|
|
116
121
|
"W{week}": "U{week}",
|
|
@@ -111,6 +111,11 @@
|
|
|
111
111
|
"key.pagedown": "Bild ab",
|
|
112
112
|
"Previous month": "Vorheriger Monat",
|
|
113
113
|
"Next month": "Nächster Monat",
|
|
114
|
+
"Previous year": "Vorheriges Jahr",
|
|
115
|
+
"Next year": "Nächstes Jahr",
|
|
116
|
+
"Earlier years": "Frühere Jahre",
|
|
117
|
+
"Later years": "Spätere Jahre",
|
|
118
|
+
"Choose a month and year": "Monat und Jahr wählen",
|
|
114
119
|
"Choose a date": "Datum wählen",
|
|
115
120
|
"Date": "Datum",
|
|
116
121
|
"W{week}": "KW{week}",
|
|
@@ -111,6 +111,11 @@
|
|
|
111
111
|
"key.pagedown": "PgDn",
|
|
112
112
|
"Previous month": "Previous month",
|
|
113
113
|
"Next month": "Next month",
|
|
114
|
+
"Previous year": "Previous year",
|
|
115
|
+
"Next year": "Next year",
|
|
116
|
+
"Earlier years": "Earlier years",
|
|
117
|
+
"Later years": "Later years",
|
|
118
|
+
"Choose a month and year": "Choose a month and year",
|
|
114
119
|
"Choose a date": "Choose a date",
|
|
115
120
|
"Date": "Date",
|
|
116
121
|
"W{week}": "W{week}",
|
|
@@ -111,6 +111,11 @@
|
|
|
111
111
|
"key.pagedown": "Av Pág",
|
|
112
112
|
"Previous month": "Mes anterior",
|
|
113
113
|
"Next month": "Mes siguiente",
|
|
114
|
+
"Previous year": "Año anterior",
|
|
115
|
+
"Next year": "Año siguiente",
|
|
116
|
+
"Earlier years": "Años anteriores",
|
|
117
|
+
"Later years": "Años siguientes",
|
|
118
|
+
"Choose a month and year": "Elegir mes y año",
|
|
114
119
|
"Choose a date": "Elegir una fecha",
|
|
115
120
|
"Date": "Fecha",
|
|
116
121
|
"W{week}": "S{week}",
|
|
@@ -111,6 +111,11 @@
|
|
|
111
111
|
"key.pagedown": "Page Down",
|
|
112
112
|
"Previous month": "Edellinen kuukausi",
|
|
113
113
|
"Next month": "Seuraava kuukausi",
|
|
114
|
+
"Previous year": "Edellinen vuosi",
|
|
115
|
+
"Next year": "Seuraava vuosi",
|
|
116
|
+
"Earlier years": "Aiemmat vuodet",
|
|
117
|
+
"Later years": "Myöhemmät vuodet",
|
|
118
|
+
"Choose a month and year": "Valitse kuukausi ja vuosi",
|
|
114
119
|
"Choose a date": "Valitse päivämäärä",
|
|
115
120
|
"Date": "Päivämäärä",
|
|
116
121
|
"W{week}": "Vk{week}",
|
|
@@ -111,6 +111,11 @@
|
|
|
111
111
|
"key.pagedown": "Page suiv.",
|
|
112
112
|
"Previous month": "Mois précédent",
|
|
113
113
|
"Next month": "Mois suivant",
|
|
114
|
+
"Previous year": "Année précédente",
|
|
115
|
+
"Next year": "Année suivante",
|
|
116
|
+
"Earlier years": "Années précédentes",
|
|
117
|
+
"Later years": "Années suivantes",
|
|
118
|
+
"Choose a month and year": "Choisir le mois et l’année",
|
|
114
119
|
"Choose a date": "Choisir une date",
|
|
115
120
|
"Date": "Date",
|
|
116
121
|
"W{week}": "S{week}",
|
|
@@ -104,6 +104,11 @@
|
|
|
104
104
|
"key.pagedown": "Page Down",
|
|
105
105
|
"Previous month": "Fyrri mánuður",
|
|
106
106
|
"Next month": "Næsti mánuður",
|
|
107
|
+
"Previous year": "Fyrra ár",
|
|
108
|
+
"Next year": "Næsta ár",
|
|
109
|
+
"Earlier years": "Fyrri ár",
|
|
110
|
+
"Later years": "Síðari ár",
|
|
111
|
+
"Choose a month and year": "Velja mánuð og ár",
|
|
107
112
|
"Choose a date": "Veldu dagsetningu",
|
|
108
113
|
"Date": "Dagsetning",
|
|
109
114
|
"W{week}": "V{week}",
|
|
@@ -111,6 +111,11 @@
|
|
|
111
111
|
"key.pagedown": "Pag giù",
|
|
112
112
|
"Previous month": "Mese precedente",
|
|
113
113
|
"Next month": "Mese successivo",
|
|
114
|
+
"Previous year": "Anno precedente",
|
|
115
|
+
"Next year": "Anno successivo",
|
|
116
|
+
"Earlier years": "Anni precedenti",
|
|
117
|
+
"Later years": "Anni successivi",
|
|
118
|
+
"Choose a month and year": "Scegli mese e anno",
|
|
114
119
|
"Choose a date": "Scegli una data",
|
|
115
120
|
"Date": "Data",
|
|
116
121
|
"W{week}": "S{week}",
|
|
@@ -111,6 +111,11 @@
|
|
|
111
111
|
"key.pagedown": "Page Down",
|
|
112
112
|
"Previous month": "前の月",
|
|
113
113
|
"Next month": "次の月",
|
|
114
|
+
"Previous year": "前の年",
|
|
115
|
+
"Next year": "次の年",
|
|
116
|
+
"Earlier years": "前の12年",
|
|
117
|
+
"Later years": "次の12年",
|
|
118
|
+
"Choose a month and year": "年と月を選択",
|
|
114
119
|
"Choose a date": "日付を選択",
|
|
115
120
|
"Date": "日付",
|
|
116
121
|
"W{week}": "第{week}週",
|
|
@@ -111,6 +111,11 @@
|
|
|
111
111
|
"key.pagedown": "Page Down",
|
|
112
112
|
"Previous month": "이전 달",
|
|
113
113
|
"Next month": "다음 달",
|
|
114
|
+
"Previous year": "이전 연도",
|
|
115
|
+
"Next year": "다음 연도",
|
|
116
|
+
"Earlier years": "이전 연도들",
|
|
117
|
+
"Later years": "다음 연도들",
|
|
118
|
+
"Choose a month and year": "연도와 월 선택",
|
|
114
119
|
"Choose a date": "날짜 선택",
|
|
115
120
|
"Date": "날짜",
|
|
116
121
|
"W{week}": "{week}주",
|
|
@@ -111,6 +111,11 @@
|
|
|
111
111
|
"key.pagedown": "Page Down",
|
|
112
112
|
"Previous month": "Forrige måned",
|
|
113
113
|
"Next month": "Neste måned",
|
|
114
|
+
"Previous year": "Forrige år",
|
|
115
|
+
"Next year": "Neste år",
|
|
116
|
+
"Earlier years": "Tidligere år",
|
|
117
|
+
"Later years": "Senere år",
|
|
118
|
+
"Choose a month and year": "Velg måned og år",
|
|
114
119
|
"Choose a date": "Velg en dato",
|
|
115
120
|
"Date": "Dato",
|
|
116
121
|
"W{week}": "U{week}",
|
|
@@ -111,6 +111,11 @@
|
|
|
111
111
|
"key.pagedown": "Page Down",
|
|
112
112
|
"Previous month": "Mês anterior",
|
|
113
113
|
"Next month": "Próximo mês",
|
|
114
|
+
"Previous year": "Ano anterior",
|
|
115
|
+
"Next year": "Próximo ano",
|
|
116
|
+
"Earlier years": "Anos anteriores",
|
|
117
|
+
"Later years": "Anos seguintes",
|
|
118
|
+
"Choose a month and year": "Escolher mês e ano",
|
|
114
119
|
"Choose a date": "Escolher uma data",
|
|
115
120
|
"Date": "Data",
|
|
116
121
|
"W{week}": "S{week}",
|
|
@@ -111,6 +111,11 @@
|
|
|
111
111
|
"key.pagedown": "Page Down",
|
|
112
112
|
"Previous month": "Mês anterior",
|
|
113
113
|
"Next month": "Mês seguinte",
|
|
114
|
+
"Previous year": "Ano anterior",
|
|
115
|
+
"Next year": "Ano seguinte",
|
|
116
|
+
"Earlier years": "Anos anteriores",
|
|
117
|
+
"Later years": "Anos seguintes",
|
|
118
|
+
"Choose a month and year": "Escolher mês e ano",
|
|
114
119
|
"Choose a date": "Escolher uma data",
|
|
115
120
|
"Date": "Data",
|
|
116
121
|
"W{week}": "S{week}",
|
|
@@ -111,6 +111,11 @@
|
|
|
111
111
|
"key.pagedown": "Page Down",
|
|
112
112
|
"Previous month": "Föregående månad",
|
|
113
113
|
"Next month": "Nästa månad",
|
|
114
|
+
"Previous year": "Föregående år",
|
|
115
|
+
"Next year": "Nästa år",
|
|
116
|
+
"Earlier years": "Tidigare år",
|
|
117
|
+
"Later years": "Senare år",
|
|
118
|
+
"Choose a month and year": "Välj månad och år",
|
|
114
119
|
"Choose a date": "Välj ett datum",
|
|
115
120
|
"Date": "Datum",
|
|
116
121
|
"W{week}": "V{week}",
|
|
@@ -111,6 +111,11 @@
|
|
|
111
111
|
"key.pagedown": "Page Down",
|
|
112
112
|
"Previous month": "上个月",
|
|
113
113
|
"Next month": "下个月",
|
|
114
|
+
"Previous year": "上一年",
|
|
115
|
+
"Next year": "下一年",
|
|
116
|
+
"Earlier years": "更早的年份",
|
|
117
|
+
"Later years": "更晚的年份",
|
|
118
|
+
"Choose a month and year": "选择月份和年份",
|
|
114
119
|
"Choose a date": "选择日期",
|
|
115
120
|
"Date": "日期",
|
|
116
121
|
"W{week}": "第{week}周",
|
package/DS1/1-root/cjk.css
CHANGED
package/DS1/1-root/fonts.css
CHANGED
package/DS1/1-root/one.css
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
heatLevels,
|
|
25
25
|
isDay,
|
|
26
26
|
isoWeek,
|
|
27
|
+
monthName,
|
|
27
28
|
monthTitle,
|
|
28
29
|
monthWeeks,
|
|
29
30
|
sameMonth,
|
|
@@ -114,6 +115,8 @@ const openPickers = new Set<Calendar>();
|
|
|
114
115
|
* for a scale that stays put from month to month; the busiest day shown
|
|
115
116
|
* by default.
|
|
116
117
|
* @prop {boolean} noHeader - Leave out the title and arrows (`no-header`).
|
|
118
|
+
* With a header, pressing the title travels by months and years: the
|
|
119
|
+
* twelve months of the year, then twelve years, and back down.
|
|
117
120
|
* @prop {boolean} noToday - Leave out the Today button (`no-today`).
|
|
118
121
|
* @prop {string} min - The first day a person may choose.
|
|
119
122
|
* @prop {string} max - The last day a person may choose.
|
|
@@ -128,7 +131,7 @@ const openPickers = new Set<Calendar>();
|
|
|
128
131
|
* @prop {string} length - How a picker writes a day: `short`, `medium` (the
|
|
129
132
|
* default) or `long`.
|
|
130
133
|
* @prop {boolean} time - A picker chooses a time with each day (Include time).
|
|
131
|
-
* @prop {boolean} required - A form needs a value;
|
|
134
|
+
* @prop {boolean} required - A form needs a value; Clear is left out.
|
|
132
135
|
* @prop {boolean} disabled - A picker cannot be opened.
|
|
133
136
|
* @prop {boolean} open - A picker's month is open.
|
|
134
137
|
* @prop {CalendarEvent[]} events - What happens on the days (property only).
|
|
@@ -142,6 +145,9 @@ const openPickers = new Set<Calendar>();
|
|
|
142
145
|
* @fires navigate - A person moved to another month; `{ month }`.
|
|
143
146
|
* @fires ds-calendar-toggle - A picker's month opened or closed; `{ open }`.
|
|
144
147
|
*
|
|
148
|
+
* A selectable calendar has Clear one square below its month, and `clear()`
|
|
149
|
+
* empties the value from code; both fire `change` with an empty value.
|
|
150
|
+
*
|
|
145
151
|
* @example
|
|
146
152
|
* <ds-calendar month="2026-10" week-numbers></ds-calendar>
|
|
147
153
|
* <ds-calendar compact selectable value="2026-10-18/2026-10-24"></ds-calendar>
|
|
@@ -172,6 +178,10 @@ export class Calendar extends CalendarBase {
|
|
|
172
178
|
disabled: { type: Boolean, reflect: true },
|
|
173
179
|
open: { type: Boolean, reflect: true },
|
|
174
180
|
unfolded: { state: true },
|
|
181
|
+
embedded: { attribute: false },
|
|
182
|
+
level: { state: true },
|
|
183
|
+
browseYear: { state: true },
|
|
184
|
+
pickFocus: { state: true },
|
|
175
185
|
};
|
|
176
186
|
|
|
177
187
|
static styles = [unsafeCSS(metrics), unsafeCSS(controls), unsafeCSS(styles)];
|
|
@@ -197,6 +207,14 @@ export class Calendar extends CalendarBase {
|
|
|
197
207
|
declare open: boolean;
|
|
198
208
|
/** The day whose hidden events are unfolded. */
|
|
199
209
|
declare unfolded: Day | undefined;
|
|
210
|
+
/** The small month inside a picker, whose Clear is the picker's own. */
|
|
211
|
+
declare embedded: boolean;
|
|
212
|
+
/** What the grid shows: the month's days, the twelve months of a year, or twelve years. */
|
|
213
|
+
declare level: "days" | "months" | "years";
|
|
214
|
+
/** The year the months and years are drawn around. */
|
|
215
|
+
declare browseYear: number;
|
|
216
|
+
/** The month (0–11) or year holding the Tab stop among the months or years. */
|
|
217
|
+
declare pickFocus: number | undefined;
|
|
200
218
|
|
|
201
219
|
protected readonly weeksRun = "rows" as const;
|
|
202
220
|
|
|
@@ -223,6 +241,9 @@ export class Calendar extends CalendarBase {
|
|
|
223
241
|
this.required = false;
|
|
224
242
|
this.disabled = false;
|
|
225
243
|
this.open = false;
|
|
244
|
+
this.embedded = false;
|
|
245
|
+
this.level = "days";
|
|
246
|
+
this.browseYear = 0;
|
|
226
247
|
}
|
|
227
248
|
|
|
228
249
|
disconnectedCallback() {
|
|
@@ -310,10 +331,184 @@ export class Calendar extends CalendarBase {
|
|
|
310
331
|
|
|
311
332
|
/** Today's month, as the Today button does. */
|
|
312
333
|
showToday() {
|
|
334
|
+
this.level = "days";
|
|
313
335
|
this.showMonth(this.todayDay, true);
|
|
314
336
|
this.focusDay = this.todayDay;
|
|
315
337
|
}
|
|
316
338
|
|
|
339
|
+
/** Empties the value, as Clear does, and says so with `change`. */
|
|
340
|
+
clear() {
|
|
341
|
+
if (this.picker) {
|
|
342
|
+
this.commit("");
|
|
343
|
+
this.open = false;
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const previous = this.value || "";
|
|
347
|
+
this.endPending = false;
|
|
348
|
+
this.hoverDay = undefined;
|
|
349
|
+
if (!previous) return;
|
|
350
|
+
this.value = "";
|
|
351
|
+
this.dispatchEvent(new CustomEvent<CalendarChangeDetail>("change", { bubbles: true, composed: true, detail: { value: "", previous, start: "", end: "" } }));
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Travelling by months and years: the title goes up a level, a choice comes back down.
|
|
355
|
+
|
|
356
|
+
/** A person has moved between levels, so a level's grid fades in when it comes. */
|
|
357
|
+
private travelled = false;
|
|
358
|
+
|
|
359
|
+
/** The twelve years drawn around `browseYear`, as their first and last. */
|
|
360
|
+
private get yearSpan(): [number, number] {
|
|
361
|
+
const first = Math.floor(this.browseYear / 12) * 12;
|
|
362
|
+
return [first, first + 11];
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
private yearName(year: number) {
|
|
366
|
+
return dateFormatter({ year: "numeric", timeZone: "UTC" }).format(Date.UTC(year, 6, 1));
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/** The title: the days go up to the months of their year, the months to twelve years. */
|
|
370
|
+
private levelUp = () => {
|
|
371
|
+
this.travelled = true;
|
|
372
|
+
if (this.level === "days") {
|
|
373
|
+
this.browseYear = Number(this.shownMonth.slice(0, 4));
|
|
374
|
+
this.pickFocus = Number(this.shownMonth.slice(5, 7)) - 1;
|
|
375
|
+
this.level = "months";
|
|
376
|
+
} else if (this.level === "months") {
|
|
377
|
+
this.pickFocus = this.browseYear;
|
|
378
|
+
this.level = "years";
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
/** Back down a level: from twelve years to the months, from the months to the days. */
|
|
383
|
+
private levelDown(focus = false) {
|
|
384
|
+
this.travelled = true;
|
|
385
|
+
if (this.level === "years") {
|
|
386
|
+
this.pickFocus = Number(this.shownMonth.slice(5, 7)) - 1;
|
|
387
|
+
this.level = "months";
|
|
388
|
+
if (focus) void this.focusPick();
|
|
389
|
+
} else if (this.level === "months") {
|
|
390
|
+
this.level = "days";
|
|
391
|
+
if (focus) void this.focusCell(this.tabDay);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/** The arrows: a month among the days, a year among the months, twelve years among the years. */
|
|
396
|
+
private step(direction: -1 | 1) {
|
|
397
|
+
if (this.level === "days") return direction < 0 ? this.previousMonth() : this.nextMonth();
|
|
398
|
+
this.browseYear += direction * (this.level === "months" ? 1 : 12);
|
|
399
|
+
if (this.level === "years") this.pickFocus = (this.pickFocus ?? this.browseYear) + direction * 12;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/** A month or a year chosen: a year shows its months, a month its days. */
|
|
403
|
+
private choose(value: number) {
|
|
404
|
+
this.travelled = true;
|
|
405
|
+
if (this.level === "years") {
|
|
406
|
+
this.browseYear = value;
|
|
407
|
+
this.pickFocus = Number(this.shownMonth.slice(5, 7)) - 1;
|
|
408
|
+
this.level = "months";
|
|
409
|
+
void this.focusPick();
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
const month = `${String(this.browseYear).padStart(4, "0")}-${String(value + 1).padStart(2, "0")}-01`;
|
|
413
|
+
this.level = "days";
|
|
414
|
+
this.showMonth(month, true);
|
|
415
|
+
const day = [this.focusDay, this.chosen.start, this.todayDay].find(day => day && sameMonth(day, month)) ?? month;
|
|
416
|
+
void this.focusCell(day);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
private async focusPick() {
|
|
420
|
+
await this.updateComplete;
|
|
421
|
+
this.renderRoot.querySelector<HTMLElement>('.pick[tabindex="0"]')?.focus({ preventScroll: true });
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
private onPickKey = (event: KeyboardEvent) => {
|
|
425
|
+
const cell = (event.target as HTMLElement).closest<HTMLElement>("[data-pick]");
|
|
426
|
+
if (!cell) return;
|
|
427
|
+
const value = Number(cell.dataset.pick);
|
|
428
|
+
const columns = this.pickColumns;
|
|
429
|
+
const rtl = getComputedStyle(this).direction === "rtl";
|
|
430
|
+
const moves: Record<string, number> = { ArrowRight: rtl ? -1 : 1, ArrowLeft: rtl ? 1 : -1, ArrowDown: columns, ArrowUp: -columns };
|
|
431
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
432
|
+
event.preventDefault();
|
|
433
|
+
this.choose(value);
|
|
434
|
+
} else if (event.key === "Escape") {
|
|
435
|
+
event.preventDefault();
|
|
436
|
+
event.stopPropagation();
|
|
437
|
+
this.levelDown(true);
|
|
438
|
+
} else if (event.key in moves) {
|
|
439
|
+
event.preventDefault();
|
|
440
|
+
let next = value + moves[event.key];
|
|
441
|
+
if (this.level === "months") {
|
|
442
|
+
// Past December is the next year's January.
|
|
443
|
+
if (next < 0 || next > 11) { this.browseYear += next < 0 ? -1 : 1; next = (next + 12) % 12; }
|
|
444
|
+
} else {
|
|
445
|
+
const [first, last] = this.yearSpan;
|
|
446
|
+
if (next < first || next > last) this.browseYear = next;
|
|
447
|
+
}
|
|
448
|
+
this.pickFocus = next;
|
|
449
|
+
void this.focusPick();
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
/** Months and years stand in rows of one square, one square apart: three across a narrow month, four across a wider one. */
|
|
454
|
+
private get pickColumns() {
|
|
455
|
+
return 7 * this.squaresPerDay >= 12 ? 4 : 3;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
private renderPicks(weeks: number) {
|
|
459
|
+
const level = this.level;
|
|
460
|
+
const year = this.browseYear;
|
|
461
|
+
const today = this.todayDay;
|
|
462
|
+
const chosen = this.chosen.start;
|
|
463
|
+
const columns = this.pickColumns;
|
|
464
|
+
const cell = Math.floor((7 * this.squaresPerDay) / columns);
|
|
465
|
+
const values = level === "months" ? Array.from({ length: 12 }, (_, month) => month) : Array.from({ length: 12 }, (_, index) => this.yearSpan[0] + index);
|
|
466
|
+
const focus = this.pickFocus !== undefined && values.includes(this.pickFocus)
|
|
467
|
+
? this.pickFocus
|
|
468
|
+
: level === "months" ? (chosen && Number(chosen.slice(0, 4)) === year ? Number(chosen.slice(5, 7)) - 1 : 0) : year;
|
|
469
|
+
const rows = Array.from({ length: Math.ceil(values.length / columns) }, (_, row) => values.slice(row * columns, row * columns + columns));
|
|
470
|
+
const long = cell >= 4;
|
|
471
|
+
const name = (value: number) => level === "months" ? monthName(`${String(year).padStart(4, "0")}-${String(value + 1).padStart(2, "0")}-01`, long ? "long" : "short") : this.yearName(value);
|
|
472
|
+
const isToday = (value: number) => level === "months" ? today.slice(0, 7) === `${String(year).padStart(4, "0")}-${String(value + 1).padStart(2, "0")}` : Number(today.slice(0, 4)) === value;
|
|
473
|
+
const isChosen = (value: number) => Boolean(chosen) && (level === "months" ? chosen.slice(0, 7) === `${String(year).padStart(4, "0")}-${String(value + 1).padStart(2, "0")}` : Number(chosen.slice(0, 4)) === value);
|
|
474
|
+
const allowed = (value: number) => {
|
|
475
|
+
const min = this.minDay, max = this.maxDay;
|
|
476
|
+
if (level === "years") return !(min && value < Number(min.slice(0, 4))) && !(max && value > Number(max.slice(0, 4)));
|
|
477
|
+
const month = `${String(year).padStart(4, "0")}-${String(value + 1).padStart(2, "0")}`;
|
|
478
|
+
return !(min && month < min.slice(0, 7)) && !(max && month > max.slice(0, 7));
|
|
479
|
+
};
|
|
480
|
+
return html`<div
|
|
481
|
+
class="picks"
|
|
482
|
+
part="picks"
|
|
483
|
+
role="grid"
|
|
484
|
+
data-level=${level}
|
|
485
|
+
?data-travel=${this.travelled}
|
|
486
|
+
aria-label=${level === "months" ? this.yearName(year) : `${this.yearName(this.yearSpan[0])} – ${this.yearName(this.yearSpan[1])}`}
|
|
487
|
+
style=${`--ds-calendar-pick-columns: ${columns}; --ds-calendar-pick-cell: ${cell}; --ds-calendar-weeks: ${weeks}`}
|
|
488
|
+
@keydown=${this.onPickKey}
|
|
489
|
+
>${rows.map(row => html`<div role="row" class="pick-row">${row.map(value => html`<button
|
|
490
|
+
type="button"
|
|
491
|
+
role="gridcell"
|
|
492
|
+
class="pick"
|
|
493
|
+
part=${["pick", isChosen(value) ? "selected" : "", isToday(value) ? "today" : ""].filter(Boolean).join(" ")}
|
|
494
|
+
data-pick=${value}
|
|
495
|
+
tabindex=${value === focus ? 0 : -1}
|
|
496
|
+
aria-selected=${String(isChosen(value))}
|
|
497
|
+
aria-current=${isToday(value) ? "date" : nothing}
|
|
498
|
+
?disabled=${!allowed(value)}
|
|
499
|
+
?data-selected=${isChosen(value)}
|
|
500
|
+
?data-today=${isToday(value)}
|
|
501
|
+
@click=${() => this.choose(value)}
|
|
502
|
+
><span class="pick-mark">${name(value)}</span></button>`)}</div>`)}</div>`;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
private renderClear() {
|
|
506
|
+
if (!this.selectable || this.embedded || this.required) return nothing;
|
|
507
|
+
return html`<div class="foot" part="foot">
|
|
508
|
+
<button class="ds-button ds-button--secondary clear-value" part="clear" type="button" ?disabled=${!this.value} @click=${() => this.clear()}>${this.words("Clear")}</button>
|
|
509
|
+
</div>`;
|
|
510
|
+
}
|
|
511
|
+
|
|
317
512
|
/** The day holding the Tab stop: the one moved to, the selected day, today, or the first. */
|
|
318
513
|
private get tabDay(): Day {
|
|
319
514
|
const month = this.shownMonth;
|
|
@@ -383,17 +578,38 @@ export class Calendar extends CalendarBase {
|
|
|
383
578
|
const min = this.minDay, max = this.maxDay;
|
|
384
579
|
const before = Boolean(min && addMonths(month, -1).slice(0, 7) < min.slice(0, 7));
|
|
385
580
|
const after = Boolean(max && addMonths(month, 1).slice(0, 7) > max.slice(0, 7));
|
|
581
|
+
const level = this.level;
|
|
582
|
+
const year = this.browseYear;
|
|
583
|
+
const span = this.yearSpan;
|
|
584
|
+
const labels = { days: ["Previous month", "Next month"], months: ["Previous year", "Next year"], years: ["Earlier years", "Later years"] }[level];
|
|
585
|
+
const blocked = level === "days"
|
|
586
|
+
? [before, after]
|
|
587
|
+
: level === "months"
|
|
588
|
+
? [Boolean(min && year - 1 < Number(min.slice(0, 4))), Boolean(max && year + 1 > Number(max.slice(0, 4)))]
|
|
589
|
+
: [Boolean(min && span[0] - 1 < Number(min.slice(0, 4))), Boolean(max && span[0] + 12 > Number(max.slice(0, 4)))];
|
|
386
590
|
const arrow = (which: "previous" | "next") => html`<button
|
|
387
591
|
class="ds-button ds-button--icon nav"
|
|
388
592
|
part=${which}
|
|
389
593
|
type="button"
|
|
390
|
-
aria-label=${this.words(which === "previous" ?
|
|
391
|
-
?disabled=${which === "previous" ?
|
|
392
|
-
@click=${() => (which === "previous" ?
|
|
594
|
+
aria-label=${this.words(labels[which === "previous" ? 0 : 1])}
|
|
595
|
+
?disabled=${blocked[which === "previous" ? 0 : 1]}
|
|
596
|
+
@click=${() => this.step(which === "previous" ? -1 : 1)}
|
|
393
597
|
><ds-icon type=${which === "previous" ? "chevron-left" : "chevron-right"} size="large" aria-hidden="true"></ds-icon></button>`;
|
|
394
|
-
const title =
|
|
598
|
+
const title = level === "days"
|
|
599
|
+
? monthTitle(month, this.compact ? "short" : "long")
|
|
600
|
+
: level === "months"
|
|
601
|
+
? this.yearName(year)
|
|
602
|
+
: `${this.yearName(span[0])} – ${this.yearName(span[0] + 11)}`;
|
|
395
603
|
return html`<div class="header" part="header">
|
|
396
|
-
|
|
604
|
+
${level === "years"
|
|
605
|
+
? html`<span class="title" id="title" aria-live="polite">${title}</span>`
|
|
606
|
+
: html`<button
|
|
607
|
+
class="title title-button"
|
|
608
|
+
part="title"
|
|
609
|
+
type="button"
|
|
610
|
+
aria-label=${`${title}, ${this.words("Choose a month and year")}`}
|
|
611
|
+
@click=${this.levelUp}
|
|
612
|
+
><span class="title-text" id="title" aria-live="polite">${title}</span><ds-icon type="chevron-down" size="large" aria-hidden="true"></ds-icon></button>`}
|
|
397
613
|
<span class="controls">
|
|
398
614
|
${this.noToday || this.squaresPerDay < 2 ? nothing : html`<button class="ds-button today-button" part="today" type="button" @click=${() => this.showToday()}>${this.words("Today")}</button>`}
|
|
399
615
|
${arrow("previous")}
|
|
@@ -471,10 +687,11 @@ export class Calendar extends CalendarBase {
|
|
|
471
687
|
const long = weekdayNames(first, "long");
|
|
472
688
|
return html`<div class="calendar" part="calendar" @focusout=${this.onFocusOut} @pointerover=${this.onPointerOver} @pointerleave=${() => (this.hoverDay = undefined)}>
|
|
473
689
|
${this.renderHeader()}
|
|
474
|
-
|
|
690
|
+
${this.level !== "days" && !this.noHeader ? this.renderPicks(weeks.length) : html`<div
|
|
475
691
|
class="grid"
|
|
476
692
|
part="grid"
|
|
477
693
|
role="grid"
|
|
694
|
+
?data-travel=${this.travelled}
|
|
478
695
|
aria-label=${this.nameOr(monthTitle(month))}
|
|
479
696
|
aria-multiselectable=${this.selectable ? "true" : nothing}
|
|
480
697
|
@keydown=${this.onKeyDown}
|
|
@@ -484,7 +701,8 @@ export class Calendar extends CalendarBase {
|
|
|
484
701
|
${short.map((name, index) => html`<span role="columnheader" class="weekday" aria-label=${long[index]}>${name}</span>`)}
|
|
485
702
|
</div>
|
|
486
703
|
${weeks.map(week => html`<div role="row" class="week" part="week">${week.map((day, column) => this.renderDay(day, column))}</div>`)}
|
|
487
|
-
</div
|
|
704
|
+
</div>`}
|
|
705
|
+
${this.renderClear()}
|
|
488
706
|
</div>`;
|
|
489
707
|
}
|
|
490
708
|
|
|
@@ -524,8 +742,9 @@ export class Calendar extends CalendarBase {
|
|
|
524
742
|
const month = this.smallMonth;
|
|
525
743
|
if (month) {
|
|
526
744
|
month.month = (this.ends.start?.day || this.today || this.todayDay).slice(0, 7);
|
|
527
|
-
// Each opening starts a new pick: the first press is a first day.
|
|
745
|
+
// Each opening starts a new pick on the month's days: the first press is a first day.
|
|
528
746
|
month.endPending = false;
|
|
747
|
+
month.level = "days";
|
|
529
748
|
}
|
|
530
749
|
panel.showPopover?.();
|
|
531
750
|
this.place();
|
|
@@ -689,10 +908,6 @@ export class Calendar extends CalendarBase {
|
|
|
689
908
|
if (control && !event.composedPath().includes(control)) control.click();
|
|
690
909
|
};
|
|
691
910
|
|
|
692
|
-
private clear = () => {
|
|
693
|
-
this.commit("");
|
|
694
|
-
this.open = false;
|
|
695
|
-
};
|
|
696
911
|
|
|
697
912
|
private moment(side: CalendarEnd) {
|
|
698
913
|
const [year, month, date] = side.day.split("-").map(Number);
|
|
@@ -785,6 +1000,7 @@ export class Calendar extends CalendarBase {
|
|
|
785
1000
|
selectable
|
|
786
1001
|
fixed
|
|
787
1002
|
outside-days
|
|
1003
|
+
.embedded=${true}
|
|
788
1004
|
.value=${days}
|
|
789
1005
|
.min=${this.min}
|
|
790
1006
|
.max=${this.max}
|
|
@@ -801,7 +1017,7 @@ export class Calendar extends CalendarBase {
|
|
|
801
1017
|
${this.required
|
|
802
1018
|
? nothing
|
|
803
1019
|
: html`<div class="separator" aria-hidden="true"></div>
|
|
804
|
-
<button class="option clear" part="clear" type="button" ?disabled=${!start} @click=${this.clear}>${this.pickerWords(undefined, "Clear")}</button>`}
|
|
1020
|
+
<button class="option clear" part="clear" type="button" ?disabled=${!start} @click=${() => this.clear()}>${this.pickerWords(undefined, "Clear")}</button>`}
|
|
805
1021
|
</div>
|
|
806
1022
|
</div>`;
|
|
807
1023
|
}
|