@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.
- package/README.md +30 -5
- package/custom-elements.json +44 -0
- package/dist/date-picker.css +114 -18
- package/dist/date-picker.js +176 -19
- package/dist/date-picker.min.css +1 -1
- package/dist/date-picker.min.js +13 -13
- package/dist/date-picker.standalone.min.js +128 -32
- package/dist/types/calendar-model.d.ts.map +1 -1
- 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/date.d.ts +6 -0
- package/dist/types/date.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 +52 -2
- package/docs/CALENDAR-INTEGRATION.md +12 -6
- 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/calendar-model.js +2 -1
- package/src/date-calendar.js +44 -8
- package/src/date-picker.css +114 -18
- package/src/date-picker.js +108 -5
- package/src/date.js +13 -3
- package/src/index.js +1 -0
- package/src/intl.js +38 -2
- 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":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAkB,MAAM,iBAAiB,CAAC;AAOtE,qBAAa,iBAAkB,SAAQ,WAAW;IAKzC,GAAG;IACH,UAAU;IACV,WAAW;IACX,MAAM;IACN,MAAM;IACX,yCAAyC;IACpC,MAAM,EADA,mBAAmB,GAAG,IAAI;IAErC,2CAA2C;IACtC,OAAO,EADD,mBAAmB,EAAE,GAAG,IAAI;IAEvC,yCAAyC;IACpC,MAAM,EADA,mBAAmB,GAAG,IAAI;IAEhC,UAAU;IACf,uGAAuG;IAClG,WAAW,EADiC,CAAC,gBAAgB,GAAG,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAEnG,mFAAmF;IAC9E,eAAe,EADsC,GAAG,CAAC,gBAAgB,CAAC;IAE/E,mCAAmC;IAC9B,kBAAkB,EADZ,EAAE,GAAG,OAAO,GAAG,KAAK;IAE1B,cAAc;IACnB;sFACkF;IAC7E,eAAe,EADuC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAEzE,OAAO;IACP,MAAM;IACN,SAAS;IACT,oBAAoB;IACpB,yBAAyB;IACzB,WAAW;IACX,qBAAqB;IACrB,WAAW;IACX,aAAa;IACb,KAAK;IACL,kBAAkB;IAClB,SAAS;;;;;;;;;;;;;;;;;;;;IACd,kBAAkB;IACb,OAAO,EADD,GAAG;IAEd,kBAAkB;IACb,UAAU,EADJ,GAAG;IAEd,kBAAkB;IACb,UAAU,EADJ,GAAG;IAEd,kBAAkB;IACb,eAAe,EADT,GAAG;IA5ChB,MAAM,CAAC,kBAAkB,WAAsE;IAE/F,cA4CC;IAED,UAAU,YAET;IAED,iBAAiB,SAOhB;IAED,cAAc,SAqCb;IAED;;;;OAIG;IACH,mBAAmB,SAoBlB;IAED,aAAa,SAkDZ;IAED,oBAAoB,SAsBnB;IAED,gDAAgD;IAChD,cAAc,CAAC,KAAK,EADR,mBAAmB,GAAG,IACd,QAanB;IAED,uFAAuF;IACvF,wBAAwB,CAAC,IAAI,EADjB,MACiB,EAAE,QAAQ,EADN,MAAM,GAAC,IACD,EAAE,QAAQ,EADc,MAAM,GAAC,IACrB,QAYhD;IAED,cAAc;IACd,IAAI,KAAK,wCAER;IAED,cAAc;IACd,IAAI,QAAQ,+BAEX;IAED,cAAc;IACd,IAAI,KAAK,uBAER;IAED,IAAI,KAAK,CAAC,KAAK,oBAAA,EAMd;IAED,cAAc;IACd,IAAI,KAAK;;;kBAER;IAED,IAAI,KAAK,CAAC,KAAK;;;iBAAA,EAId;IAED,cAAc;IACd,IAAI,MAAM,WAET;IAED,IAAI,MAAM,CAAC,KAAK,QAAA,EAGf;IAED,+HAA+H;IAC/H,IAAI,WAAW,qBAEd;IAED,IAAI,WAAW,CAAC,KAAK,QAAA,EAGpB;IAED,cAAc;IACd,IAAI,GAAG,WAGN;IAED,IAAI,GAAG,CAAC,KAAK,QAAA,EAGZ;IAED,cAAc;IACd,IAAI,GAAG,WAGN;IAED,IAAI,GAAG,CAAC,KAAK,QAAA,EAGZ;IAED,cAAc;IACd,IAAI,WAAW,YAEd;IAED,IAAI,WAAW,CAAC,KAAK,SAAA,EAGpB;IAED,cAAc;IACd,IAAI,IAAI,YAEP;IAED,cAAc;IACd,IAAI,QAAQ;;;;;;;;;;;;;;;;;;;MAEX;IAED,IAAI,QAAQ,CAAC,KAAK;;;;;;;;;;;;;;;;;;;KAAA,EAOjB;IAED,6BAA6B;IAC7B,IAAI,MAAM,IADY,GAAG,CAGxB;IAED,IAAI,MAAM,CAAC,KAAK,EALM,GAKN,EAIf;IAED,6BAA6B;IAC7B,IAAI,SAAS,IADS,GAAG,CAGxB;IAED,IAAI,SAAS,CAAC,KAAK,EALG,GAKH,EAIlB;IAED,6BAA6B;IAC7B,IAAI,SAAS,IADS,GAAG,CAGxB;IAED,IAAI,SAAS,CAAC,KAAK,EALG,GAKH,EAGlB;IAED,6BAA6B;IAC7B,IAAI,cAAc,IADI,GAAG,CAGxB;IAED,IAAI,cAAc,CAAC,KAAK,EALF,GAKE,EAIvB;IAED,QAAQ;;;;;MAEP;IAED,eAAe,SAEd;IAED,eAAe,SAQd;IAED,gBAAgB,SASf;IAED,aAAa,SAaZ;IAED,8CAA8C;IAC9C,MAAM,CAAC,WAAW,AADd,CAAuC,EAA/B,gBACM,QAkDjB;IAED,KAAK,SA6GJ;IAED,UAAU,SAuGT;IAED,0EAA0E;IAC1E,eAAe,CAAC,QAAQ,EADZ,EAAE,GAAG,OAAO,GAAG,KACH,EAAE,KAAK,EADoB,aACpB,QAkB9B;IAED,uEAAuE;IACvE,aAAa,CAAC,QAAQ,EADV,EAAE,GAAG,OAAO,GAAG,KACL,EAAE,KAAK,EADsB,UACtB,QAe5B;IAED;;;8BAG0B;IAC1B,kBAAkB,CAAC,KAAK,EADb,KACa,QAWvB;IAED,mCAAmC;IACnC,SAAS,CAAC,KAAK,EADH,aACG,QAMd;IAED,oBAAoB,SAenB;IAED,cAAc,SA4Bb;IAED,mBAAmB,SASlB;IAED,wBAAwB,SASvB;IAED,4BAA4B;IAC5B,aAAa,CAAC,KAAK,EADP,MACO,QAKlB;IAED,gGAAgG;IAChG,SAAS,CAAC,KAAK,EADH,MACG,EAAE,OAAO,AADE,CAAmE,EAA3D;QAAC,IAAI,CAAC,EAAC,OAAO,CAAC;QAAA,MAAM,CAAC,EAAC,OAAO,CAAC;QAAA,OAAO,CAAC,EAAC,OAAO,CAAA;KACpD,QAmB5B;IAED;;;;;OAKG;IACG,YAAY,CAAC,IAAI,EAFZ,MAEY,GAFW,OAAO,CAAC;QAAC,EAAE,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC,CAWzE;IAED,iEAAiE;IAC3D,WAAW,CAAC,IAAI,EADV,OACU,EAAE,OAAO,AADL,CAAoC,EAA5B;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KACd,oBAUnC;IAED,qCAAqC;IAC/B,gBAAgB,CAAC,KAAK,EADhB,OAAO,GAAG,KACM,oBAc3B;IAED;+FAC2F;IAC3F,SAAS,CAAC,KAAK,EAFH,OAAO,GAAG,KAEP,EAAE,KAAK,EAFqB,MAErB,EAAE,OAAO,AAD5B,CAAmE,EAA3D;QAAC,IAAI,CAAC,EAAC,OAAO,CAAC;QAAC,MAAM,CAAC,EAAC,OAAO,CAAC;QAAC,IAAI,CAAC,EAAC,OAAO,CAAA;KACrB,GAD4C,OAAO,CA8BtF;IAED;uGACmG;IACnG,SAAS,CAAC,KAAK,EADJ,MACI,EAAE,GAAG,EADa,MACb,EAAE,OAAO,AADgB,CAAmD,EAA3C;QAAC,IAAI,CAAC,EAAC,OAAO,CAAC;QAAC,MAAM,CAAC,EAAC,OAAO,CAAA;KAClD,QAWjC;IAED,qCAAqC;IACrC,eAAe,CAAC,KAAK,EADT,OAAO,GAAG,KACD,UAEpB;IAED,gBAAgB,SAGf;IAED;6DACyD;IACzD,cAAc,SAYb;IAED;;;;;OAKG;IACH,gBAAgB,CAAC,KAAK,EAFX,OAAO,GAAG,KAEC,QAkBrB;IAED;;;;;;;;OAQG;IACH,oBAAoB,CAAC,KAAK,EAFf,OAAO,GAAG,KAEK,QAyBzB;IAED,uBAAuB,SAGtB;IAED,eAAe,SAed;IAED,oBAAoB,SAWnB;IAED,qCAAqC;IACrC,WAAW,CAAC,KAAK,EADL,OAAO,GAAG,KACL,QAShB;IAED,WAAW,SASV;IAED,sCAAsC;IACtC,qBAAqB,IADP,EAAE,GAAG,OAAO,GAAG,KAAK,CAcjC;IAED,cAAc;IACR,QAAQ,qBA+Bb;IAED,sDAAsD;IACtD,IAAI,CAAC,OAAO,AADA,CAAuC,EAA/B;QAAC,SAAS,CAAC,EAAC,OAAO,CAAA;KACtB,QA+BhB;IAED,gCAAgC;IAChC,YAAY,CAAC,QAAQ,EADT,OACS,QAKpB;IAED,8CAA8C;IAC9C,IAAI,CAAC,YAAY,AADL,CAA+B,EAAvB,OACK,QAsBxB;IAED;;;yCAGqC;IACrC,qBAAqB,IADR,EAAE,GAAG,OAAO,GAAG,KAAK,CAShC;CACF"}
|
package/dist/types/date.d.ts
CHANGED
|
@@ -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 */
|
package/dist/types/date.d.ts.map
CHANGED
|
@@ -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,
|
|
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"}
|
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,
|
|
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`
|
|
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
|
-
|
|
29
|
-
|
|
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
|
-
|
|
37
|
-
mini.display =
|
|
38
|
-
mini.focusedDate = date;
|
|
41
|
+
anchorDate = event.detail.date.toString();
|
|
42
|
+
mini.display = anchorDate.slice(0, 7);
|
|
39
43
|
});
|
|
40
44
|
```
|
|
41
45
|
|
|
42
|
-
|
|
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
|
|
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/calendar-model.js
CHANGED
|
@@ -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);
|
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
|
|
|
@@ -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,
|
|
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
|
-
|
|
765
|
-
|
|
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
|
-
|
|
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
|
}
|