@haiilo/catalyst 5.3.0 → 5.4.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.
Files changed (169) hide show
  1. package/dist/catalyst/catalyst.css +56 -39
  2. package/dist/catalyst/catalyst.esm.js +1 -1
  3. package/dist/catalyst/catalyst.esm.js.map +1 -1
  4. package/dist/catalyst/index.cdn.js +1 -0
  5. package/dist/catalyst/index.esm.js +2 -2
  6. package/dist/catalyst/index.esm.js.map +1 -1
  7. package/dist/catalyst/p-34e0cbba.entry.js +10 -0
  8. package/dist/catalyst/p-34e0cbba.entry.js.map +1 -0
  9. package/dist/catalyst/{p-d1fb9d96.js → p-ce6a1db2.js} +1 -1
  10. package/dist/catalyst/p-ce6a1db2.js.map +1 -0
  11. package/dist/catalyst/p-cf32399c.js +2 -0
  12. package/dist/catalyst/p-cf32399c.js.map +1 -0
  13. package/dist/catalyst/scss/_snippets/_checkbox-hint.scss +20 -0
  14. package/dist/catalyst/scss/utils/_border.scss +14 -0
  15. package/dist/catalyst/scss/utils/_media.mixins.scss +0 -1
  16. package/dist/catalyst/scss/utils/_typography.mixins.scss +1 -0
  17. package/dist/cjs/{cat-alert_25.cjs.entry.js → cat-alert_27.cjs.entry.js} +3628 -185
  18. package/dist/cjs/cat-alert_27.cjs.entry.js.map +1 -0
  19. package/dist/cjs/{cat-icon-registry-671af264.js → cat-icon-registry-228164a1.js} +43 -2
  20. package/dist/cjs/cat-icon-registry-228164a1.js.map +1 -0
  21. package/dist/cjs/catalyst.cjs.js +3 -3
  22. package/dist/cjs/catalyst.cjs.js.map +1 -1
  23. package/dist/cjs/{index-01312a2e.js → index-4258b31e.js} +8 -1
  24. package/dist/{catalyst/p-d1fb9d96.js.map → cjs/index-4258b31e.js.map} +1 -1
  25. package/dist/cjs/index.cjs.js +2 -2
  26. package/dist/cjs/index.cjs.js.map +1 -1
  27. package/dist/cjs/loader.cjs.js +3 -3
  28. package/dist/cjs/loader.cjs.js.map +1 -1
  29. package/dist/collection/collection-manifest.json +4 -2
  30. package/dist/collection/components/cat-alert/cat-alert.js +5 -5
  31. package/dist/collection/components/cat-alert/cat-alert.js.map +1 -1
  32. package/dist/collection/components/cat-button/cat-button.css +7 -7
  33. package/dist/collection/components/cat-button/cat-button.js +6 -24
  34. package/dist/collection/components/cat-button/cat-button.js.map +1 -1
  35. package/dist/collection/components/cat-checkbox/cat-checkbox.css +24 -1
  36. package/dist/collection/components/cat-checkbox/cat-checkbox.js +8 -4
  37. package/dist/collection/components/cat-checkbox/cat-checkbox.js.map +1 -1
  38. package/dist/collection/components/cat-datepicker/cat-datepicker.css +381 -0
  39. package/dist/collection/components/cat-datepicker/cat-datepicker.js +873 -0
  40. package/dist/collection/components/cat-datepicker/cat-datepicker.js.map +1 -0
  41. package/dist/collection/components/cat-datepicker/datepicker-type.js +8 -0
  42. package/dist/collection/components/cat-datepicker/datepicker-type.js.map +1 -0
  43. package/dist/collection/components/cat-datepicker/dayjs.config.js +8 -0
  44. package/dist/collection/components/cat-datepicker/dayjs.config.js.map +1 -0
  45. package/dist/collection/components/cat-datepicker/vanillajs-datepicker.config.js +46 -0
  46. package/dist/collection/components/cat-datepicker/vanillajs-datepicker.config.js.map +1 -0
  47. package/dist/collection/components/cat-dropdown/cat-dropdown.css +1 -0
  48. package/dist/collection/components/cat-dropdown/cat-dropdown.js +12 -5
  49. package/dist/collection/components/cat-dropdown/cat-dropdown.js.map +1 -1
  50. package/dist/collection/components/cat-form-group/cat-form-group.js +1 -1
  51. package/dist/collection/components/cat-form-group/cat-form-group.js.map +1 -1
  52. package/dist/collection/components/cat-icon/cat-icon-registry.js +29 -1
  53. package/dist/collection/components/cat-icon/cat-icon-registry.js.map +1 -1
  54. package/dist/collection/components/cat-input/cat-input.css +384 -11
  55. package/dist/collection/components/cat-input/cat-input.js +8 -4
  56. package/dist/collection/components/cat-input/cat-input.js.map +1 -1
  57. package/dist/collection/components/cat-notification/cat-notification.js +1 -1
  58. package/dist/collection/components/cat-notification/cat-notification.js.map +1 -1
  59. package/dist/collection/components/cat-pagination/cat-pagination.js +28 -6
  60. package/dist/collection/components/cat-pagination/cat-pagination.js.map +1 -1
  61. package/dist/collection/components/cat-radio/cat-radio.css +24 -1
  62. package/dist/collection/components/cat-radio/cat-radio.js +8 -4
  63. package/dist/collection/components/cat-radio/cat-radio.js.map +1 -1
  64. package/dist/collection/components/cat-radio-group/cat-radio-group.js +7 -3
  65. package/dist/collection/components/cat-radio-group/cat-radio-group.js.map +1 -1
  66. package/dist/collection/components/cat-scrollable/cat-scrollable.css +1 -4
  67. package/dist/collection/components/cat-select/cat-select.css +8 -11
  68. package/dist/collection/components/cat-select/cat-select.js +43 -18
  69. package/dist/collection/components/cat-select/cat-select.js.map +1 -1
  70. package/dist/collection/components/cat-skeleton/cat-skeleton.css +1 -1
  71. package/dist/collection/components/cat-textarea/cat-textarea.css +9 -12
  72. package/dist/collection/components/cat-textarea/cat-textarea.js +8 -4
  73. package/dist/collection/components/cat-textarea/cat-textarea.js.map +1 -1
  74. package/dist/collection/components/cat-timepicker/cat-timepicker.css +5 -0
  75. package/dist/collection/components/cat-timepicker/cat-timepicker.js +668 -0
  76. package/dist/collection/components/cat-timepicker/cat-timepicker.js.map +1 -0
  77. package/dist/collection/components/cat-toggle/cat-toggle.css +24 -1
  78. package/dist/collection/components/cat-toggle/cat-toggle.js +8 -4
  79. package/dist/collection/components/cat-toggle/cat-toggle.js.map +1 -1
  80. package/dist/collection/components/cat-tooltip/cat-tooltip.css +1 -1
  81. package/dist/collection/index.cdn.js +1 -0
  82. package/dist/collection/scss/_snippets/_checkbox-hint.scss +20 -0
  83. package/dist/collection/scss/utils/_border.scss +14 -0
  84. package/dist/collection/scss/utils/_media.mixins.scss +0 -1
  85. package/dist/collection/scss/utils/_typography.mixins.scss +1 -0
  86. package/dist/components/cat-alert.js +5 -5
  87. package/dist/components/cat-alert.js.map +1 -1
  88. package/dist/components/cat-button2.js +7 -9
  89. package/dist/components/cat-button2.js.map +1 -1
  90. package/dist/components/cat-checkbox2.js +2 -2
  91. package/dist/components/cat-checkbox2.js.map +1 -1
  92. package/dist/components/cat-datepicker.d.ts +11 -0
  93. package/dist/components/cat-datepicker.js +3210 -0
  94. package/dist/components/cat-datepicker.js.map +1 -0
  95. package/dist/components/cat-dropdown2.js +182 -57
  96. package/dist/components/cat-dropdown2.js.map +1 -1
  97. package/dist/components/cat-form-group.js +1 -1
  98. package/dist/components/cat-form-group.js.map +1 -1
  99. package/dist/components/cat-icon-registry.js +42 -1
  100. package/dist/components/cat-icon-registry.js.map +1 -1
  101. package/dist/components/cat-input.js +1 -226
  102. package/dist/components/cat-input.js.map +1 -1
  103. package/dist/components/cat-input2.js +230 -0
  104. package/dist/components/cat-input2.js.map +1 -0
  105. package/dist/components/cat-pagination.js +10 -5
  106. package/dist/components/cat-pagination.js.map +1 -1
  107. package/dist/components/cat-radio-group.js.map +1 -1
  108. package/dist/components/cat-radio.js +2 -2
  109. package/dist/components/cat-radio.js.map +1 -1
  110. package/dist/components/cat-scrollable2.js +7 -5
  111. package/dist/components/cat-scrollable2.js.map +1 -1
  112. package/dist/components/cat-select-demo.js +2 -2
  113. package/dist/components/cat-select-demo.js.map +1 -1
  114. package/dist/components/cat-select2.js +37 -16
  115. package/dist/components/cat-select2.js.map +1 -1
  116. package/dist/components/cat-skeleton2.js +1 -1
  117. package/dist/components/cat-skeleton2.js.map +1 -1
  118. package/dist/components/cat-textarea.js +3 -3
  119. package/dist/components/cat-textarea.js.map +1 -1
  120. package/dist/components/cat-timepicker.d.ts +11 -0
  121. package/dist/components/cat-timepicker.js +258 -0
  122. package/dist/components/cat-timepicker.js.map +1 -0
  123. package/dist/components/cat-toggle.js +2 -2
  124. package/dist/components/cat-toggle.js.map +1 -1
  125. package/dist/components/cat-tooltip.js +1 -1
  126. package/dist/components/cat-tooltip.js.map +1 -1
  127. package/dist/components/floating-ui.dom.esm.js +64 -62
  128. package/dist/components/floating-ui.dom.esm.js.map +1 -1
  129. package/dist/components/index.js +1 -1
  130. package/dist/components/index.js.map +1 -1
  131. package/dist/esm/{cat-alert_25.entry.js → cat-alert_27.entry.js} +3627 -186
  132. package/dist/esm/cat-alert_27.entry.js.map +1 -0
  133. package/dist/esm/{cat-icon-registry-d6b80490.js → cat-icon-registry-4bd597f4.js} +43 -2
  134. package/dist/esm/cat-icon-registry-4bd597f4.js.map +1 -0
  135. package/dist/esm/catalyst.js +4 -4
  136. package/dist/esm/catalyst.js.map +1 -1
  137. package/dist/esm/{index-fc2f91a4.js → index-636ce8d6.js} +8 -1
  138. package/dist/esm/index-636ce8d6.js.map +1 -0
  139. package/dist/esm/index.js +3 -3
  140. package/dist/esm/index.js.map +1 -1
  141. package/dist/esm/loader.js +4 -4
  142. package/dist/esm/loader.js.map +1 -1
  143. package/dist/types/components/cat-button/cat-button.d.ts +0 -5
  144. package/dist/types/components/cat-checkbox/cat-checkbox.d.ts +1 -1
  145. package/dist/types/components/cat-datepicker/cat-datepicker.d.ts +187 -0
  146. package/dist/types/components/cat-datepicker/datepicker-type.d.ts +7 -0
  147. package/dist/types/components/cat-datepicker/datepicker.d.ts +1 -0
  148. package/dist/types/components/cat-datepicker/dayjs.config.d.ts +3 -0
  149. package/dist/types/components/cat-datepicker/vanillajs-datepicker.config.d.ts +4 -0
  150. package/dist/types/components/cat-input/cat-input.d.ts +1 -1
  151. package/dist/types/components/cat-pagination/cat-pagination.d.ts +6 -0
  152. package/dist/types/components/cat-radio/cat-radio.d.ts +1 -1
  153. package/dist/types/components/cat-radio-group/cat-radio-group.d.ts +1 -1
  154. package/dist/types/components/cat-select/cat-select.d.ts +6 -1
  155. package/dist/types/components/cat-textarea/cat-textarea.d.ts +1 -1
  156. package/dist/types/components/cat-timepicker/cat-timepicker.d.ts +158 -0
  157. package/dist/types/components/cat-toggle/cat-toggle.d.ts +1 -1
  158. package/dist/types/components.d.ts +532 -17
  159. package/package.json +22 -18
  160. package/dist/catalyst/p-ba081831.entry.js +0 -10
  161. package/dist/catalyst/p-ba081831.entry.js.map +0 -1
  162. package/dist/catalyst/p-ccfebe33.js +0 -2
  163. package/dist/catalyst/p-ccfebe33.js.map +0 -1
  164. package/dist/cjs/cat-alert_25.cjs.entry.js.map +0 -1
  165. package/dist/cjs/cat-icon-registry-671af264.js.map +0 -1
  166. package/dist/cjs/index-01312a2e.js.map +0 -1
  167. package/dist/esm/cat-alert_25.entry.js.map +0 -1
  168. package/dist/esm/cat-icon-registry-d6b80490.js.map +0 -1
  169. package/dist/esm/index-fc2f91a4.js.map +0 -1
@@ -0,0 +1,3210 @@
1
+ import { proxyCustomElement, HTMLElement as HTMLElement$1, createEvent, h, Host } from '@stencil/core/internal/client';
2
+ import { c as createCommonjsModule, a as commonjsGlobal, l as loglevel } from './loglevel.js';
3
+ import { c as catI18nRegistry } from './cat-i18n-registry.js';
4
+ import { d as defineCustomElement$5 } from './cat-button2.js';
5
+ import { d as defineCustomElement$4 } from './cat-icon2.js';
6
+ import { d as defineCustomElement$3 } from './cat-input2.js';
7
+ import { d as defineCustomElement$2 } from './cat-spinner2.js';
8
+
9
+ var dayjs_min = createCommonjsModule(function (module, exports) {
10
+ !function(t,e){module.exports=e();}(commonjsGlobal,(function(){var t=1e3,e=6e4,n=36e5,r="millisecond",i="second",s="minute",u="hour",a="day",o="week",f="month",h="quarter",c="year",d="date",l="Invalid Date",$=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,y=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,M={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(t){var e=["th","st","nd","rd"],n=t%100;return "["+t+(e[(n-20)%10]||e[n]||e[0])+"]"}},m=function(t,e,n){var r=String(t);return !r||r.length>=e?t:""+Array(e+1-r.length).join(n)+t},v={s:m,z:function(t){var e=-t.utcOffset(),n=Math.abs(e),r=Math.floor(n/60),i=n%60;return (e<=0?"+":"-")+m(r,2,"0")+":"+m(i,2,"0")},m:function t(e,n){if(e.date()<n.date())return -t(n,e);var r=12*(n.year()-e.year())+(n.month()-e.month()),i=e.clone().add(r,f),s=n-i<0,u=e.clone().add(r+(s?-1:1),f);return +(-(r+(n-i)/(s?i-u:u-i))||0)},a:function(t){return t<0?Math.ceil(t)||0:Math.floor(t)},p:function(t){return {M:f,y:c,w:o,d:a,D:d,h:u,m:s,s:i,ms:r,Q:h}[t]||String(t||"").toLowerCase().replace(/s$/,"")},u:function(t){return void 0===t}},g="en",D={};D[g]=M;var p=function(t){return t instanceof _},S=function t(e,n,r){var i;if(!e)return g;if("string"==typeof e){var s=e.toLowerCase();D[s]&&(i=s),n&&(D[s]=n,i=s);var u=e.split("-");if(!i&&u.length>1)return t(u[0])}else {var a=e.name;D[a]=e,i=a;}return !r&&i&&(g=i),i||!r&&g},w=function(t,e){if(p(t))return t.clone();var n="object"==typeof e?e:{};return n.date=t,n.args=arguments,new _(n)},O=v;O.l=S,O.i=p,O.w=function(t,e){return w(t,{locale:e.$L,utc:e.$u,x:e.$x,$offset:e.$offset})};var _=function(){function M(t){this.$L=S(t.locale,null,!0),this.parse(t);}var m=M.prototype;return m.parse=function(t){this.$d=function(t){var e=t.date,n=t.utc;if(null===e)return new Date(NaN);if(O.u(e))return new Date;if(e instanceof Date)return new Date(e);if("string"==typeof e&&!/Z$/i.test(e)){var r=e.match($);if(r){var i=r[2]-1||0,s=(r[7]||"0").substring(0,3);return n?new Date(Date.UTC(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)):new Date(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)}}return new Date(e)}(t),this.$x=t.x||{},this.init();},m.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds();},m.$utils=function(){return O},m.isValid=function(){return !(this.$d.toString()===l)},m.isSame=function(t,e){var n=w(t);return this.startOf(e)<=n&&n<=this.endOf(e)},m.isAfter=function(t,e){return w(t)<this.startOf(e)},m.isBefore=function(t,e){return this.endOf(e)<w(t)},m.$g=function(t,e,n){return O.u(t)?this[e]:this.set(n,t)},m.unix=function(){return Math.floor(this.valueOf()/1e3)},m.valueOf=function(){return this.$d.getTime()},m.startOf=function(t,e){var n=this,r=!!O.u(e)||e,h=O.p(t),l=function(t,e){var i=O.w(n.$u?Date.UTC(n.$y,e,t):new Date(n.$y,e,t),n);return r?i:i.endOf(a)},$=function(t,e){return O.w(n.toDate()[t].apply(n.toDate("s"),(r?[0,0,0,0]:[23,59,59,999]).slice(e)),n)},y=this.$W,M=this.$M,m=this.$D,v="set"+(this.$u?"UTC":"");switch(h){case c:return r?l(1,0):l(31,11);case f:return r?l(1,M):l(0,M+1);case o:var g=this.$locale().weekStart||0,D=(y<g?y+7:y)-g;return l(r?m-D:m+(6-D),M);case a:case d:return $(v+"Hours",0);case u:return $(v+"Minutes",1);case s:return $(v+"Seconds",2);case i:return $(v+"Milliseconds",3);default:return this.clone()}},m.endOf=function(t){return this.startOf(t,!1)},m.$set=function(t,e){var n,o=O.p(t),h="set"+(this.$u?"UTC":""),l=(n={},n[a]=h+"Date",n[d]=h+"Date",n[f]=h+"Month",n[c]=h+"FullYear",n[u]=h+"Hours",n[s]=h+"Minutes",n[i]=h+"Seconds",n[r]=h+"Milliseconds",n)[o],$=o===a?this.$D+(e-this.$W):e;if(o===f||o===c){var y=this.clone().set(d,1);y.$d[l]($),y.init(),this.$d=y.set(d,Math.min(this.$D,y.daysInMonth())).$d;}else l&&this.$d[l]($);return this.init(),this},m.set=function(t,e){return this.clone().$set(t,e)},m.get=function(t){return this[O.p(t)]()},m.add=function(r,h){var d,l=this;r=Number(r);var $=O.p(h),y=function(t){var e=w(l);return O.w(e.date(e.date()+Math.round(t*r)),l)};if($===f)return this.set(f,this.$M+r);if($===c)return this.set(c,this.$y+r);if($===a)return y(1);if($===o)return y(7);var M=(d={},d[s]=e,d[u]=n,d[i]=t,d)[$]||1,m=this.$d.getTime()+r*M;return O.w(m,this)},m.subtract=function(t,e){return this.add(-1*t,e)},m.format=function(t){var e=this,n=this.$locale();if(!this.isValid())return n.invalidDate||l;var r=t||"YYYY-MM-DDTHH:mm:ssZ",i=O.z(this),s=this.$H,u=this.$m,a=this.$M,o=n.weekdays,f=n.months,h=function(t,n,i,s){return t&&(t[n]||t(e,r))||i[n].slice(0,s)},c=function(t){return O.s(s%12||12,t,"0")},d=n.meridiem||function(t,e,n){var r=t<12?"AM":"PM";return n?r.toLowerCase():r},$={YY:String(this.$y).slice(-2),YYYY:this.$y,M:a+1,MM:O.s(a+1,2,"0"),MMM:h(n.monthsShort,a,f,3),MMMM:h(f,a),D:this.$D,DD:O.s(this.$D,2,"0"),d:String(this.$W),dd:h(n.weekdaysMin,this.$W,o,2),ddd:h(n.weekdaysShort,this.$W,o,3),dddd:o[this.$W],H:String(s),HH:O.s(s,2,"0"),h:c(1),hh:c(2),a:d(s,u,!0),A:d(s,u,!1),m:String(u),mm:O.s(u,2,"0"),s:String(this.$s),ss:O.s(this.$s,2,"0"),SSS:O.s(this.$ms,3,"0"),Z:i};return r.replace(y,(function(t,e){return e||$[t]||i.replace(":","")}))},m.utcOffset=function(){return 15*-Math.round(this.$d.getTimezoneOffset()/15)},m.diff=function(r,d,l){var $,y=O.p(d),M=w(r),m=(M.utcOffset()-this.utcOffset())*e,v=this-M,g=O.m(this,M);return g=($={},$[c]=g/12,$[f]=g,$[h]=g/3,$[o]=(v-m)/6048e5,$[a]=(v-m)/864e5,$[u]=v/n,$[s]=v/e,$[i]=v/t,$)[y]||v,l?g:O.a(g)},m.daysInMonth=function(){return this.endOf(f).$D},m.$locale=function(){return D[this.$L]},m.locale=function(t,e){if(!t)return this.$L;var n=this.clone(),r=S(t,e,!0);return r&&(n.$L=r),n},m.clone=function(){return O.w(this.$d,this)},m.toDate=function(){return new Date(this.valueOf())},m.toJSON=function(){return this.isValid()?this.toISOString():null},m.toISOString=function(){return this.$d.toISOString()},m.toString=function(){return this.$d.toUTCString()},M}(),T=_.prototype;return w.prototype=T,[["$ms",r],["$s",i],["$m",s],["$H",u],["$W",a],["$M",f],["$y",c],["$D",d]].forEach((function(t){T[t[1]]=function(e){return this.$g(e,t[0],t[1])};})),w.extend=function(t,e){return t.$i||(t(e,_,w),t.$i=!0),w},w.locale=S,w.isDayjs=p,w.unix=function(t){return w(1e3*t)},w.en=D[g],w.Ls=D,w.p={},w}));
11
+ });
12
+
13
+ var isoWeek = createCommonjsModule(function (module, exports) {
14
+ !function(e,t){module.exports=t();}(commonjsGlobal,(function(){var e="day";return function(t,i,s){var a=function(t){return t.add(4-t.isoWeekday(),e)},d=i.prototype;d.isoWeekYear=function(){return a(this).year()},d.isoWeek=function(t){if(!this.$utils().u(t))return this.add(7*(t-this.isoWeek()),e);var i,d,n,o,r=a(this),u=(i=this.isoWeekYear(),d=this.$u,n=(d?s.utc:s)().year(i).startOf("year"),o=4-n.isoWeekday(),n.isoWeekday()>4&&(o+=7),n.add(o,e));return r.diff(u,"week")+1},d.isoWeekday=function(e){return this.$utils().u(e)?this.day()||7:this.day(this.day()%7?e:e-7)};var n=d.startOf;d.startOf=function(e,t){var i=this.$utils(),s=!!i.u(t)||t;return "isoweek"===i.p(e)?s?this.date(this.date()-(this.isoWeekday()-1)).startOf("day"):this.date(this.date()-1-(this.isoWeekday()-1)+7).endOf("day"):n.bind(this)(e,t)};}}));
15
+ });
16
+
17
+ var utc = createCommonjsModule(function (module, exports) {
18
+ !function(t,i){module.exports=i();}(commonjsGlobal,(function(){var t="minute",i=/[+-]\d\d(?::?\d\d)?/g,e=/([+-]|\d\d)/g;return function(s,f,n){var u=f.prototype;n.utc=function(t){var i={date:t,utc:!0,args:arguments};return new f(i)},u.utc=function(i){var e=n(this.toDate(),{locale:this.$L,utc:!0});return i?e.add(this.utcOffset(),t):e},u.local=function(){return n(this.toDate(),{locale:this.$L,utc:!1})};var o=u.parse;u.parse=function(t){t.utc&&(this.$u=!0),this.$utils().u(t.$offset)||(this.$offset=t.$offset),o.call(this,t);};var r=u.init;u.init=function(){if(this.$u){var t=this.$d;this.$y=t.getUTCFullYear(),this.$M=t.getUTCMonth(),this.$D=t.getUTCDate(),this.$W=t.getUTCDay(),this.$H=t.getUTCHours(),this.$m=t.getUTCMinutes(),this.$s=t.getUTCSeconds(),this.$ms=t.getUTCMilliseconds();}else r.call(this);};var a=u.utcOffset;u.utcOffset=function(s,f){var n=this.$utils().u;if(n(s))return this.$u?0:n(this.$offset)?a.call(this):this.$offset;if("string"==typeof s&&(s=function(t){void 0===t&&(t="");var s=t.match(i);if(!s)return null;var f=(""+s[0]).match(e)||["-",0,0],n=f[0],u=60*+f[1]+ +f[2];return 0===u?0:"+"===n?u:-u}(s),null===s))return this;var u=Math.abs(s)<=16?60*s:s,o=this;if(f)return o.$offset=u,o.$u=0===s,o;if(0!==s){var r=this.$u?this.toDate().getTimezoneOffset():-1*this.utcOffset();(o=this.local().add(u+r,t)).$offset=u,o.$x.$localOffset=r;}else o=this.utc();return o};var h=u.format;u.format=function(t){var i=t||(this.$u?"YYYY-MM-DDTHH:mm:ss[Z]":"");return h.call(this,i)},u.valueOf=function(){var t=this.$utils().u(this.$offset)?0:this.$offset+(this.$x.$localOffset||this.$d.getTimezoneOffset());return this.$d.valueOf()-6e4*t},u.isUTC=function(){return !!this.$u},u.toISOString=function(){return this.toDate().toISOString()},u.toString=function(){return this.toDate().toUTCString()};var l=u.toDate;u.toDate=function(t){return "s"===t&&this.$offset?n(this.format("YYYY-MM-DD HH:mm:ss:SSS")).toDate():l.call(this)};var c=u.diff;u.diff=function(t,i,e){if(t&&this.$u===t.$u)return c.call(this,t,i,e);var s=this.local(),f=n(t).local();return c.call(s,f,i,e)};}}));
19
+ });
20
+
21
+ dayjs_min.extend(isoWeek);
22
+ dayjs_min.extend(utc);
23
+ const today$1 = () => dayjs_min().utc().startOf('day').toDate();
24
+
25
+ function lastItemOf(arr) {
26
+ return arr[arr.length - 1];
27
+ }
28
+
29
+ // push only the items not included in the array
30
+ function pushUnique(arr, ...items) {
31
+ items.forEach((item) => {
32
+ if (arr.includes(item)) {
33
+ return;
34
+ }
35
+ arr.push(item);
36
+ });
37
+ return arr;
38
+ }
39
+
40
+ function stringToArray(str, separator) {
41
+ // convert empty string to an empty array
42
+ return str ? str.split(separator) : [];
43
+ }
44
+
45
+ function isInRange(testVal, min, max) {
46
+ const minOK = min === undefined || testVal >= min;
47
+ const maxOK = max === undefined || testVal <= max;
48
+ return minOK && maxOK;
49
+ }
50
+
51
+ function limitToRange(val, min, max) {
52
+ if (val < min) {
53
+ return min;
54
+ }
55
+ if (val > max) {
56
+ return max;
57
+ }
58
+ return val;
59
+ }
60
+
61
+ function createTagRepeat(tagName, repeat, attributes = {}, index = 0, html = '') {
62
+ const openTagSrc = Object.keys(attributes).reduce((src, attr) => {
63
+ let val = attributes[attr];
64
+ if (typeof val === 'function') {
65
+ val = val(index);
66
+ }
67
+ return `${src} ${attr}="${val}"`;
68
+ }, tagName);
69
+ html += `<${openTagSrc}></${tagName}>`;
70
+
71
+ const next = index + 1;
72
+ return next < repeat
73
+ ? createTagRepeat(tagName, repeat, attributes, next, html)
74
+ : html;
75
+ }
76
+
77
+ // Remove the spacing surrounding tags for HTML parser not to create text nodes
78
+ // before/after elements
79
+ function optimizeTemplateHTML(html) {
80
+ return html.replace(/>\s+/g, '>').replace(/\s+</, '<');
81
+ }
82
+
83
+ function stripTime(timeValue) {
84
+ return new Date(timeValue).setHours(0, 0, 0, 0);
85
+ }
86
+
87
+ function today() {
88
+ return new Date().setHours(0, 0, 0, 0);
89
+ }
90
+
91
+ // Get the time value of the start of given date or year, month and day
92
+ function dateValue(...args) {
93
+ switch (args.length) {
94
+ case 0:
95
+ return today();
96
+ case 1:
97
+ return stripTime(args[0]);
98
+ }
99
+
100
+ // use setFullYear() to keep 2-digit year from being mapped to 1900-1999
101
+ const newDate = new Date(0);
102
+ newDate.setFullYear(...args);
103
+ return newDate.setHours(0, 0, 0, 0);
104
+ }
105
+
106
+ function addDays(date, amount) {
107
+ const newDate = new Date(date);
108
+ return newDate.setDate(newDate.getDate() + amount);
109
+ }
110
+
111
+ function addWeeks(date, amount) {
112
+ return addDays(date, amount * 7);
113
+ }
114
+
115
+ function addMonths(date, amount) {
116
+ // If the day of the date is not in the new month, the last day of the new
117
+ // month will be returned. e.g. Jan 31 + 1 month → Feb 28 (not Mar 03)
118
+ const newDate = new Date(date);
119
+ const monthsToSet = newDate.getMonth() + amount;
120
+ let expectedMonth = monthsToSet % 12;
121
+ if (expectedMonth < 0) {
122
+ expectedMonth += 12;
123
+ }
124
+
125
+ const time = newDate.setMonth(monthsToSet);
126
+ return newDate.getMonth() !== expectedMonth ? newDate.setDate(0) : time;
127
+ }
128
+
129
+ function addYears(date, amount) {
130
+ // If the date is Feb 29 and the new year is not a leap year, Feb 28 of the
131
+ // new year will be returned.
132
+ const newDate = new Date(date);
133
+ const expectedMonth = newDate.getMonth();
134
+ const time = newDate.setFullYear(newDate.getFullYear() + amount);
135
+ return expectedMonth === 1 && newDate.getMonth() === 2 ? newDate.setDate(0) : time;
136
+ }
137
+
138
+ // Calculate the distance bettwen 2 days of the week
139
+ function dayDiff(day, from) {
140
+ return (day - from + 7) % 7;
141
+ }
142
+
143
+ // Get the date of the specified day of the week of given base date
144
+ function dayOfTheWeekOf(baseDate, dayOfWeek, weekStart = 0) {
145
+ const baseDay = new Date(baseDate).getDay();
146
+ return addDays(baseDate, dayDiff(dayOfWeek, weekStart) - dayDiff(baseDay, weekStart));
147
+ }
148
+
149
+ function calcWeekNum(dayOfTheWeek, sameDayOfFirstWeek) {
150
+ return Math.round((dayOfTheWeek - sameDayOfFirstWeek) / 604800000) + 1;
151
+ }
152
+
153
+ // Get the ISO week number of a date
154
+ function getIsoWeek(date) {
155
+ // - Start of ISO week is Monday
156
+ // - Use Thursday for culculation because the first Thursday of ISO week is
157
+ // always in January
158
+ const thuOfTheWeek = dayOfTheWeekOf(date, 4, 1);
159
+ // - Week 1 in ISO week is the week including Jan 04
160
+ // - Use the Thu of given date's week (instead of given date itself) to
161
+ // calculate week 1 of the year so that Jan 01 - 03 won't be miscalculated
162
+ // as week 0 when Jan 04 is Mon - Wed
163
+ const firstThu = dayOfTheWeekOf(new Date(thuOfTheWeek).setMonth(0, 4), 4, 1);
164
+ // return Math.round((thuOfTheWeek - firstThu) / 604800000) + 1;
165
+ return calcWeekNum(thuOfTheWeek, firstThu);
166
+ }
167
+
168
+ // Calculate week number in traditional week number system
169
+ // @see https://en.wikipedia.org/wiki/Week#Other_week_numbering_systems
170
+ function calcTraditionalWeekNumber(date, weekStart) {
171
+ // - Week 1 of traditional week is the week including the Jan 01
172
+ // - Use Jan 01 of given date's year to calculate the start of week 1
173
+ const startOfFirstWeek = dayOfTheWeekOf(new Date(date).setMonth(0, 1), weekStart, weekStart);
174
+ const startOfTheWeek = dayOfTheWeekOf(date, weekStart, weekStart);
175
+ const weekNum = calcWeekNum(startOfTheWeek, startOfFirstWeek);
176
+ if (weekNum < 53) {
177
+ return weekNum;
178
+ }
179
+ // If the 53rd week includes Jan 01, it's actually next year's week 1
180
+ const weekOneOfNextYear = dayOfTheWeekOf(new Date(date).setDate(32), weekStart, weekStart);
181
+ return startOfTheWeek === weekOneOfNextYear ? 1 : weekNum;
182
+ }
183
+
184
+ // Get the Western traditional week number of a date
185
+ function getWesternTradWeek(date) {
186
+ // Start of Western traditionl week is Sunday
187
+ return calcTraditionalWeekNumber(date, 0);
188
+ }
189
+
190
+ // Get the Middle Eastern week number of a date
191
+ function getMidEasternWeek(date) {
192
+ // Start of Middle Eastern week is Saturday
193
+ return calcTraditionalWeekNumber(date, 6);
194
+ }
195
+
196
+ // Get the start year of the period of years that includes given date
197
+ // years: length of the year period
198
+ function startOfYearPeriod(date, years) {
199
+ /* @see https://en.wikipedia.org/wiki/Year_zero#ISO_8601 */
200
+ const year = new Date(date).getFullYear();
201
+ return Math.floor(year / years) * years;
202
+ }
203
+
204
+ // Convert date to the first/last date of the month/year of the date
205
+ function regularizeDate(date, timeSpan, useLastDate) {
206
+ if (timeSpan !== 1 && timeSpan !== 2) {
207
+ return date;
208
+ }
209
+ const newDate = new Date(date);
210
+ if (timeSpan === 1) {
211
+ useLastDate
212
+ ? newDate.setMonth(newDate.getMonth() + 1, 0)
213
+ : newDate.setDate(1);
214
+ } else {
215
+ useLastDate
216
+ ? newDate.setFullYear(newDate.getFullYear() + 1, 0, 0)
217
+ : newDate.setMonth(0, 1);
218
+ }
219
+ return newDate.setHours(0, 0, 0, 0);
220
+ }
221
+
222
+ // pattern for format parts
223
+ const reFormatTokens = /dd?|DD?|mm?|MM?|yy?(?:yy)?/;
224
+ // pattern for non date parts
225
+ const reNonDateParts = /[\s!-/:-@[-`{-~年月日]+/;
226
+ // cache for persed formats
227
+ let knownFormats = {};
228
+ // parse funtions for date parts
229
+ const parseFns = {
230
+ y(date, year) {
231
+ return new Date(date).setFullYear(parseInt(year, 10));
232
+ },
233
+ m(date, month, locale) {
234
+ const newDate = new Date(date);
235
+ let monthIndex = parseInt(month, 10) - 1;
236
+
237
+ if (isNaN(monthIndex)) {
238
+ if (!month) {
239
+ return NaN;
240
+ }
241
+
242
+ const monthName = month.toLowerCase();
243
+ const compareNames = name => name.toLowerCase().startsWith(monthName);
244
+ // compare with both short and full names because some locales have periods
245
+ // in the short names (not equal to the first X letters of the full names)
246
+ monthIndex = locale.monthsShort.findIndex(compareNames);
247
+ if (monthIndex < 0) {
248
+ monthIndex = locale.months.findIndex(compareNames);
249
+ }
250
+ if (monthIndex < 0) {
251
+ return NaN;
252
+ }
253
+ }
254
+
255
+ newDate.setMonth(monthIndex);
256
+ return newDate.getMonth() !== normalizeMonth(monthIndex)
257
+ ? newDate.setDate(0)
258
+ : newDate.getTime();
259
+ },
260
+ d(date, day) {
261
+ return new Date(date).setDate(parseInt(day, 10));
262
+ },
263
+ };
264
+ // format functions for date parts
265
+ const formatFns = {
266
+ d(date) {
267
+ return date.getDate();
268
+ },
269
+ dd(date) {
270
+ return padZero(date.getDate(), 2);
271
+ },
272
+ D(date, locale) {
273
+ return locale.daysShort[date.getDay()];
274
+ },
275
+ DD(date, locale) {
276
+ return locale.days[date.getDay()];
277
+ },
278
+ m(date) {
279
+ return date.getMonth() + 1;
280
+ },
281
+ mm(date) {
282
+ return padZero(date.getMonth() + 1, 2);
283
+ },
284
+ M(date, locale) {
285
+ return locale.monthsShort[date.getMonth()];
286
+ },
287
+ MM(date, locale) {
288
+ return locale.months[date.getMonth()];
289
+ },
290
+ y(date) {
291
+ return date.getFullYear();
292
+ },
293
+ yy(date) {
294
+ return padZero(date.getFullYear(), 2).slice(-2);
295
+ },
296
+ yyyy(date) {
297
+ return padZero(date.getFullYear(), 4);
298
+ },
299
+ };
300
+
301
+ // get month index in normal range (0 - 11) from any number
302
+ function normalizeMonth(monthIndex) {
303
+ return monthIndex > -1 ? monthIndex % 12 : normalizeMonth(monthIndex + 12);
304
+ }
305
+
306
+ function padZero(num, length) {
307
+ return num.toString().padStart(length, '0');
308
+ }
309
+
310
+ function parseFormatString(format) {
311
+ if (typeof format !== 'string') {
312
+ throw new Error("Invalid date format.");
313
+ }
314
+ if (format in knownFormats) {
315
+ return knownFormats[format];
316
+ }
317
+
318
+ // sprit the format string into parts and seprators
319
+ const separators = format.split(reFormatTokens);
320
+ const parts = format.match(new RegExp(reFormatTokens, 'g'));
321
+ if (separators.length === 0 || !parts) {
322
+ throw new Error("Invalid date format.");
323
+ }
324
+
325
+ // collect format functions used in the format
326
+ const partFormatters = parts.map(token => formatFns[token]);
327
+
328
+ // collect parse function keys used in the format
329
+ // iterate over parseFns' keys in order to keep the order of the keys.
330
+ const partParserKeys = Object.keys(parseFns).reduce((keys, key) => {
331
+ const token = parts.find(part => part[0] !== 'D' && part[0].toLowerCase() === key);
332
+ if (token) {
333
+ keys.push(key);
334
+ }
335
+ return keys;
336
+ }, []);
337
+
338
+ return knownFormats[format] = {
339
+ parser(dateStr, locale) {
340
+ const dateParts = dateStr.split(reNonDateParts).reduce((dtParts, part, index) => {
341
+ if (part.length > 0 && parts[index]) {
342
+ const token = parts[index][0];
343
+ if (token === 'M') {
344
+ dtParts.m = part;
345
+ } else if (token !== 'D') {
346
+ dtParts[token] = part;
347
+ }
348
+ }
349
+ return dtParts;
350
+ }, {});
351
+
352
+ // iterate over partParserkeys so that the parsing is made in the oder
353
+ // of year, month and day to prevent the day parser from correcting last
354
+ // day of month wrongly
355
+ return partParserKeys.reduce((origDate, key) => {
356
+ const newDate = parseFns[key](origDate, dateParts[key], locale);
357
+ // ingnore the part failed to parse
358
+ return isNaN(newDate) ? origDate : newDate;
359
+ }, today());
360
+ },
361
+ formatter(date, locale) {
362
+ let dateStr = partFormatters.reduce((str, fn, index) => {
363
+ return str += `${separators[index]}${fn(date, locale)}`;
364
+ }, '');
365
+ // separators' length is always parts' length + 1,
366
+ return dateStr += lastItemOf(separators);
367
+ },
368
+ };
369
+ }
370
+
371
+ function parseDate(dateStr, format, locale) {
372
+ if (dateStr instanceof Date || typeof dateStr === 'number') {
373
+ const date = stripTime(dateStr);
374
+ return isNaN(date) ? undefined : date;
375
+ }
376
+ if (!dateStr) {
377
+ return undefined;
378
+ }
379
+ if (dateStr === 'today') {
380
+ return today();
381
+ }
382
+
383
+ if (format && format.toValue) {
384
+ const date = format.toValue(dateStr, format, locale);
385
+ return isNaN(date) ? undefined : stripTime(date);
386
+ }
387
+
388
+ return parseFormatString(format).parser(dateStr, locale);
389
+ }
390
+
391
+ function formatDate(date, format, locale) {
392
+ if (isNaN(date) || (!date && date !== 0)) {
393
+ return '';
394
+ }
395
+
396
+ const dateObj = typeof date === 'number' ? new Date(date) : date;
397
+
398
+ if (format.toDisplay) {
399
+ return format.toDisplay(dateObj, format, locale);
400
+ }
401
+
402
+ return parseFormatString(format).formatter(dateObj, locale);
403
+ }
404
+
405
+ const range = document.createRange();
406
+
407
+ function parseHTML(html) {
408
+ return range.createContextualFragment(html);
409
+ }
410
+
411
+ function getParent(el) {
412
+ return el.parentElement
413
+ || (el.parentNode instanceof ShadowRoot ? el.parentNode.host : undefined);
414
+ }
415
+
416
+ function isActiveElement(el) {
417
+ return el.getRootNode().activeElement === el;
418
+ }
419
+
420
+ function hideElement(el) {
421
+ if (el.style.display === 'none') {
422
+ return;
423
+ }
424
+ // back up the existing display setting in data-style-display
425
+ if (el.style.display) {
426
+ el.dataset.styleDisplay = el.style.display;
427
+ }
428
+ el.style.display = 'none';
429
+ }
430
+
431
+ function showElement(el) {
432
+ if (el.style.display !== 'none') {
433
+ return;
434
+ }
435
+ if (el.dataset.styleDisplay) {
436
+ // restore backed-up dispay property
437
+ el.style.display = el.dataset.styleDisplay;
438
+ delete el.dataset.styleDisplay;
439
+ } else {
440
+ el.style.display = '';
441
+ }
442
+ }
443
+
444
+ function emptyChildNodes(el) {
445
+ if (el.firstChild) {
446
+ el.removeChild(el.firstChild);
447
+ emptyChildNodes(el);
448
+ }
449
+ }
450
+
451
+ function replaceChildNodes(el, newChildNodes) {
452
+ emptyChildNodes(el);
453
+ if (newChildNodes instanceof DocumentFragment) {
454
+ el.appendChild(newChildNodes);
455
+ } else if (typeof newChildNodes === 'string') {
456
+ el.appendChild(parseHTML(newChildNodes));
457
+ } else if (typeof newChildNodes.forEach === 'function') {
458
+ newChildNodes.forEach((node) => {
459
+ el.appendChild(node);
460
+ });
461
+ }
462
+ }
463
+
464
+ const listenerRegistry = new WeakMap();
465
+ const {addEventListener, removeEventListener} = EventTarget.prototype;
466
+
467
+ // Register event listeners to a key object
468
+ // listeners: array of listener definitions;
469
+ // - each definition must be a flat array of event target and the arguments
470
+ // used to call addEventListener() on the target
471
+ function registerListeners(keyObj, listeners) {
472
+ let registered = listenerRegistry.get(keyObj);
473
+ if (!registered) {
474
+ registered = [];
475
+ listenerRegistry.set(keyObj, registered);
476
+ }
477
+ listeners.forEach((listener) => {
478
+ addEventListener.call(...listener);
479
+ registered.push(listener);
480
+ });
481
+ }
482
+
483
+ function unregisterListeners(keyObj) {
484
+ let listeners = listenerRegistry.get(keyObj);
485
+ if (!listeners) {
486
+ return;
487
+ }
488
+ listeners.forEach((listener) => {
489
+ removeEventListener.call(...listener);
490
+ });
491
+ listenerRegistry.delete(keyObj);
492
+ }
493
+
494
+ // Event.composedPath() polyfill for Edge
495
+ // based on https://gist.github.com/kleinfreund/e9787d73776c0e3750dcfcdc89f100ec
496
+ if (!Event.prototype.composedPath) {
497
+ const getComposedPath = (node, path = []) => {
498
+ path.push(node);
499
+
500
+ let parent;
501
+ if (node.parentNode) {
502
+ parent = node.parentNode;
503
+ } else if (node.host) { // ShadowRoot
504
+ parent = node.host;
505
+ } else if (node.defaultView) { // Document
506
+ parent = node.defaultView;
507
+ }
508
+ return parent ? getComposedPath(parent, path) : path;
509
+ };
510
+
511
+ Event.prototype.composedPath = function () {
512
+ return getComposedPath(this.target);
513
+ };
514
+ }
515
+
516
+ function findFromPath(path, criteria, currentTarget) {
517
+ const [node, ...rest] = path;
518
+ if (criteria(node)) {
519
+ return node;
520
+ }
521
+ if (node === currentTarget || node.tagName === 'HTML' || rest.length === 0) {
522
+ // stop when reaching currentTarget or <html>
523
+ return;
524
+ }
525
+ return findFromPath(rest, criteria, currentTarget);
526
+ }
527
+
528
+ // Search for the actual target of a delegated event
529
+ function findElementInEventPath(ev, selector) {
530
+ const criteria = typeof selector === 'function'
531
+ ? selector
532
+ : el => el instanceof Element && el.matches(selector);
533
+ return findFromPath(ev.composedPath(), criteria, ev.currentTarget);
534
+ }
535
+
536
+ // default locales
537
+ const locales = {
538
+ en: {
539
+ days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
540
+ daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
541
+ daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
542
+ months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
543
+ monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
544
+ today: "Today",
545
+ clear: "Clear",
546
+ titleFormat: "MM y"
547
+ }
548
+ };
549
+
550
+ // config options updatable by setOptions() and their default values
551
+ const defaultOptions = {
552
+ autohide: false,
553
+ beforeShowDay: null,
554
+ beforeShowDecade: null,
555
+ beforeShowMonth: null,
556
+ beforeShowYear: null,
557
+ clearButton: false,
558
+ dateDelimiter: ',',
559
+ datesDisabled: [],
560
+ daysOfWeekDisabled: [],
561
+ daysOfWeekHighlighted: [],
562
+ defaultViewDate: undefined, // placeholder, defaults to today() by the program
563
+ disableTouchKeyboard: false,
564
+ enableOnReadonly: true,
565
+ format: 'mm/dd/yyyy',
566
+ language: 'en',
567
+ maxDate: null,
568
+ maxNumberOfDates: 1,
569
+ maxView: 3,
570
+ minDate: null,
571
+ nextArrow: '»',
572
+ orientation: 'auto',
573
+ pickLevel: 0,
574
+ prevArrow: '«',
575
+ showDaysOfWeek: true,
576
+ showOnClick: true,
577
+ showOnFocus: true,
578
+ startView: 0,
579
+ title: '',
580
+ todayButton: false,
581
+ todayButtonMode: 0,
582
+ todayHighlight: false,
583
+ updateOnBlur: true,
584
+ weekNumbers: 0,
585
+ weekStart: 0,
586
+ };
587
+
588
+ const {
589
+ language: defaultLang,
590
+ format: defaultFormat,
591
+ weekStart: defaultWeekStart,
592
+ } = defaultOptions;
593
+
594
+ // Reducer function to filter out invalid day-of-week from the input
595
+ function sanitizeDOW(dow, day) {
596
+ return dow.length < 6 && day >= 0 && day < 7
597
+ ? pushUnique(dow, day)
598
+ : dow;
599
+ }
600
+
601
+ function determineGetWeekMethod(numberingMode, weekStart) {
602
+ const methodId = numberingMode === 4
603
+ ? (weekStart === 6 ? 3 : !weekStart + 1)
604
+ : numberingMode;
605
+ switch (methodId) {
606
+ case 1:
607
+ return getIsoWeek;
608
+ case 2:
609
+ return getWesternTradWeek;
610
+ case 3:
611
+ return getMidEasternWeek;
612
+ }
613
+ }
614
+
615
+ function updateWeekStart(newValue, config, weekNumbers) {
616
+ config.weekStart = newValue;
617
+ config.weekEnd = (newValue + 6) % 7;
618
+ if (weekNumbers === 4) {
619
+ config.getWeekNumber = determineGetWeekMethod(4, newValue);
620
+ }
621
+ return newValue;
622
+ }
623
+
624
+ // validate input date. if invalid, fallback to the original value
625
+ function validateDate(value, format, locale, origValue) {
626
+ const date = parseDate(value, format, locale);
627
+ return date !== undefined ? date : origValue;
628
+ }
629
+
630
+ // Validate viewId. if invalid, fallback to the original value
631
+ function validateViewId(value, origValue, max = 3) {
632
+ const viewId = parseInt(value, 10);
633
+ return viewId >= 0 && viewId <= max ? viewId : origValue;
634
+ }
635
+
636
+ function replaceOptions(options, from, to, convert = undefined) {
637
+ if (from in options) {
638
+ if (!(to in options)) {
639
+ options[to] = convert ? convert(options[from]) : options[from];
640
+ }
641
+ delete options[from];
642
+ }
643
+ }
644
+
645
+ // Create Datepicker configuration to set
646
+ function processOptions(options, datepicker) {
647
+ const inOpts = Object.assign({}, options);
648
+ const config = {};
649
+ const locales = datepicker.constructor.locales;
650
+ const rangeEnd = !!datepicker.rangeSideIndex;
651
+ let {
652
+ datesDisabled,
653
+ format,
654
+ language,
655
+ locale,
656
+ maxDate,
657
+ maxView,
658
+ minDate,
659
+ pickLevel,
660
+ startView,
661
+ weekNumbers,
662
+ weekStart,
663
+ } = datepicker.config || {};
664
+
665
+ // for backword compatibility
666
+ replaceOptions(inOpts, 'calendarWeeks', 'weekNumbers', val => val ? 1 : 0);
667
+ replaceOptions(inOpts, 'clearBtn', 'clearButton');
668
+ replaceOptions(inOpts, 'todayBtn', 'todayButton');
669
+ replaceOptions(inOpts, 'todayBtnMode', 'todayButtonMode');
670
+
671
+ if (inOpts.language) {
672
+ let lang;
673
+ if (inOpts.language !== language) {
674
+ if (locales[inOpts.language]) {
675
+ lang = inOpts.language;
676
+ } else {
677
+ // Check if langauge + region tag can fallback to the one without
678
+ // region (e.g. fr-CA → fr)
679
+ lang = inOpts.language.split('-')[0];
680
+ if (!locales[lang]) {
681
+ lang = false;
682
+ }
683
+ }
684
+ }
685
+ delete inOpts.language;
686
+ if (lang) {
687
+ language = config.language = lang;
688
+
689
+ // update locale as well when updating language
690
+ const origLocale = locale || locales[defaultLang];
691
+ // use default language's properties for the fallback
692
+ locale = Object.assign({
693
+ format: defaultFormat,
694
+ weekStart: defaultWeekStart
695
+ }, locales[defaultLang]);
696
+ if (language !== defaultLang) {
697
+ Object.assign(locale, locales[language]);
698
+ }
699
+ config.locale = locale;
700
+ // if format and/or weekStart are the same as old locale's defaults,
701
+ // update them to new locale's defaults
702
+ if (format === origLocale.format) {
703
+ format = config.format = locale.format;
704
+ }
705
+ if (weekStart === origLocale.weekStart) {
706
+ weekStart = updateWeekStart(locale.weekStart, config, weekNumbers);
707
+ }
708
+ }
709
+ }
710
+
711
+ if (inOpts.format) {
712
+ const hasToDisplay = typeof inOpts.format.toDisplay === 'function';
713
+ const hasToValue = typeof inOpts.format.toValue === 'function';
714
+ const validFormatString = reFormatTokens.test(inOpts.format);
715
+ if ((hasToDisplay && hasToValue) || validFormatString) {
716
+ format = config.format = inOpts.format;
717
+ }
718
+ delete inOpts.format;
719
+ }
720
+
721
+ //*** pick level ***//
722
+ let newPickLevel = pickLevel;
723
+ if ('pickLevel' in inOpts) {
724
+ newPickLevel = validateViewId(inOpts.pickLevel, pickLevel, 2);
725
+ delete inOpts.pickLevel;
726
+ }
727
+ if (newPickLevel !== pickLevel) {
728
+ if (newPickLevel > pickLevel) {
729
+ // complement current minDate/madDate so that the existing range will be
730
+ // expanded to fit the new level later
731
+ if (!('minDate' in inOpts)) {
732
+ inOpts.minDate = minDate;
733
+ }
734
+ if (!('maxDate' in inOpts)) {
735
+ inOpts.maxDate = maxDate;
736
+ }
737
+ }
738
+ // complement datesDisabled so that it will be reset later
739
+ if (datesDisabled && !inOpts.datesDisabled) {
740
+ inOpts.datesDisabled = [];
741
+ }
742
+ pickLevel = config.pickLevel = newPickLevel;
743
+ }
744
+
745
+ //*** dates ***//
746
+ // while min and maxDate for "no limit" in the options are better to be null
747
+ // (especially when updating), the ones in the config have to be undefined
748
+ // because null is treated as 0 (= unix epoch) when comparing with time value
749
+ let minDt = minDate;
750
+ let maxDt = maxDate;
751
+ if ('minDate' in inOpts) {
752
+ const defaultMinDt = dateValue(0, 0, 1);
753
+ minDt = inOpts.minDate === null
754
+ ? defaultMinDt // set 0000-01-01 to prevent negative values for year
755
+ : validateDate(inOpts.minDate, format, locale, minDt);
756
+ if (minDt !== defaultMinDt) {
757
+ minDt = regularizeDate(minDt, pickLevel, false);
758
+ }
759
+ delete inOpts.minDate;
760
+ }
761
+ if ('maxDate' in inOpts) {
762
+ maxDt = inOpts.maxDate === null
763
+ ? undefined
764
+ : validateDate(inOpts.maxDate, format, locale, maxDt);
765
+ if (maxDt !== undefined) {
766
+ maxDt = regularizeDate(maxDt, pickLevel, true);
767
+ }
768
+ delete inOpts.maxDate;
769
+ }
770
+ if (maxDt < minDt) {
771
+ minDate = config.minDate = maxDt;
772
+ maxDate = config.maxDate = minDt;
773
+ } else {
774
+ if (minDate !== minDt) {
775
+ minDate = config.minDate = minDt;
776
+ }
777
+ if (maxDate !== maxDt) {
778
+ maxDate = config.maxDate = maxDt;
779
+ }
780
+ }
781
+
782
+ if (inOpts.datesDisabled) {
783
+ const dtsDisabled = inOpts.datesDisabled;
784
+ if (typeof dtsDisabled === 'function') {
785
+ config.datesDisabled = null;
786
+ config.checkDisabled = (timeValue, viewId) => dtsDisabled(
787
+ new Date(timeValue),
788
+ viewId,
789
+ rangeEnd
790
+ );
791
+ } else {
792
+ const disabled = config.datesDisabled = dtsDisabled.reduce((dates, dt) => {
793
+ const date = parseDate(dt, format, locale);
794
+ return date !== undefined
795
+ ? pushUnique(dates, regularizeDate(date, pickLevel, rangeEnd))
796
+ : dates;
797
+ }, []);
798
+ config.checkDisabled = timeValue => disabled.includes(timeValue);
799
+ }
800
+ delete inOpts.datesDisabled;
801
+ }
802
+ if ('defaultViewDate' in inOpts) {
803
+ const viewDate = parseDate(inOpts.defaultViewDate, format, locale);
804
+ if (viewDate !== undefined) {
805
+ config.defaultViewDate = viewDate;
806
+ }
807
+ delete inOpts.defaultViewDate;
808
+ }
809
+
810
+ //*** days of week ***//
811
+ if ('weekStart' in inOpts) {
812
+ const wkStart = Number(inOpts.weekStart) % 7;
813
+ if (!isNaN(wkStart)) {
814
+ weekStart = updateWeekStart(wkStart, config, weekNumbers);
815
+ }
816
+ delete inOpts.weekStart;
817
+ }
818
+ if (inOpts.daysOfWeekDisabled) {
819
+ config.daysOfWeekDisabled = inOpts.daysOfWeekDisabled.reduce(sanitizeDOW, []);
820
+ delete inOpts.daysOfWeekDisabled;
821
+ }
822
+ if (inOpts.daysOfWeekHighlighted) {
823
+ config.daysOfWeekHighlighted = inOpts.daysOfWeekHighlighted.reduce(sanitizeDOW, []);
824
+ delete inOpts.daysOfWeekHighlighted;
825
+ }
826
+
827
+ //*** week numbers ***//
828
+ if ('weekNumbers' in inOpts) {
829
+ let method = inOpts.weekNumbers;
830
+ if (method) {
831
+ const getWeekNumber = typeof method === 'function'
832
+ ? (timeValue, startOfWeek) => method(new Date(timeValue), startOfWeek)
833
+ : determineGetWeekMethod((method = parseInt(method, 10)), weekStart);
834
+ if (getWeekNumber) {
835
+ weekNumbers = config.weekNumbers = method;
836
+ config.getWeekNumber = getWeekNumber;
837
+ }
838
+ } else {
839
+ weekNumbers = config.weekNumbers = 0;
840
+ config.getWeekNumber = null;
841
+ }
842
+ delete inOpts.weekNumbers;
843
+ }
844
+
845
+ //*** multi date ***//
846
+ if ('maxNumberOfDates' in inOpts) {
847
+ const maxNumberOfDates = parseInt(inOpts.maxNumberOfDates, 10);
848
+ if (maxNumberOfDates >= 0) {
849
+ config.maxNumberOfDates = maxNumberOfDates;
850
+ config.multidate = maxNumberOfDates !== 1;
851
+ }
852
+ delete inOpts.maxNumberOfDates;
853
+ }
854
+ if (inOpts.dateDelimiter) {
855
+ config.dateDelimiter = String(inOpts.dateDelimiter);
856
+ delete inOpts.dateDelimiter;
857
+ }
858
+
859
+ //*** view ***//
860
+ let newMaxView = maxView;
861
+ if ('maxView' in inOpts) {
862
+ newMaxView = validateViewId(inOpts.maxView, maxView);
863
+ delete inOpts.maxView;
864
+ }
865
+ // ensure max view >= pick level
866
+ newMaxView = pickLevel > newMaxView ? pickLevel : newMaxView;
867
+ if (newMaxView !== maxView) {
868
+ maxView = config.maxView = newMaxView;
869
+ }
870
+
871
+ let newStartView = startView;
872
+ if ('startView' in inOpts) {
873
+ newStartView = validateViewId(inOpts.startView, newStartView);
874
+ delete inOpts.startView;
875
+ }
876
+ // ensure pick level <= start view <= max view
877
+ if (newStartView < pickLevel) {
878
+ newStartView = pickLevel;
879
+ } else if (newStartView > maxView) {
880
+ newStartView = maxView;
881
+ }
882
+ if (newStartView !== startView) {
883
+ config.startView = newStartView;
884
+ }
885
+
886
+ //*** template ***//
887
+ if (inOpts.prevArrow) {
888
+ const prevArrow = parseHTML(inOpts.prevArrow);
889
+ if (prevArrow.childNodes.length > 0) {
890
+ config.prevArrow = prevArrow.childNodes;
891
+ }
892
+ delete inOpts.prevArrow;
893
+ }
894
+ if (inOpts.nextArrow) {
895
+ const nextArrow = parseHTML(inOpts.nextArrow);
896
+ if (nextArrow.childNodes.length > 0) {
897
+ config.nextArrow = nextArrow.childNodes;
898
+ }
899
+ delete inOpts.nextArrow;
900
+ }
901
+
902
+ //*** misc ***//
903
+ if ('disableTouchKeyboard' in inOpts) {
904
+ config.disableTouchKeyboard = 'ontouchstart' in document && !!inOpts.disableTouchKeyboard;
905
+ delete inOpts.disableTouchKeyboard;
906
+ }
907
+ if (inOpts.orientation) {
908
+ const orientation = inOpts.orientation.toLowerCase().split(/\s+/g);
909
+ config.orientation = {
910
+ x: orientation.find(x => (x === 'left' || x === 'right')) || 'auto',
911
+ y: orientation.find(y => (y === 'top' || y === 'bottom')) || 'auto',
912
+ };
913
+ delete inOpts.orientation;
914
+ }
915
+ if ('todayButtonMode' in inOpts) {
916
+ switch(inOpts.todayButtonMode) {
917
+ case 0:
918
+ case 1:
919
+ config.todayButtonMode = inOpts.todayButtonMode;
920
+ }
921
+ delete inOpts.todayButtonMode;
922
+ }
923
+
924
+ //*** copy the rest ***//
925
+ Object.entries(inOpts).forEach(([key, value]) => {
926
+ if (value !== undefined && key in defaultOptions) {
927
+ config[key] = value;
928
+ }
929
+ });
930
+
931
+ return config;
932
+ }
933
+
934
+ const defaultShortcutKeys = {
935
+ show: {key: 'ArrowDown'},
936
+ hide: null,
937
+ toggle: {key: 'Escape'},
938
+ prevButton: {key: 'ArrowLeft', ctrlOrMetaKey: true},
939
+ nextButton: {key: 'ArrowRight', ctrlOrMetaKey: true},
940
+ viewSwitch: {key: 'ArrowUp', ctrlOrMetaKey: true},
941
+ clearButton: {key: 'Backspace', ctrlOrMetaKey: true},
942
+ todayButton: {key: '.', ctrlOrMetaKey: true},
943
+ exitEditMode: {key: 'ArrowDown', ctrlOrMetaKey: true},
944
+ };
945
+
946
+ function createShortcutKeyConfig(options) {
947
+ return Object.keys(defaultShortcutKeys).reduce((keyDefs, shortcut) => {
948
+ const keyDef = options[shortcut] === undefined
949
+ ? defaultShortcutKeys[shortcut]
950
+ : options[shortcut];
951
+ const key = keyDef && keyDef.key;
952
+ if (!key || typeof key !== 'string') {
953
+ return keyDefs;
954
+ }
955
+
956
+ const normalizedDef = {
957
+ key,
958
+ ctrlOrMetaKey: !!(keyDef.ctrlOrMetaKey || keyDef.ctrlKey || keyDef.metaKey),
959
+ };
960
+ if (key.length > 1) {
961
+ normalizedDef.altKey = !!keyDef.altKey;
962
+ normalizedDef.shiftKey = !!keyDef.shiftKey;
963
+ }
964
+ keyDefs[shortcut] = normalizedDef;
965
+ return keyDefs;
966
+ }, {});
967
+ }
968
+
969
+ const pickerTemplate = optimizeTemplateHTML(`<div class="datepicker">
970
+ <div class="datepicker-picker">
971
+ <div class="datepicker-header">
972
+ <div class="datepicker-title"></div>
973
+ <div class="datepicker-controls">
974
+ <button type="button" class="%buttonClass% prev-button prev-btn"></button>
975
+ <button type="button" class="%buttonClass% view-switch"></button>
976
+ <button type="button" class="%buttonClass% next-button next-btn"></button>
977
+ </div>
978
+ </div>
979
+ <div class="datepicker-main"></div>
980
+ <div class="datepicker-footer">
981
+ <div class="datepicker-controls">
982
+ <button type="button" class="%buttonClass% today-button today-btn"></button>
983
+ <button type="button" class="%buttonClass% clear-button clear-btn"></button>
984
+ </div>
985
+ </div>
986
+ </div>
987
+ </div>`);
988
+
989
+ const daysTemplate = optimizeTemplateHTML(`<div class="days">
990
+ <div class="days-of-week">${createTagRepeat('span', 7, {class: 'dow'})}</div>
991
+ <div class="datepicker-grid">${createTagRepeat('span', 42)}</div>
992
+ </div>`);
993
+
994
+ const weekNumbersTemplate = optimizeTemplateHTML(`<div class="week-numbers calendar-weeks">
995
+ <div class="days-of-week"><span class="dow"></span></div>
996
+ <div class="weeks">${createTagRepeat('span', 6, {class: 'week'})}</div>
997
+ </div>`);
998
+
999
+ // Base class of the view classes
1000
+ class View {
1001
+ constructor(picker, config) {
1002
+ Object.assign(this, config, {
1003
+ picker,
1004
+ element: parseHTML(`<div class="datepicker-view"></div>`).firstChild,
1005
+ selected: [],
1006
+ isRangeEnd: !!picker.datepicker.rangeSideIndex,
1007
+ });
1008
+ this.init(this.picker.datepicker.config);
1009
+ }
1010
+
1011
+ init(options) {
1012
+ if ('pickLevel' in options) {
1013
+ this.isMinView = this.id === options.pickLevel;
1014
+ }
1015
+ this.setOptions(options);
1016
+ this.updateFocus();
1017
+ this.updateSelection();
1018
+ }
1019
+
1020
+ prepareForRender(switchLabel, prevButtonDisabled, nextButtonDisabled) {
1021
+ // refresh disabled years on every render in order to clear the ones added
1022
+ // by beforeShow hook at previous render
1023
+ this.disabled = [];
1024
+
1025
+ const picker = this.picker;
1026
+ picker.setViewSwitchLabel(switchLabel);
1027
+ picker.setPrevButtonDisabled(prevButtonDisabled);
1028
+ picker.setNextButtonDisabled(nextButtonDisabled);
1029
+ }
1030
+
1031
+ setDisabled(date, classList) {
1032
+ classList.add('disabled');
1033
+ pushUnique(this.disabled, date);
1034
+ }
1035
+
1036
+ // Execute beforeShow() callback and apply the result to the element
1037
+ // args:
1038
+ performBeforeHook(el, timeValue) {
1039
+ let result = this.beforeShow(new Date(timeValue));
1040
+ switch (typeof result) {
1041
+ case 'boolean':
1042
+ result = {enabled: result};
1043
+ break;
1044
+ case 'string':
1045
+ result = {classes: result};
1046
+ }
1047
+
1048
+ if (result) {
1049
+ const classList = el.classList;
1050
+ if (result.enabled === false) {
1051
+ this.setDisabled(timeValue, classList);
1052
+ }
1053
+ if (result.classes) {
1054
+ const extraClasses = result.classes.split(/\s+/);
1055
+ classList.add(...extraClasses);
1056
+ if (extraClasses.includes('disabled')) {
1057
+ this.setDisabled(timeValue, classList);
1058
+ }
1059
+ }
1060
+ if (result.content) {
1061
+ replaceChildNodes(el, result.content);
1062
+ }
1063
+ }
1064
+ }
1065
+
1066
+ renderCell(el, content, cellVal, date, {selected, range}, outOfScope, extraClasses = []) {
1067
+ el.textContent = content;
1068
+ if (this.isMinView) {
1069
+ el.dataset.date = date;
1070
+ }
1071
+
1072
+ const classList = el.classList;
1073
+ el.className = `datepicker-cell ${this.cellClass}`;
1074
+ if (cellVal < this.first) {
1075
+ classList.add('prev');
1076
+ } else if (cellVal > this.last) {
1077
+ classList.add('next');
1078
+ }
1079
+ classList.add(...extraClasses);
1080
+ if (outOfScope || this.checkDisabled(date, this.id)) {
1081
+ this.setDisabled(date, classList);
1082
+ }
1083
+ if (range) {
1084
+ const [rangeStart, rangeEnd] = range;
1085
+ if (cellVal > rangeStart && cellVal < rangeEnd) {
1086
+ classList.add('range');
1087
+ }
1088
+ if (cellVal === rangeStart) {
1089
+ classList.add('range-start');
1090
+ }
1091
+ if (cellVal === rangeEnd) {
1092
+ classList.add('range-end');
1093
+ }
1094
+ }
1095
+ if (selected.includes(cellVal)) {
1096
+ classList.add('selected');
1097
+ }
1098
+ if (cellVal === this.focused) {
1099
+ classList.add('focused');
1100
+ }
1101
+
1102
+ if (this.beforeShow) {
1103
+ this.performBeforeHook(el, date);
1104
+ }
1105
+ }
1106
+
1107
+ refreshCell(el, cellVal, selected, [rangeStart, rangeEnd]) {
1108
+ const classList = el.classList;
1109
+ classList.remove('range', 'range-start', 'range-end', 'selected', 'focused');
1110
+ if (cellVal > rangeStart && cellVal < rangeEnd) {
1111
+ classList.add('range');
1112
+ }
1113
+ if (cellVal === rangeStart) {
1114
+ classList.add('range-start');
1115
+ }
1116
+ if (cellVal === rangeEnd) {
1117
+ classList.add('range-end');
1118
+ }
1119
+ if (selected.includes(cellVal)) {
1120
+ classList.add('selected');
1121
+ }
1122
+ if (cellVal === this.focused) {
1123
+ classList.add('focused');
1124
+ }
1125
+ }
1126
+
1127
+ changeFocusedCell(cellIndex) {
1128
+ this.grid.querySelectorAll('.focused').forEach((el) => {
1129
+ el.classList.remove('focused');
1130
+ });
1131
+ this.grid.children[cellIndex].classList.add('focused');
1132
+ }
1133
+ }
1134
+
1135
+ class DaysView extends View {
1136
+ constructor(picker) {
1137
+ super(picker, {
1138
+ id: 0,
1139
+ name: 'days',
1140
+ cellClass: 'day',
1141
+ });
1142
+ }
1143
+
1144
+ init(options, onConstruction = true) {
1145
+ if (onConstruction) {
1146
+ const inner = parseHTML(daysTemplate).firstChild;
1147
+ this.dow = inner.firstChild;
1148
+ this.grid = inner.lastChild;
1149
+ this.element.appendChild(inner);
1150
+ }
1151
+ super.init(options);
1152
+ }
1153
+
1154
+ setOptions(options) {
1155
+ let updateDOW;
1156
+
1157
+ if ('minDate' in options) {
1158
+ this.minDate = options.minDate;
1159
+ }
1160
+ if ('maxDate' in options) {
1161
+ this.maxDate = options.maxDate;
1162
+ }
1163
+ if (options.checkDisabled) {
1164
+ this.checkDisabled = options.checkDisabled;
1165
+ }
1166
+ if (options.daysOfWeekDisabled) {
1167
+ this.daysOfWeekDisabled = options.daysOfWeekDisabled;
1168
+ updateDOW = true;
1169
+ }
1170
+ if (options.daysOfWeekHighlighted) {
1171
+ this.daysOfWeekHighlighted = options.daysOfWeekHighlighted;
1172
+ }
1173
+ if ('todayHighlight' in options) {
1174
+ this.todayHighlight = options.todayHighlight;
1175
+ }
1176
+ if ('weekStart' in options) {
1177
+ this.weekStart = options.weekStart;
1178
+ this.weekEnd = options.weekEnd;
1179
+ updateDOW = true;
1180
+ }
1181
+ if (options.locale) {
1182
+ const locale = this.locale = options.locale;
1183
+ this.dayNames = locale.daysMin;
1184
+ this.switchLabelFormat = locale.titleFormat;
1185
+ updateDOW = true;
1186
+ }
1187
+ if ('beforeShowDay' in options) {
1188
+ this.beforeShow = typeof options.beforeShowDay === 'function'
1189
+ ? options.beforeShowDay
1190
+ : undefined;
1191
+ }
1192
+
1193
+ if ('weekNumbers' in options) {
1194
+ if (options.weekNumbers && !this.weekNumbers) {
1195
+ const weeksElem = parseHTML(weekNumbersTemplate).firstChild;
1196
+ this.weekNumbers = {
1197
+ element: weeksElem,
1198
+ dow: weeksElem.firstChild,
1199
+ weeks: weeksElem.lastChild,
1200
+ };
1201
+ this.element.insertBefore(weeksElem, this.element.firstChild);
1202
+ } else if (this.weekNumbers && !options.weekNumbers) {
1203
+ this.element.removeChild(this.weekNumbers.element);
1204
+ this.weekNumbers = null;
1205
+ }
1206
+ }
1207
+
1208
+ if ('getWeekNumber' in options) {
1209
+ this.getWeekNumber = options.getWeekNumber;
1210
+ }
1211
+
1212
+ if ('showDaysOfWeek' in options) {
1213
+ if (options.showDaysOfWeek) {
1214
+ showElement(this.dow);
1215
+ if (this.weekNumbers) {
1216
+ showElement(this.weekNumbers.dow);
1217
+ }
1218
+ } else {
1219
+ hideElement(this.dow);
1220
+ if (this.weekNumbers) {
1221
+ hideElement(this.weekNumbers.dow);
1222
+ }
1223
+ }
1224
+ }
1225
+
1226
+ // update days-of-week when locale, daysOfweekDisabled or weekStart is changed
1227
+ if (updateDOW) {
1228
+ Array.from(this.dow.children).forEach((el, index) => {
1229
+ const dow = (this.weekStart + index) % 7;
1230
+ el.textContent = this.dayNames[dow];
1231
+ el.className = this.daysOfWeekDisabled.includes(dow) ? 'dow disabled' : 'dow';
1232
+ });
1233
+ }
1234
+ }
1235
+
1236
+ // Apply update on the focused date to view's settings
1237
+ updateFocus() {
1238
+ const viewDate = new Date(this.picker.viewDate);
1239
+ const viewYear = viewDate.getFullYear();
1240
+ const viewMonth = viewDate.getMonth();
1241
+ const firstOfMonth = dateValue(viewYear, viewMonth, 1);
1242
+ const start = dayOfTheWeekOf(firstOfMonth, this.weekStart, this.weekStart);
1243
+
1244
+ this.first = firstOfMonth;
1245
+ this.last = dateValue(viewYear, viewMonth + 1, 0);
1246
+ this.start = start;
1247
+ this.focused = this.picker.viewDate;
1248
+ }
1249
+
1250
+ // Apply update on the selected dates to view's settings
1251
+ updateSelection() {
1252
+ const {dates, rangepicker} = this.picker.datepicker;
1253
+ this.selected = dates;
1254
+ if (rangepicker) {
1255
+ this.range = rangepicker.dates;
1256
+ }
1257
+ }
1258
+
1259
+ // Update the entire view UI
1260
+ render() {
1261
+ // update today marker on ever render
1262
+ this.today = this.todayHighlight ? today() : undefined;
1263
+
1264
+ this.prepareForRender(
1265
+ formatDate(this.focused, this.switchLabelFormat, this.locale),
1266
+ this.first <= this.minDate,
1267
+ this.last >= this.maxDate
1268
+ );
1269
+
1270
+ if (this.weekNumbers) {
1271
+ const weekStart = this.weekStart;
1272
+ const startOfWeek = dayOfTheWeekOf(this.first, weekStart, weekStart);
1273
+ Array.from(this.weekNumbers.weeks.children).forEach((el, index) => {
1274
+ const dateOfWeekStart = addWeeks(startOfWeek, index);
1275
+ el.textContent = this.getWeekNumber(dateOfWeekStart, weekStart);
1276
+ if (index > 3) {
1277
+ el.classList[dateOfWeekStart > this.last ? 'add' : 'remove']('next');
1278
+ }
1279
+ });
1280
+ }
1281
+ Array.from(this.grid.children).forEach((el, index) => {
1282
+ const current = addDays(this.start, index);
1283
+ const dateObj = new Date(current);
1284
+ const day = dateObj.getDay();
1285
+ const extraClasses = [];
1286
+
1287
+ if (this.today === current) {
1288
+ extraClasses.push('today');
1289
+ }
1290
+ if (this.daysOfWeekHighlighted.includes(day)) {
1291
+ extraClasses.push('highlighted');
1292
+ }
1293
+
1294
+ this.renderCell(
1295
+ el,
1296
+ dateObj.getDate(),
1297
+ current,
1298
+ current,
1299
+ this,
1300
+ current < this.minDate
1301
+ || current > this.maxDate
1302
+ || this.daysOfWeekDisabled.includes(day),
1303
+ extraClasses
1304
+ );
1305
+ });
1306
+ }
1307
+
1308
+ // Update the view UI by applying the changes of selected and focused items
1309
+ refresh() {
1310
+ const range = this.range || [];
1311
+ Array.from(this.grid.children).forEach((el) => {
1312
+ this.refreshCell(el, Number(el.dataset.date), this.selected, range);
1313
+ });
1314
+ }
1315
+
1316
+ // Update the view UI by applying the change of focused item
1317
+ refreshFocus() {
1318
+ this.changeFocusedCell(Math.round((this.focused - this.start) / 86400000));
1319
+ }
1320
+ }
1321
+
1322
+ function computeMonthRange(range, thisYear) {
1323
+ if (!range || !range[0] || !range[1]) {
1324
+ return;
1325
+ }
1326
+
1327
+ const [[startY, startM], [endY, endM]] = range;
1328
+ if (startY > thisYear || endY < thisYear) {
1329
+ return;
1330
+ }
1331
+ return [
1332
+ startY === thisYear ? startM : -1,
1333
+ endY === thisYear ? endM : 12,
1334
+ ];
1335
+ }
1336
+
1337
+ class MonthsView extends View {
1338
+ constructor(picker) {
1339
+ super(picker, {
1340
+ id: 1,
1341
+ name: 'months',
1342
+ cellClass: 'month',
1343
+ });
1344
+ }
1345
+
1346
+ init(options, onConstruction = true) {
1347
+ if (onConstruction) {
1348
+ this.grid = this.element;
1349
+ this.element.classList.add('months', 'datepicker-grid');
1350
+ this.grid.appendChild(parseHTML(createTagRepeat('span', 12, {'data-month': ix => ix})));
1351
+ this.first = 0;
1352
+ this.last = 11;
1353
+ }
1354
+ super.init(options);
1355
+ }
1356
+
1357
+ setOptions(options) {
1358
+ if (options.locale) {
1359
+ this.monthNames = options.locale.monthsShort;
1360
+ }
1361
+ if ('minDate' in options) {
1362
+ if (options.minDate === undefined) {
1363
+ this.minYear = this.minMonth = this.minDate = undefined;
1364
+ } else {
1365
+ const minDateObj = new Date(options.minDate);
1366
+ this.minYear = minDateObj.getFullYear();
1367
+ this.minMonth = minDateObj.getMonth();
1368
+ this.minDate = minDateObj.setDate(1);
1369
+ }
1370
+ }
1371
+ if ('maxDate' in options) {
1372
+ if (options.maxDate === undefined) {
1373
+ this.maxYear = this.maxMonth = this.maxDate = undefined;
1374
+ } else {
1375
+ const maxDateObj = new Date(options.maxDate);
1376
+ this.maxYear = maxDateObj.getFullYear();
1377
+ this.maxMonth = maxDateObj.getMonth();
1378
+ this.maxDate = dateValue(this.maxYear, this.maxMonth + 1, 0);
1379
+ }
1380
+ }
1381
+ if (options.checkDisabled) {
1382
+ this.checkDisabled = this.isMinView || options.datesDisabled === null
1383
+ ? options.checkDisabled
1384
+ : () => false;
1385
+ }
1386
+ if ('beforeShowMonth' in options) {
1387
+ this.beforeShow = typeof options.beforeShowMonth === 'function'
1388
+ ? options.beforeShowMonth
1389
+ : undefined;
1390
+ }
1391
+ }
1392
+
1393
+ // Update view's settings to reflect the viewDate set on the picker
1394
+ updateFocus() {
1395
+ const viewDate = new Date(this.picker.viewDate);
1396
+ this.year = viewDate.getFullYear();
1397
+ this.focused = viewDate.getMonth();
1398
+ }
1399
+
1400
+ // Update view's settings to reflect the selected dates
1401
+ updateSelection() {
1402
+ const {dates, rangepicker} = this.picker.datepicker;
1403
+ this.selected = dates.reduce((selected, timeValue) => {
1404
+ const date = new Date(timeValue);
1405
+ const year = date.getFullYear();
1406
+ const month = date.getMonth();
1407
+ if (selected[year] === undefined) {
1408
+ selected[year] = [month];
1409
+ } else {
1410
+ pushUnique(selected[year], month);
1411
+ }
1412
+ return selected;
1413
+ }, {});
1414
+ if (rangepicker && rangepicker.dates) {
1415
+ this.range = rangepicker.dates.map(timeValue => {
1416
+ const date = new Date(timeValue);
1417
+ return isNaN(date) ? undefined : [date.getFullYear(), date.getMonth()];
1418
+ });
1419
+ }
1420
+ }
1421
+
1422
+ // Update the entire view UI
1423
+ render() {
1424
+ this.prepareForRender(
1425
+ this.year,
1426
+ this.year <= this.minYear,
1427
+ this.year >= this.maxYear
1428
+ );
1429
+
1430
+ const selected = this.selected[this.year] || [];
1431
+ const yrOutOfRange = this.year < this.minYear || this.year > this.maxYear;
1432
+ const isMinYear = this.year === this.minYear;
1433
+ const isMaxYear = this.year === this.maxYear;
1434
+ const range = computeMonthRange(this.range, this.year);
1435
+
1436
+ Array.from(this.grid.children).forEach((el, index) => {
1437
+ const date = regularizeDate(new Date(this.year, index, 1), 1, this.isRangeEnd);
1438
+
1439
+ this.renderCell(
1440
+ el,
1441
+ this.monthNames[index],
1442
+ index,
1443
+ date,
1444
+ {selected, range},
1445
+ yrOutOfRange
1446
+ || isMinYear && index < this.minMonth
1447
+ || isMaxYear && index > this.maxMonth
1448
+ );
1449
+ });
1450
+ }
1451
+
1452
+ // Update the view UI by applying the changes of selected and focused items
1453
+ refresh() {
1454
+ const selected = this.selected[this.year] || [];
1455
+ const range = computeMonthRange(this.range, this.year) || [];
1456
+ Array.from(this.grid.children).forEach((el, index) => {
1457
+ this.refreshCell(el, index, selected, range);
1458
+ });
1459
+ }
1460
+
1461
+ // Update the view UI by applying the change of focused item
1462
+ refreshFocus() {
1463
+ this.changeFocusedCell(this.focused);
1464
+ }
1465
+ }
1466
+
1467
+ function toTitleCase(word) {
1468
+ return [...word].reduce((str, ch, ix) => str += ix ? ch : ch.toUpperCase(), '');
1469
+ }
1470
+
1471
+ // Class representing the years and decades view elements
1472
+ class YearsView extends View {
1473
+ constructor(picker, config) {
1474
+ super(picker, config);
1475
+ }
1476
+
1477
+ init(options, onConstruction = true) {
1478
+ if (onConstruction) {
1479
+ this.navStep = this.step * 10;
1480
+ this.beforeShowOption = `beforeShow${toTitleCase(this.cellClass)}`;
1481
+ this.grid = this.element;
1482
+ this.element.classList.add(this.name, 'datepicker-grid');
1483
+ this.grid.appendChild(parseHTML(createTagRepeat('span', 12)));
1484
+ }
1485
+ super.init(options);
1486
+ }
1487
+
1488
+ setOptions(options) {
1489
+ if ('minDate' in options) {
1490
+ if (options.minDate === undefined) {
1491
+ this.minYear = this.minDate = undefined;
1492
+ } else {
1493
+ this.minYear = startOfYearPeriod(options.minDate, this.step);
1494
+ this.minDate = dateValue(this.minYear, 0, 1);
1495
+ }
1496
+ }
1497
+ if ('maxDate' in options) {
1498
+ if (options.maxDate === undefined) {
1499
+ this.maxYear = this.maxDate = undefined;
1500
+ } else {
1501
+ this.maxYear = startOfYearPeriod(options.maxDate, this.step);
1502
+ this.maxDate = dateValue(this.maxYear, 11, 31);
1503
+ }
1504
+ }
1505
+ if (options.checkDisabled) {
1506
+ this.checkDisabled = this.isMinView || options.datesDisabled === null
1507
+ ? options.checkDisabled
1508
+ : () => false;
1509
+ }
1510
+ if (this.beforeShowOption in options) {
1511
+ const beforeShow = options[this.beforeShowOption];
1512
+ this.beforeShow = typeof beforeShow === 'function' ? beforeShow : undefined;
1513
+ }
1514
+ }
1515
+
1516
+ // Update view's settings to reflect the viewDate set on the picker
1517
+ updateFocus() {
1518
+ const viewDate = new Date(this.picker.viewDate);
1519
+ const first = startOfYearPeriod(viewDate, this.navStep);
1520
+ const last = first + 9 * this.step;
1521
+
1522
+ this.first = first;
1523
+ this.last = last;
1524
+ this.start = first - this.step;
1525
+ this.focused = startOfYearPeriod(viewDate, this.step);
1526
+ }
1527
+
1528
+ // Update view's settings to reflect the selected dates
1529
+ updateSelection() {
1530
+ const {dates, rangepicker} = this.picker.datepicker;
1531
+ this.selected = dates.reduce((years, timeValue) => {
1532
+ return pushUnique(years, startOfYearPeriod(timeValue, this.step));
1533
+ }, []);
1534
+ if (rangepicker && rangepicker.dates) {
1535
+ this.range = rangepicker.dates.map(timeValue => {
1536
+ if (timeValue !== undefined) {
1537
+ return startOfYearPeriod(timeValue, this.step);
1538
+ }
1539
+ });
1540
+ }
1541
+ }
1542
+
1543
+ // Update the entire view UI
1544
+ render() {
1545
+ this.prepareForRender(
1546
+ `${this.first}-${this.last}`,
1547
+ this.first <= this.minYear,
1548
+ this.last >= this.maxYear
1549
+ );
1550
+
1551
+ Array.from(this.grid.children).forEach((el, index) => {
1552
+ const current = this.start + (index * this.step);
1553
+ const date = regularizeDate(new Date(current, 0, 1), 2, this.isRangeEnd);
1554
+
1555
+ el.dataset.year = current;
1556
+ this.renderCell(
1557
+ el,
1558
+ current,
1559
+ current,
1560
+ date,
1561
+ this,
1562
+ current < this.minYear || current > this.maxYear
1563
+ );
1564
+ });
1565
+ }
1566
+
1567
+ // Update the view UI by applying the changes of selected and focused items
1568
+ refresh() {
1569
+ const range = this.range || [];
1570
+ Array.from(this.grid.children).forEach((el) => {
1571
+ this.refreshCell(el, Number(el.textContent), this.selected, range);
1572
+ });
1573
+ }
1574
+
1575
+ // Update the view UI by applying the change of focused item
1576
+ refreshFocus() {
1577
+ this.changeFocusedCell(Math.round((this.focused - this.start) / this.step));
1578
+ }
1579
+ }
1580
+
1581
+ function triggerDatepickerEvent(datepicker, type) {
1582
+ const detail = {
1583
+ date: datepicker.getDate(),
1584
+ viewDate: new Date(datepicker.picker.viewDate),
1585
+ viewId: datepicker.picker.currentView.id,
1586
+ datepicker,
1587
+ };
1588
+ datepicker.element.dispatchEvent(new CustomEvent(type, {detail}));
1589
+ }
1590
+
1591
+ // direction: -1 (to previous), 1 (to next)
1592
+ function goToPrevOrNext(datepicker, direction) {
1593
+ const {config, picker} = datepicker;
1594
+ const {currentView, viewDate} = picker;
1595
+ let newViewDate;
1596
+ switch (currentView.id) {
1597
+ case 0:
1598
+ newViewDate = addMonths(viewDate, direction);
1599
+ break;
1600
+ case 1:
1601
+ newViewDate = addYears(viewDate, direction);
1602
+ break;
1603
+ default:
1604
+ newViewDate = addYears(viewDate, direction * currentView.navStep);
1605
+ }
1606
+ newViewDate = limitToRange(newViewDate, config.minDate, config.maxDate);
1607
+ picker.changeFocus(newViewDate).render();
1608
+ }
1609
+
1610
+ function switchView(datepicker) {
1611
+ const viewId = datepicker.picker.currentView.id;
1612
+ if (viewId === datepicker.config.maxView) {
1613
+ return;
1614
+ }
1615
+ datepicker.picker.changeView(viewId + 1).render();
1616
+ }
1617
+
1618
+ function clearSelection(datepicker) {
1619
+ datepicker.setDate({clear: true});
1620
+ }
1621
+
1622
+ function goToOrSelectToday(datepicker) {
1623
+ const currentDate = today();
1624
+ if (datepicker.config.todayButtonMode === 1) {
1625
+ datepicker.setDate(currentDate, {forceRefresh: true, viewDate: currentDate});
1626
+ } else {
1627
+ datepicker.setFocusedDate(currentDate, true);
1628
+ }
1629
+ }
1630
+
1631
+ function unfocus(datepicker) {
1632
+ const onBlur = () => {
1633
+ if (datepicker.config.updateOnBlur) {
1634
+ datepicker.update({revert: true});
1635
+ } else {
1636
+ datepicker.refresh('input');
1637
+ }
1638
+ datepicker.hide();
1639
+ };
1640
+ const element = datepicker.element;
1641
+
1642
+ if (isActiveElement(element)) {
1643
+ element.addEventListener('blur', onBlur, {once: true});
1644
+ } else {
1645
+ onBlur();
1646
+ }
1647
+ }
1648
+
1649
+ function goToSelectedMonthOrYear(datepicker, selection) {
1650
+ const picker = datepicker.picker;
1651
+ const viewDate = new Date(picker.viewDate);
1652
+ const viewId = picker.currentView.id;
1653
+ const newDate = viewId === 1
1654
+ ? addMonths(viewDate, selection - viewDate.getMonth())
1655
+ : addYears(viewDate, selection - viewDate.getFullYear());
1656
+
1657
+ picker.changeFocus(newDate).changeView(viewId - 1).render();
1658
+ }
1659
+
1660
+ function onClickViewSwitch(datepicker) {
1661
+ switchView(datepicker);
1662
+ }
1663
+
1664
+ function onClickPrevButton(datepicker) {
1665
+ goToPrevOrNext(datepicker, -1);
1666
+ }
1667
+
1668
+ function onClickNextButton(datepicker) {
1669
+ goToPrevOrNext(datepicker, 1);
1670
+ }
1671
+
1672
+ // For the picker's main block to delegete the events from `datepicker-cell`s
1673
+ function onClickView(datepicker, ev) {
1674
+ const target = findElementInEventPath(ev, '.datepicker-cell');
1675
+ if (!target || target.classList.contains('disabled')) {
1676
+ return;
1677
+ }
1678
+
1679
+ const {id, isMinView} = datepicker.picker.currentView;
1680
+ const data = target.dataset;
1681
+ if (isMinView) {
1682
+ datepicker.setDate(Number(data.date));
1683
+ } else if (id === 1) {
1684
+ goToSelectedMonthOrYear(datepicker, Number(data.month));
1685
+ } else {
1686
+ goToSelectedMonthOrYear(datepicker, Number(data.year));
1687
+ }
1688
+ }
1689
+
1690
+ function onMousedownPicker(ev) {
1691
+ ev.preventDefault();
1692
+ }
1693
+
1694
+ const orientClasses = ['left', 'top', 'right', 'bottom'].reduce((obj, key) => {
1695
+ obj[key] = `datepicker-orient-${key}`;
1696
+ return obj;
1697
+ }, {});
1698
+ const toPx = num => num ? `${num}px` : num;
1699
+
1700
+ function processPickerOptions(picker, options) {
1701
+ if ('title' in options) {
1702
+ if (options.title) {
1703
+ picker.controls.title.textContent = options.title;
1704
+ showElement(picker.controls.title);
1705
+ } else {
1706
+ picker.controls.title.textContent = '';
1707
+ hideElement(picker.controls.title);
1708
+ }
1709
+ }
1710
+ if (options.prevArrow) {
1711
+ const prevButton = picker.controls.prevButton;
1712
+ emptyChildNodes(prevButton);
1713
+ options.prevArrow.forEach((node) => {
1714
+ prevButton.appendChild(node.cloneNode(true));
1715
+ });
1716
+ }
1717
+ if (options.nextArrow) {
1718
+ const nextButton = picker.controls.nextButton;
1719
+ emptyChildNodes(nextButton);
1720
+ options.nextArrow.forEach((node) => {
1721
+ nextButton.appendChild(node.cloneNode(true));
1722
+ });
1723
+ }
1724
+ if (options.locale) {
1725
+ picker.controls.todayButton.textContent = options.locale.today;
1726
+ picker.controls.clearButton.textContent = options.locale.clear;
1727
+ }
1728
+ if ('todayButton' in options) {
1729
+ if (options.todayButton) {
1730
+ showElement(picker.controls.todayButton);
1731
+ } else {
1732
+ hideElement(picker.controls.todayButton);
1733
+ }
1734
+ }
1735
+ if ('minDate' in options || 'maxDate' in options) {
1736
+ const {minDate, maxDate} = picker.datepicker.config;
1737
+ picker.controls.todayButton.disabled = !isInRange(today(), minDate, maxDate);
1738
+ }
1739
+ if ('clearButton' in options) {
1740
+ if (options.clearButton) {
1741
+ showElement(picker.controls.clearButton);
1742
+ } else {
1743
+ hideElement(picker.controls.clearButton);
1744
+ }
1745
+ }
1746
+ }
1747
+
1748
+ // Compute view date to reset, which will be...
1749
+ // - the last item of the selected dates or defaultViewDate if no selection
1750
+ // - limitted to minDate or maxDate if it exceeds the range
1751
+ function computeResetViewDate(datepicker) {
1752
+ const {dates, config, rangeSideIndex} = datepicker;
1753
+ const viewDate = dates.length > 0
1754
+ ? lastItemOf(dates)
1755
+ : regularizeDate(config.defaultViewDate, config.pickLevel, rangeSideIndex);
1756
+ return limitToRange(viewDate, config.minDate, config.maxDate);
1757
+ }
1758
+
1759
+ // Change current view's view date
1760
+ function setViewDate(picker, newDate) {
1761
+ if (!('_oldViewDate' in picker) && newDate !== picker.viewDate) {
1762
+ picker._oldViewDate = picker.viewDate;
1763
+ }
1764
+ picker.viewDate = newDate;
1765
+
1766
+ // return whether the new date is in different period on time from the one
1767
+ // displayed in the current view
1768
+ // when true, the view needs to be re-rendered on the next UI refresh.
1769
+ const {id, year, first, last} = picker.currentView;
1770
+ const viewYear = new Date(newDate).getFullYear();
1771
+ switch (id) {
1772
+ case 0:
1773
+ return newDate < first || newDate > last;
1774
+ case 1:
1775
+ return viewYear !== year;
1776
+ default:
1777
+ return viewYear < first || viewYear > last;
1778
+ }
1779
+ }
1780
+
1781
+ function getTextDirection(el) {
1782
+ return window.getComputedStyle(el).direction;
1783
+ }
1784
+
1785
+ // find the closet scrollable ancestor elemnt under the body
1786
+ function findScrollParents(el) {
1787
+ const parent = getParent(el);
1788
+ if (parent === document.body || !parent) {
1789
+ return;
1790
+ }
1791
+
1792
+ // checking overflow only is enough because computed overflow cannot be
1793
+ // visible or a combination of visible and other when either axis is set
1794
+ // to other than visible.
1795
+ // (Setting one axis to other than 'visible' while the other is 'visible'
1796
+ // results in the other axis turning to 'auto')
1797
+ return window.getComputedStyle(parent).overflow !== 'visible'
1798
+ ? parent
1799
+ : findScrollParents(parent);
1800
+ }
1801
+
1802
+ // Class representing the picker UI
1803
+ class Picker {
1804
+ constructor(datepicker) {
1805
+ const {config, inputField} = this.datepicker = datepicker;
1806
+
1807
+ const template = pickerTemplate.replace(/%buttonClass%/g, config.buttonClass);
1808
+ const element = this.element = parseHTML(template).firstChild;
1809
+ const [header, main, footer] = element.firstChild.children;
1810
+ const title = header.firstElementChild;
1811
+ const [prevButton, viewSwitch, nextButton] = header.lastElementChild.children;
1812
+ const [todayButton, clearButton] = footer.firstChild.children;
1813
+ const controls = {
1814
+ title,
1815
+ prevButton,
1816
+ viewSwitch,
1817
+ nextButton,
1818
+ todayButton,
1819
+ clearButton,
1820
+ };
1821
+ this.main = main;
1822
+ this.controls = controls;
1823
+
1824
+ const elementClass = inputField ? 'dropdown' : 'inline';
1825
+ element.classList.add(`datepicker-${elementClass}`);
1826
+
1827
+ processPickerOptions(this, config);
1828
+ this.viewDate = computeResetViewDate(datepicker);
1829
+
1830
+ // set up event listeners
1831
+ registerListeners(datepicker, [
1832
+ [element, 'mousedown', onMousedownPicker],
1833
+ [main, 'click', onClickView.bind(null, datepicker)],
1834
+ [controls.viewSwitch, 'click', onClickViewSwitch.bind(null, datepicker)],
1835
+ [controls.prevButton, 'click', onClickPrevButton.bind(null, datepicker)],
1836
+ [controls.nextButton, 'click', onClickNextButton.bind(null, datepicker)],
1837
+ [controls.todayButton, 'click', goToOrSelectToday.bind(null, datepicker)],
1838
+ [controls.clearButton, 'click', clearSelection.bind(null, datepicker)],
1839
+ ]);
1840
+
1841
+ // set up views
1842
+ this.views = [
1843
+ new DaysView(this),
1844
+ new MonthsView(this),
1845
+ new YearsView(this, {id: 2, name: 'years', cellClass: 'year', step: 1}),
1846
+ new YearsView(this, {id: 3, name: 'decades', cellClass: 'decade', step: 10}),
1847
+ ];
1848
+ this.currentView = this.views[config.startView];
1849
+
1850
+ this.currentView.render();
1851
+ this.main.appendChild(this.currentView.element);
1852
+ if (config.container) {
1853
+ config.container.appendChild(this.element);
1854
+ } else {
1855
+ inputField.after(this.element);
1856
+ }
1857
+ }
1858
+
1859
+ setOptions(options) {
1860
+ processPickerOptions(this, options);
1861
+ this.views.forEach((view) => {
1862
+ view.init(options, false);
1863
+ });
1864
+ this.currentView.render();
1865
+ }
1866
+
1867
+ detach() {
1868
+ this.element.remove();
1869
+ }
1870
+
1871
+ show() {
1872
+ if (this.active) {
1873
+ return;
1874
+ }
1875
+
1876
+ const {datepicker, element} = this;
1877
+ const inputField = datepicker.inputField;
1878
+ if (inputField) {
1879
+ // ensure picker's direction matches input's
1880
+ const inputDirection = getTextDirection(inputField);
1881
+ if (inputDirection !== getTextDirection(getParent(element))) {
1882
+ element.dir = inputDirection;
1883
+ } else if (element.dir) {
1884
+ element.removeAttribute('dir');
1885
+ }
1886
+
1887
+ element.style.visibility = 'hidden';
1888
+ element.classList.add('active');
1889
+ this.place();
1890
+ element.style.visibility = '';
1891
+
1892
+ if (datepicker.config.disableTouchKeyboard) {
1893
+ inputField.blur();
1894
+ }
1895
+ } else {
1896
+ element.classList.add('active');
1897
+ }
1898
+ this.active = true;
1899
+ triggerDatepickerEvent(datepicker, 'show');
1900
+ }
1901
+
1902
+ hide() {
1903
+ if (!this.active) {
1904
+ return;
1905
+ }
1906
+ this.datepicker.exitEditMode();
1907
+ this.element.classList.remove('active');
1908
+ this.active = false;
1909
+ triggerDatepickerEvent(this.datepicker, 'hide');
1910
+ }
1911
+
1912
+ place() {
1913
+ const {classList, offsetParent, style} = this.element;
1914
+ const {config, inputField} = this.datepicker;
1915
+ const {
1916
+ width: calendarWidth,
1917
+ height: calendarHeight,
1918
+ } = this.element.getBoundingClientRect();
1919
+ const {
1920
+ left: inputLeft,
1921
+ top: inputTop,
1922
+ right: inputRight,
1923
+ bottom: inputBottom,
1924
+ width: inputWidth,
1925
+ height: inputHeight
1926
+ } = inputField.getBoundingClientRect();
1927
+ let {x: orientX, y: orientY} = config.orientation;
1928
+ let left = inputLeft;
1929
+ let top = inputTop;
1930
+
1931
+ // caliculate offsetLeft/Top of inputField
1932
+ if (offsetParent === document.body || !offsetParent) {
1933
+ left += window.scrollX;
1934
+ top += window.scrollY;
1935
+ } else {
1936
+ const offsetParentRect = offsetParent.getBoundingClientRect();
1937
+ left -= offsetParentRect.left - offsetParent.scrollLeft;
1938
+ top -= offsetParentRect.top - offsetParent.scrollTop;
1939
+ }
1940
+
1941
+ // caliculate the boundaries of the visible area that contains inputField
1942
+ const scrollParent = findScrollParents(inputField);
1943
+ let scrollAreaLeft = 0;
1944
+ let scrollAreaTop = 0;
1945
+ let {
1946
+ clientWidth: scrollAreaRight,
1947
+ clientHeight: scrollAreaBottom,
1948
+ } = document.documentElement;
1949
+
1950
+ if (scrollParent) {
1951
+ const scrollParentRect = scrollParent.getBoundingClientRect();
1952
+ if (scrollParentRect.top > 0) {
1953
+ scrollAreaTop = scrollParentRect.top;
1954
+ }
1955
+ if (scrollParentRect.left > 0) {
1956
+ scrollAreaLeft = scrollParentRect.left;
1957
+ }
1958
+ if (scrollParentRect.right < scrollAreaRight) {
1959
+ scrollAreaRight = scrollParentRect.right;
1960
+ }
1961
+ if (scrollParentRect.bottom < scrollAreaBottom) {
1962
+ scrollAreaBottom = scrollParentRect.bottom;
1963
+ }
1964
+ }
1965
+
1966
+ // determine the horizontal orientation and left position
1967
+ let adjustment = 0;
1968
+ if (orientX === 'auto') {
1969
+ if (inputLeft < scrollAreaLeft) {
1970
+ orientX = 'left';
1971
+ adjustment = scrollAreaLeft - inputLeft;
1972
+ } else if (inputLeft + calendarWidth > scrollAreaRight) {
1973
+ orientX = 'right';
1974
+ if (scrollAreaRight < inputRight) {
1975
+ adjustment = scrollAreaRight - inputRight;
1976
+ }
1977
+ } else if (getTextDirection(inputField) === 'rtl') {
1978
+ orientX = inputRight - calendarWidth < scrollAreaLeft ? 'left' : 'right';
1979
+ } else {
1980
+ orientX = 'left';
1981
+ }
1982
+ }
1983
+ if (orientX === 'right') {
1984
+ left += inputWidth - calendarWidth;
1985
+ }
1986
+ left += adjustment;
1987
+
1988
+ // determine the vertical orientation and top position
1989
+ if (orientY === 'auto') {
1990
+ if (inputTop - calendarHeight > scrollAreaTop) {
1991
+ orientY = inputBottom + calendarHeight > scrollAreaBottom ? 'top' : 'bottom';
1992
+ } else {
1993
+ orientY = 'bottom';
1994
+ }
1995
+ }
1996
+ if (orientY === 'top') {
1997
+ top -= calendarHeight;
1998
+ } else {
1999
+ top += inputHeight;
2000
+ }
2001
+
2002
+ classList.remove(...Object.values(orientClasses));
2003
+ classList.add(orientClasses[orientX], orientClasses[orientY]);
2004
+
2005
+ style.left = toPx(left);
2006
+ style.top = toPx(top);
2007
+ }
2008
+
2009
+ setViewSwitchLabel(labelText) {
2010
+ this.controls.viewSwitch.textContent = labelText;
2011
+ }
2012
+
2013
+ setPrevButtonDisabled(disabled) {
2014
+ this.controls.prevButton.disabled = disabled;
2015
+ }
2016
+
2017
+ setNextButtonDisabled(disabled) {
2018
+ this.controls.nextButton.disabled = disabled;
2019
+ }
2020
+
2021
+ changeView(viewId) {
2022
+ const currentView = this.currentView;
2023
+ if (viewId !== currentView.id) {
2024
+ if (!this._oldView) {
2025
+ this._oldView = currentView;
2026
+ }
2027
+ this.currentView = this.views[viewId];
2028
+ this._renderMethod = 'render';
2029
+ }
2030
+ return this;
2031
+ }
2032
+
2033
+ // Change the focused date (view date)
2034
+ changeFocus(newViewDate) {
2035
+ this._renderMethod = setViewDate(this, newViewDate) ? 'render' : 'refreshFocus';
2036
+ this.views.forEach((view) => {
2037
+ view.updateFocus();
2038
+ });
2039
+ return this;
2040
+ }
2041
+
2042
+ // Apply the change of the selected dates
2043
+ update(viewDate = undefined) {
2044
+ const newViewDate = viewDate === undefined
2045
+ ? computeResetViewDate(this.datepicker)
2046
+ : viewDate;
2047
+ this._renderMethod = setViewDate(this, newViewDate) ? 'render' : 'refresh';
2048
+ this.views.forEach((view) => {
2049
+ view.updateFocus();
2050
+ view.updateSelection();
2051
+ });
2052
+ return this;
2053
+ }
2054
+
2055
+ // Refresh the picker UI
2056
+ render(quickRender = true) {
2057
+ const {currentView, datepicker, _oldView: oldView} = this;
2058
+ const oldViewDate = new Date(this._oldViewDate);
2059
+ const renderMethod = (quickRender && this._renderMethod) || 'render';
2060
+ delete this._oldView;
2061
+ delete this._oldViewDate;
2062
+ delete this._renderMethod;
2063
+
2064
+ currentView[renderMethod]();
2065
+ if (oldView) {
2066
+ this.main.replaceChild(currentView.element, oldView.element);
2067
+ triggerDatepickerEvent(datepicker, 'changeView');
2068
+ }
2069
+ if (!isNaN(oldViewDate)) {
2070
+ const newViewDate = new Date(this.viewDate);
2071
+ if (newViewDate.getFullYear() !== oldViewDate.getFullYear()) {
2072
+ triggerDatepickerEvent(datepicker, 'changeYear');
2073
+ }
2074
+ if (newViewDate.getMonth() !== oldViewDate.getMonth()) {
2075
+ triggerDatepickerEvent(datepicker, 'changeMonth');
2076
+ }
2077
+ }
2078
+ }
2079
+ }
2080
+
2081
+ // Find the closest date that doesn't meet the condition for unavailable date
2082
+ // Returns undefined if no available date is found
2083
+ // addFn: function to calculate the next date
2084
+ // - args: time value, amount
2085
+ // increase: amount to pass to addFn
2086
+ // testFn: function to test the unavailability of the date
2087
+ // - args: time value; return: true if unavailable
2088
+ function findNextAvailableOne(date, addFn, increase, testFn, min, max) {
2089
+ if (!isInRange(date, min, max)) {
2090
+ return;
2091
+ }
2092
+ if (testFn(date)) {
2093
+ const newDate = addFn(date, increase);
2094
+ return findNextAvailableOne(newDate, addFn, increase, testFn, min, max);
2095
+ }
2096
+ return date;
2097
+ }
2098
+
2099
+ // direction: -1 (left/up), 1 (right/down)
2100
+ // vertical: true for up/down, false for left/right
2101
+ function moveByArrowKey(datepicker, direction, vertical) {
2102
+ const picker = datepicker.picker;
2103
+ const currentView = picker.currentView;
2104
+ const step = currentView.step || 1;
2105
+ let viewDate = picker.viewDate;
2106
+ let addFn;
2107
+ switch (currentView.id) {
2108
+ case 0:
2109
+ viewDate = addDays(viewDate, vertical ? direction * 7 : direction);
2110
+ addFn = addDays;
2111
+ break;
2112
+ case 1:
2113
+ viewDate = addMonths(viewDate, vertical ? direction * 4 : direction);
2114
+ addFn = addMonths;
2115
+ break;
2116
+ default:
2117
+ viewDate = addYears(viewDate, direction * (vertical ? 4 : 1) * step);
2118
+ addFn = addYears;
2119
+ }
2120
+ viewDate = findNextAvailableOne(
2121
+ viewDate,
2122
+ addFn,
2123
+ direction < 0 ? -step : step,
2124
+ (date) => currentView.disabled.includes(date),
2125
+ currentView.minDate,
2126
+ currentView.maxDate
2127
+ );
2128
+ if (viewDate !== undefined) {
2129
+ picker.changeFocus(viewDate).render();
2130
+ }
2131
+ }
2132
+
2133
+ function onKeydown(datepicker, ev) {
2134
+ const {config, picker, editMode} = datepicker;
2135
+ const active = picker.active;
2136
+ const {key, altKey, shiftKey} = ev;
2137
+ const ctrlOrMetaKey = ev.ctrlKey || ev.metaKey;
2138
+ const cancelEvent = () => {
2139
+ ev.preventDefault();
2140
+ ev.stopPropagation();
2141
+ };
2142
+
2143
+ // tab/enter keys should not be taken by shortcut keys
2144
+ if (key === 'Tab') {
2145
+ unfocus(datepicker);
2146
+ return;
2147
+ }
2148
+ if (key === 'Enter') {
2149
+ if (!active) {
2150
+ datepicker.update();
2151
+ } else if (editMode) {
2152
+ datepicker.exitEditMode({update: true, autohide: config.autohide});
2153
+ } else {
2154
+ const currentView = picker.currentView;
2155
+ if (currentView.isMinView) {
2156
+ datepicker.setDate(picker.viewDate);
2157
+ } else {
2158
+ picker.changeView(currentView.id - 1).render();
2159
+ cancelEvent();
2160
+ }
2161
+ }
2162
+ return;
2163
+ }
2164
+
2165
+ const shortcutKeys = config.shortcutKeys;
2166
+ const keyInfo = {key, ctrlOrMetaKey, altKey, shiftKey};
2167
+ const shortcut = Object.keys(shortcutKeys).find((item) => {
2168
+ const keyDef = shortcutKeys[item];
2169
+ return !Object.keys(keyDef).find(prop => keyDef[prop] !== keyInfo[prop]);
2170
+ });
2171
+ if (shortcut) {
2172
+ let action;
2173
+ if (shortcut === 'toggle') {
2174
+ action = shortcut;
2175
+ } else if (editMode) {
2176
+ if (shortcut === 'exitEditMode') {
2177
+ action = shortcut;
2178
+ }
2179
+ } else if (active) {
2180
+ if (shortcut === 'hide') {
2181
+ action = shortcut;
2182
+ } else if (shortcut === 'prevButton') {
2183
+ action = [goToPrevOrNext, [datepicker, -1]];
2184
+ } else if (shortcut === 'nextButton') {
2185
+ action = [goToPrevOrNext, [datepicker, 1]];
2186
+ } else if (shortcut === 'viewSwitch') {
2187
+ action = [switchView, [datepicker]];
2188
+ } else if (config.clearButton && shortcut === 'clearButton') {
2189
+ action = [clearSelection, [datepicker]];
2190
+ } else if (config.todayButton && shortcut === 'todayButton') {
2191
+ action = [goToOrSelectToday, [datepicker]];
2192
+ }
2193
+ } else if (shortcut === 'show') {
2194
+ action = shortcut;
2195
+ }
2196
+ if (action) {
2197
+ if (Array.isArray(action)) {
2198
+ action[0].apply(null, action[1]);
2199
+ } else {
2200
+ datepicker[action]();
2201
+ }
2202
+ cancelEvent();
2203
+ return;
2204
+ }
2205
+ }
2206
+
2207
+ // perform as a regular <input> when picker in hidden or in edit mode
2208
+ if (!active || editMode) {
2209
+ return;
2210
+ }
2211
+
2212
+ const handleArrowKeyPress = (direction, vertical) => {
2213
+ if (shiftKey || ctrlOrMetaKey || altKey) {
2214
+ datepicker.enterEditMode();
2215
+ } else {
2216
+ moveByArrowKey(datepicker, direction, vertical);
2217
+ ev.preventDefault();
2218
+ }
2219
+ };
2220
+
2221
+ if (key === 'ArrowLeft') {
2222
+ handleArrowKeyPress(-1, false);
2223
+ } else if (key === 'ArrowRight') {
2224
+ handleArrowKeyPress(1, false);
2225
+ } else if (key === 'ArrowUp') {
2226
+ handleArrowKeyPress(-1, true);
2227
+ } else if (key === 'ArrowDown') {
2228
+ handleArrowKeyPress(1, true);
2229
+ } else if (
2230
+ key === 'Backspace'
2231
+ || key === 'Delete'
2232
+ // When autofill is performed, Chromium-based browsers trigger fake
2233
+ // keydown/keyup events that don't have the `key` property (on Edge,
2234
+ // keyup only) in addition to the input event. Therefore, we need to
2235
+ // check the existence of `key`'s value before checking the length.
2236
+ // (issue #144)
2237
+ || (key && key.length === 1 && !ctrlOrMetaKey)
2238
+ ) {
2239
+ datepicker.enterEditMode();
2240
+ }
2241
+ }
2242
+
2243
+ function onFocus(datepicker) {
2244
+ if (datepicker.config.showOnFocus && !datepicker._showing) {
2245
+ datepicker.show();
2246
+ }
2247
+ }
2248
+
2249
+ // for the prevention for entering edit mode while getting focus on click
2250
+ function onMousedown(datepicker, ev) {
2251
+ const el = ev.target;
2252
+ if (datepicker.picker.active || datepicker.config.showOnClick) {
2253
+ el._active = isActiveElement(el);
2254
+ el._clicking = setTimeout(() => {
2255
+ delete el._active;
2256
+ delete el._clicking;
2257
+ }, 2000);
2258
+ }
2259
+ }
2260
+
2261
+ function onClickInput(datepicker, ev) {
2262
+ const el = ev.target;
2263
+ if (!el._clicking) {
2264
+ return;
2265
+ }
2266
+ clearTimeout(el._clicking);
2267
+ delete el._clicking;
2268
+
2269
+ if (el._active) {
2270
+ datepicker.enterEditMode();
2271
+ }
2272
+ delete el._active;
2273
+
2274
+ if (datepicker.config.showOnClick) {
2275
+ datepicker.show();
2276
+ }
2277
+ }
2278
+
2279
+ function onPaste(datepicker, ev) {
2280
+ if (ev.clipboardData.types.includes('text/plain')) {
2281
+ datepicker.enterEditMode();
2282
+ }
2283
+ }
2284
+
2285
+ // for the `document` to delegate the events from outside the picker/input field
2286
+ function onClickOutside(datepicker, ev) {
2287
+ const {element, picker} = datepicker;
2288
+ // check both picker's and input's activeness to make updateOnBlur work in
2289
+ // the cases where...
2290
+ // - picker is hidden by ESC key press → input stays focused
2291
+ // - input is unfocused by closing mobile keyboard → piker is kept shown
2292
+ if (!picker.active && !isActiveElement(element)) {
2293
+ return;
2294
+ }
2295
+ const pickerElem = picker.element;
2296
+ if (findElementInEventPath(ev, el => el === element || el === pickerElem)) {
2297
+ return;
2298
+ }
2299
+ unfocus(datepicker);
2300
+ }
2301
+
2302
+ function stringifyDates(dates, config) {
2303
+ return dates
2304
+ .map(dt => formatDate(dt, config.format, config.locale))
2305
+ .join(config.dateDelimiter);
2306
+ }
2307
+
2308
+ // parse input dates and create an array of time values for selection
2309
+ // returns undefined if there are no valid dates in inputDates
2310
+ // when origDates (current selection) is passed, the function works to mix
2311
+ // the input dates into the current selection
2312
+ function processInputDates(datepicker, inputDates, clear = false) {
2313
+ if (inputDates.length === 0) {
2314
+ // empty input is considered valid unless origiDates is passed
2315
+ return clear ? [] : undefined;
2316
+ }
2317
+
2318
+ const {config, dates: origDates, rangeSideIndex} = datepicker;
2319
+ const {pickLevel, maxNumberOfDates} = config;
2320
+ let newDates = inputDates.reduce((dates, dt) => {
2321
+ let date = parseDate(dt, config.format, config.locale);
2322
+ if (date === undefined) {
2323
+ return dates;
2324
+ }
2325
+ // adjust to 1st of the month/Jan 1st of the year
2326
+ // or to the last day of the monh/Dec 31st of the year if the datepicker
2327
+ // is the range-end picker of a rangepicker
2328
+ date = regularizeDate(date, pickLevel, rangeSideIndex);
2329
+ if (
2330
+ isInRange(date, config.minDate, config.maxDate)
2331
+ && !dates.includes(date)
2332
+ && !config.checkDisabled(date, pickLevel)
2333
+ && (pickLevel > 0 || !config.daysOfWeekDisabled.includes(new Date(date).getDay()))
2334
+ ) {
2335
+ dates.push(date);
2336
+ }
2337
+ return dates;
2338
+ }, []);
2339
+ if (newDates.length === 0) {
2340
+ return;
2341
+ }
2342
+ if (config.multidate && !clear) {
2343
+ // get the synmetric difference between origDates and newDates
2344
+ newDates = newDates.reduce((dates, date) => {
2345
+ if (!origDates.includes(date)) {
2346
+ dates.push(date);
2347
+ }
2348
+ return dates;
2349
+ }, origDates.filter(date => !newDates.includes(date)));
2350
+ }
2351
+ // do length check always because user can input multiple dates regardless of the mode
2352
+ return maxNumberOfDates && newDates.length > maxNumberOfDates
2353
+ ? newDates.slice(maxNumberOfDates * -1)
2354
+ : newDates;
2355
+ }
2356
+
2357
+ // refresh the UI elements
2358
+ // modes: 1: input only, 2, picker only, 3 both
2359
+ function refreshUI(datepicker, mode = 3, quickRender = true, viewDate = undefined) {
2360
+ const {config, picker, inputField} = datepicker;
2361
+ if (mode & 2) {
2362
+ const newView = picker.active ? config.pickLevel : config.startView;
2363
+ picker.update(viewDate).changeView(newView).render(quickRender);
2364
+ }
2365
+ if (mode & 1 && inputField) {
2366
+ inputField.value = stringifyDates(datepicker.dates, config);
2367
+ }
2368
+ }
2369
+
2370
+ function setDate(datepicker, inputDates, options) {
2371
+ const config = datepicker.config;
2372
+ let {clear, render, autohide, revert, forceRefresh, viewDate} = options;
2373
+ if (render === undefined) {
2374
+ render = true;
2375
+ }
2376
+ if (!render) {
2377
+ autohide = forceRefresh = false;
2378
+ } else if (autohide === undefined) {
2379
+ autohide = config.autohide;
2380
+ }
2381
+ viewDate = parseDate(viewDate, config.format, config.locale);
2382
+
2383
+ const newDates = processInputDates(datepicker, inputDates, clear);
2384
+ if (!newDates && !revert) {
2385
+ return;
2386
+ }
2387
+ if (newDates && newDates.toString() !== datepicker.dates.toString()) {
2388
+ datepicker.dates = newDates;
2389
+ refreshUI(datepicker, render ? 3 : 1, true, viewDate);
2390
+ triggerDatepickerEvent(datepicker, 'changeDate');
2391
+ } else {
2392
+ refreshUI(datepicker, forceRefresh ? 3 : 1, true, viewDate);
2393
+ }
2394
+
2395
+ if (autohide) {
2396
+ datepicker.hide();
2397
+ }
2398
+ }
2399
+
2400
+ function getOutputConverter(datepicker, format) {
2401
+ return format
2402
+ ? date => formatDate(date, format, datepicker.config.locale)
2403
+ : date => new Date(date);
2404
+ }
2405
+
2406
+ /**
2407
+ * Class representing a date picker
2408
+ */
2409
+ class Datepicker {
2410
+ /**
2411
+ * Create a date picker
2412
+ * @param {Element} element - element to bind a date picker
2413
+ * @param {Object} [options] - config options
2414
+ * @param {DateRangePicker} [rangepicker] - DateRangePicker instance the
2415
+ * date picker belongs to. Use this only when creating date picker as a part
2416
+ * of date range picker
2417
+ */
2418
+ constructor(element, options = {}, rangepicker = undefined) {
2419
+ element.datepicker = this;
2420
+ this.element = element;
2421
+ this.dates = [];
2422
+
2423
+ // initialize config
2424
+ const config = this.config = Object.assign({
2425
+ buttonClass: (options.buttonClass && String(options.buttonClass)) || 'button',
2426
+ container: null,
2427
+ defaultViewDate: today(),
2428
+ maxDate: undefined,
2429
+ minDate: undefined,
2430
+ }, processOptions(defaultOptions, this));
2431
+
2432
+ // configure by type
2433
+ let inputField;
2434
+ if (element.tagName === 'INPUT') {
2435
+ inputField = this.inputField = element;
2436
+ inputField.classList.add('datepicker-input');
2437
+ if (options.container) {
2438
+ // omit string type check because it doesn't guarantee to avoid errors
2439
+ // (invalid selector string causes abend with sytax error)
2440
+ config.container = options.container instanceof HTMLElement
2441
+ ? options.container
2442
+ : document.querySelector(options.container);
2443
+ }
2444
+ } else {
2445
+ config.container = element;
2446
+ }
2447
+ if (rangepicker) {
2448
+ // check validiry
2449
+ const index = rangepicker.inputs.indexOf(inputField);
2450
+ const datepickers = rangepicker.datepickers;
2451
+ if (index < 0 || index > 1 || !Array.isArray(datepickers)) {
2452
+ throw Error('Invalid rangepicker object.');
2453
+ }
2454
+ // attach itaelf to the rangepicker here so that processInputDates() can
2455
+ // determine if this is the range-end picker of the rangepicker while
2456
+ // setting inital values when pickLevel > 0
2457
+ datepickers[index] = this;
2458
+ this.rangepicker = rangepicker;
2459
+ this.rangeSideIndex = index;
2460
+ }
2461
+
2462
+ // set up config
2463
+ this._options = options;
2464
+ Object.assign(config, processOptions(options, this));
2465
+ config.shortcutKeys = createShortcutKeyConfig(options.shortcutKeys || {});
2466
+
2467
+ // process initial value
2468
+ const initialDates = stringToArray(
2469
+ element.value || element.dataset.date,
2470
+ config.dateDelimiter
2471
+ );
2472
+ delete element.dataset.date;
2473
+ const inputDateValues = processInputDates(this, initialDates);
2474
+ if (inputDateValues && inputDateValues.length > 0) {
2475
+ this.dates = inputDateValues;
2476
+ }
2477
+ if (inputField) {
2478
+ inputField.value = stringifyDates(this.dates, config);
2479
+ }
2480
+
2481
+ // set up picekr element
2482
+ const picker = this.picker = new Picker(this);
2483
+
2484
+ const keydownListener = [element, 'keydown', onKeydown.bind(null, this)];
2485
+ if (inputField) {
2486
+ registerListeners(this, [
2487
+ keydownListener,
2488
+ [inputField, 'focus', onFocus.bind(null, this)],
2489
+ [inputField, 'mousedown', onMousedown.bind(null, this)],
2490
+ [inputField, 'click', onClickInput.bind(null, this)],
2491
+ [inputField, 'paste', onPaste.bind(null, this)],
2492
+ // To detect a click on outside, just listening to mousedown is enough,
2493
+ // no need to listen to touchstart.
2494
+ // Actually, listening to touchstart can be a problem because, while
2495
+ // mousedown is fired only on tapping but not on swiping/pinching,
2496
+ // touchstart is fired on swiping/pinching as well.
2497
+ // (issue #95)
2498
+ [document, 'mousedown', onClickOutside.bind(null, this)],
2499
+ [window, 'resize', picker.place.bind(picker)]
2500
+ ]);
2501
+ } else {
2502
+ registerListeners(this, [keydownListener]);
2503
+ this.show();
2504
+ }
2505
+ }
2506
+
2507
+ /**
2508
+ * Format Date object or time value in given format and language
2509
+ * @param {Date|Number} date - date or time value to format
2510
+ * @param {String|Object} format - format string or object that contains
2511
+ * toDisplay() custom formatter, whose signature is
2512
+ * - args:
2513
+ * - date: {Date} - Date instance of the date passed to the method
2514
+ * - format: {Object} - the format object passed to the method
2515
+ * - locale: {Object} - locale for the language specified by `lang`
2516
+ * - return:
2517
+ * {String} formatted date
2518
+ * @param {String} [lang=en] - language code for the locale to use
2519
+ * @return {String} formatted date
2520
+ */
2521
+ static formatDate(date, format, lang) {
2522
+ return formatDate(date, format, lang && locales[lang] || locales.en);
2523
+ }
2524
+
2525
+ /**
2526
+ * Parse date string
2527
+ * @param {String|Date|Number} dateStr - date string, Date object or time
2528
+ * value to parse
2529
+ * @param {String|Object} format - format string or object that contains
2530
+ * toValue() custom parser, whose signature is
2531
+ * - args:
2532
+ * - dateStr: {String|Date|Number} - the dateStr passed to the method
2533
+ * - format: {Object} - the format object passed to the method
2534
+ * - locale: {Object} - locale for the language specified by `lang`
2535
+ * - return:
2536
+ * {Date|Number} parsed date or its time value
2537
+ * @param {String} [lang=en] - language code for the locale to use
2538
+ * @return {Number} time value of parsed date
2539
+ */
2540
+ static parseDate(dateStr, format, lang) {
2541
+ return parseDate(dateStr, format, lang && locales[lang] || locales.en);
2542
+ }
2543
+
2544
+ /**
2545
+ * @type {Object} - Installed locales in `[languageCode]: localeObject` format
2546
+ * en`:_English (US)_ is pre-installed.
2547
+ */
2548
+ static get locales() {
2549
+ return locales;
2550
+ }
2551
+
2552
+ /**
2553
+ * @type {Boolean} - Whether the picker element is shown. `true` whne shown
2554
+ */
2555
+ get active() {
2556
+ return !!(this.picker && this.picker.active);
2557
+ }
2558
+
2559
+ /**
2560
+ * @type {HTMLDivElement} - DOM object of picker element
2561
+ */
2562
+ get pickerElement() {
2563
+ return this.picker ? this.picker.element : undefined;
2564
+ }
2565
+
2566
+ /**
2567
+ * Set new values to the config options
2568
+ * @param {Object} options - config options to update
2569
+ */
2570
+ setOptions(options) {
2571
+ const newOptions = processOptions(options, this);
2572
+ Object.assign(this._options, options);
2573
+ Object.assign(this.config, newOptions);
2574
+ this.picker.setOptions(newOptions);
2575
+
2576
+ refreshUI(this, 3);
2577
+ }
2578
+
2579
+ /**
2580
+ * Show the picker element
2581
+ */
2582
+ show() {
2583
+ if (this.inputField) {
2584
+ const {config, inputField} = this;
2585
+ if (inputField.disabled || (inputField.readOnly && !config.enableOnReadonly)) {
2586
+ return;
2587
+ }
2588
+ if (!isActiveElement(inputField) && !config.disableTouchKeyboard) {
2589
+ this._showing = true;
2590
+ inputField.focus();
2591
+ delete this._showing;
2592
+ }
2593
+ }
2594
+ this.picker.show();
2595
+ }
2596
+
2597
+ /**
2598
+ * Hide the picker element
2599
+ * Not available on inline picker
2600
+ */
2601
+ hide() {
2602
+ if (!this.inputField) {
2603
+ return;
2604
+ }
2605
+ this.picker.hide();
2606
+ this.picker.update().changeView(this.config.startView).render();
2607
+ }
2608
+
2609
+ /**
2610
+ * Toggle the display of the picker element
2611
+ * Not available on inline picker
2612
+ *
2613
+ * Unlike hide(), the picker does not return to the start view when hiding.
2614
+ */
2615
+ toggle() {
2616
+ if (!this.picker.active) {
2617
+ this.show();
2618
+ } else if (this.inputField) {
2619
+ this.picker.hide();
2620
+ }
2621
+ }
2622
+
2623
+ /**
2624
+ * Destroy the Datepicker instance
2625
+ * @return {Detepicker} - the instance destroyed
2626
+ */
2627
+ destroy() {
2628
+ this.hide();
2629
+ unregisterListeners(this);
2630
+ this.picker.detach();
2631
+ const element = this.element;
2632
+ element.classList.remove('datepicker-input');
2633
+ delete element.datepicker;
2634
+ return this;
2635
+ }
2636
+
2637
+ /**
2638
+ * Get the selected date(s)
2639
+ *
2640
+ * The method returns a Date object of selected date by default, and returns
2641
+ * an array of selected dates in multidate mode. If format string is passed,
2642
+ * it returns date string(s) formatted in given format.
2643
+ *
2644
+ * @param {String} [format] - format string to stringify the date(s)
2645
+ * @return {Date|String|Date[]|String[]} - selected date(s), or if none is
2646
+ * selected, empty array in multidate mode and undefined in sigledate mode
2647
+ */
2648
+ getDate(format = undefined) {
2649
+ const callback = getOutputConverter(this, format);
2650
+
2651
+ if (this.config.multidate) {
2652
+ return this.dates.map(callback);
2653
+ }
2654
+ if (this.dates.length > 0) {
2655
+ return callback(this.dates[0]);
2656
+ }
2657
+ }
2658
+
2659
+ /**
2660
+ * Set selected date(s)
2661
+ *
2662
+ * In multidate mode, you can pass multiple dates as a series of arguments
2663
+ * or an array. (Since each date is parsed individually, the type of the
2664
+ * dates doesn't have to be the same.)
2665
+ * The given dates are used to toggle the select status of each date. The
2666
+ * number of selected dates is kept from exceeding the length set to
2667
+ * maxNumberOfDates.
2668
+ *
2669
+ * With clear: true option, the method can be used to clear the selection
2670
+ * and to replace the selection instead of toggling in multidate mode.
2671
+ * If the option is passed with no date arguments or an empty dates array,
2672
+ * it works as "clear" (clear the selection then set nothing), and if the
2673
+ * option is passed with new dates to select, it works as "replace" (clear
2674
+ * the selection then set the given dates)
2675
+ *
2676
+ * When render: false option is used, the method omits re-rendering the
2677
+ * picker element. In this case, you need to call refresh() method later in
2678
+ * order for the picker element to reflect the changes. The input field is
2679
+ * refreshed always regardless of this option.
2680
+ *
2681
+ * When invalid (unparsable, repeated, disabled or out-of-range) dates are
2682
+ * passed, the method ignores them and applies only valid ones. In the case
2683
+ * that all the given dates are invalid, which is distinguished from passing
2684
+ * no dates, the method considers it as an error and leaves the selection
2685
+ * untouched. (The input field also remains untouched unless revert: true
2686
+ * option is used.)
2687
+ * Replacing the selection with the same date(s) also causes a similar
2688
+ * situation. In both cases, the method does not refresh the picker element
2689
+ * unless forceRefresh: true option is used.
2690
+ *
2691
+ * If viewDate option is used, the method changes the focused date to the
2692
+ * specified date instead of the last item of the selection.
2693
+ *
2694
+ * @param {...(Date|Number|String)|Array} [dates] - Date strings, Date
2695
+ * objects, time values or mix of those for new selection
2696
+ * @param {Object} [options] - function options
2697
+ * - clear: {boolean} - Whether to clear the existing selection
2698
+ * defualt: false
2699
+ * - render: {boolean} - Whether to re-render the picker element
2700
+ * default: true
2701
+ * - autohide: {boolean} - Whether to hide the picker element after re-render
2702
+ * Ignored when used with render: false
2703
+ * default: config.autohide
2704
+ * - revert: {boolean} - Whether to refresh the input field when all the
2705
+ * passed dates are invalid
2706
+ * default: false
2707
+ * - forceRefresh: {boolean} - Whether to refresh the picker element when
2708
+ * passed dates don't change the existing selection
2709
+ * default: false
2710
+ * - viewDate: {Date|Number|String} - Date to be focused after setiing date(s)
2711
+ * default: The last item of the resulting selection, or defaultViewDate
2712
+ * config option if none is selected
2713
+ */
2714
+ setDate(...args) {
2715
+ const dates = [...args];
2716
+ const opts = {};
2717
+ const lastArg = lastItemOf(args);
2718
+ if (
2719
+ lastArg
2720
+ && typeof lastArg === 'object'
2721
+ && !Array.isArray(lastArg)
2722
+ && !(lastArg instanceof Date)
2723
+ ) {
2724
+ Object.assign(opts, dates.pop());
2725
+ }
2726
+
2727
+ const inputDates = Array.isArray(dates[0]) ? dates[0] : dates;
2728
+ setDate(this, inputDates, opts);
2729
+ }
2730
+
2731
+ /**
2732
+ * Update the selected date(s) with input field's value
2733
+ * Not available on inline picker
2734
+ *
2735
+ * The input field will be refreshed with properly formatted date string.
2736
+ *
2737
+ * In the case that all the entered dates are invalid (unparsable, repeated,
2738
+ * disabled or out-of-range), which is distinguished from empty input field,
2739
+ * the method leaves the input field untouched as well as the selection by
2740
+ * default. If revert: true option is used in this case, the input field is
2741
+ * refreshed with the existing selection.
2742
+ * The method also doesn't refresh the picker element in this case and when
2743
+ * the entered dates are the same as the existing selection. If
2744
+ * forceRefresh: true option is used, the picker element is refreshed in
2745
+ * these cases too.
2746
+ *
2747
+ * @param {Object} [options] - function options
2748
+ * - autohide: {boolean} - whether to hide the picker element after refresh
2749
+ * default: false
2750
+ * - revert: {boolean} - Whether to refresh the input field when all the
2751
+ * passed dates are invalid
2752
+ * default: false
2753
+ * - forceRefresh: {boolean} - Whether to refresh the picer element when
2754
+ * input field's value doesn't change the existing selection
2755
+ * default: false
2756
+ */
2757
+ update(options = undefined) {
2758
+ if (!this.inputField) {
2759
+ return;
2760
+ }
2761
+
2762
+ const opts = Object.assign(options || {}, {clear: true, render: true, viewDate: undefined});
2763
+ const inputDates = stringToArray(this.inputField.value, this.config.dateDelimiter);
2764
+ setDate(this, inputDates, opts);
2765
+ }
2766
+
2767
+ /**
2768
+ * Get the focused date
2769
+ *
2770
+ * The method returns a Date object of focused date by default. If format
2771
+ * string is passed, it returns date string formatted in given format.
2772
+ *
2773
+ * @param {String} [format] - format string to stringify the date
2774
+ * @return {Date|String} - focused date (viewDate)
2775
+ */
2776
+ getFocusedDate(format = undefined) {
2777
+ return getOutputConverter(this, format)(this.picker.viewDate);
2778
+ }
2779
+
2780
+ /**
2781
+ * Set focused date
2782
+ *
2783
+ * By default, the method updates the focus on the view shown at the time,
2784
+ * or the one set to the startView config option if the picker is hidden.
2785
+ * When resetView: true is passed, the view displayed is changed to the
2786
+ * pickLevel config option's if the picker is shown.
2787
+ *
2788
+ * @param {Date|Number|String} viewDate - date string, Date object, time
2789
+ * values of the date to focus
2790
+ * @param {Boolean} [resetView] - whether to change the view to pickLevel
2791
+ * config option's when the picker is shown. Ignored when the picker is
2792
+ * hidden
2793
+ */
2794
+ setFocusedDate(viewDate, resetView = false) {
2795
+ const {config, picker, active, rangeSideIndex} = this;
2796
+ const pickLevel = config.pickLevel;
2797
+ const newViewDate = parseDate(viewDate, config.format, config.locale);
2798
+ if (newViewDate === undefined) {
2799
+ return;
2800
+ }
2801
+
2802
+ picker.changeFocus(regularizeDate(newViewDate, pickLevel, rangeSideIndex));
2803
+ if (active && resetView) {
2804
+ picker.changeView(pickLevel);
2805
+ }
2806
+ picker.render();
2807
+ }
2808
+
2809
+ /**
2810
+ * Refresh the picker element and the associated input field
2811
+ * @param {String} [target] - target item when refreshing one item only
2812
+ * 'picker' or 'input'
2813
+ * @param {Boolean} [forceRender] - whether to re-render the picker element
2814
+ * regardless of its state instead of optimized refresh
2815
+ */
2816
+ refresh(target = undefined, forceRender = false) {
2817
+ if (target && typeof target !== 'string') {
2818
+ forceRender = target;
2819
+ target = undefined;
2820
+ }
2821
+
2822
+ let mode;
2823
+ if (target === 'picker') {
2824
+ mode = 2;
2825
+ } else if (target === 'input') {
2826
+ mode = 1;
2827
+ } else {
2828
+ mode = 3;
2829
+ }
2830
+ refreshUI(this, mode, !forceRender);
2831
+ }
2832
+
2833
+ /**
2834
+ * Enter edit mode
2835
+ * Not available on inline picker or when the picker element is hidden
2836
+ */
2837
+ enterEditMode() {
2838
+ const inputField = this.inputField;
2839
+ if (!inputField || inputField.readOnly || !this.picker.active || this.editMode) {
2840
+ return;
2841
+ }
2842
+ this.editMode = true;
2843
+ inputField.classList.add('in-edit');
2844
+ }
2845
+
2846
+ /**
2847
+ * Exit from edit mode
2848
+ * Not available on inline picker
2849
+ * @param {Object} [options] - function options
2850
+ * - update: {boolean} - whether to call update() after exiting
2851
+ * If false, input field is revert to the existing selection
2852
+ * default: false
2853
+ */
2854
+ exitEditMode(options = undefined) {
2855
+ if (!this.inputField || !this.editMode) {
2856
+ return;
2857
+ }
2858
+ const opts = Object.assign({update: false}, options);
2859
+ delete this.editMode;
2860
+ this.inputField.classList.remove('in-edit');
2861
+ if (opts.update) {
2862
+ this.update(opts);
2863
+ }
2864
+ }
2865
+ }
2866
+
2867
+ var DatepickerTypeEnum;
2868
+ (function (DatepickerTypeEnum) {
2869
+ DatepickerTypeEnum[DatepickerTypeEnum["date"] = 0] = "date";
2870
+ DatepickerTypeEnum[DatepickerTypeEnum["month"] = 1] = "month";
2871
+ DatepickerTypeEnum[DatepickerTypeEnum["year"] = 2] = "year";
2872
+ DatepickerTypeEnum[DatepickerTypeEnum["week"] = 3] = "week";
2873
+ })(DatepickerTypeEnum || (DatepickerTypeEnum = {}));
2874
+
2875
+ var _a, _b, _c;
2876
+ const browserLanguage = (_b = (_a = window === null || window === void 0 ? void 0 : window.navigator) === null || _a === void 0 ? void 0 : _a.language) !== null && _b !== void 0 ? _b : 'en';
2877
+ const getDefaultDate = (type, selectedDate) => {
2878
+ const date = selectedDate ? dayjs_min(selectedDate).toDate() : today$1();
2879
+ return type === 'week' ? dayjs_min(date).startOf('isoWeek').toDate() : date;
2880
+ };
2881
+ function getDatepickerOptions(type, selectedDate) {
2882
+ const config = {
2883
+ enableOnReadonly: false,
2884
+ pickLevel: DatepickerTypeEnum[type],
2885
+ todayButton: true,
2886
+ todayButtonMode: 1,
2887
+ todayHighlight: true,
2888
+ weekStart: 1,
2889
+ language: 'browser',
2890
+ defaultViewDate: getDefaultDate(type, selectedDate)
2891
+ };
2892
+ return config;
2893
+ }
2894
+ function daysForLocale(weekday = 'long') {
2895
+ const date = new Date();
2896
+ const firstDayOfWeek = new Date(date.setUTCDate(date.getUTCDate() - date.getUTCDay()));
2897
+ const format = new Intl.DateTimeFormat(browserLanguage, { weekday }).format;
2898
+ return [...Array(7).keys()].map(day => format(firstDayOfWeek.setUTCDate(firstDayOfWeek.getUTCDate() + day)));
2899
+ }
2900
+ function monthsForLocale(month = 'long') {
2901
+ const date = new Date();
2902
+ const format = new Intl.DateTimeFormat(browserLanguage, { month }).format;
2903
+ return [...Array(12).keys()].map(month => format(date.setUTCMonth(month)));
2904
+ }
2905
+ if ((_c = Datepicker === null || Datepicker === void 0 ? void 0 : Datepicker.locales) === null || _c === void 0 ? void 0 : _c.browser) {
2906
+ Datepicker.locales.browser = {
2907
+ days: daysForLocale('long'),
2908
+ daysShort: daysForLocale('short'),
2909
+ daysMin: daysForLocale('narrow'),
2910
+ months: monthsForLocale('long'),
2911
+ monthsShort: monthsForLocale('short'),
2912
+ today: catI18nRegistry.t('input.today')
2913
+ };
2914
+ }
2915
+
2916
+ const catDatepickerCss = ".datepicker{width:min-content}.datepicker:not(.active){display:none}.datepicker-dropdown{position:absolute;z-index:20;padding-top:4px}.datepicker-dropdown.datepicker-orient-top{padding-top:0;padding-bottom:4px}.datepicker-picker{display:flex;flex-direction:column;border-radius:var(--cat-border-radius-m, 0.25rem);background-color:white}.datepicker-dropdown .datepicker-picker{box-shadow:0 4px 6px -2px rgba(27, 31, 38, 0.03), 0 12px 16px -4px rgba(27, 31, 38, 0.08)}.datepicker-main{flex:auto;padding:2px}.datepicker-footer{box-shadow:none;background-color:transparent}.datepicker-title{box-shadow:none;background-color:hsl(0, 0%, 96%);padding:0.375rem 0.75rem;text-align:center;font-weight:700}.datepicker-controls{display:flex}.datepicker-header .datepicker-controls{padding:2px 2px 0}.datepicker-controls .button{display:inline-flex;position:relative;align-items:center;justify-content:center;margin:0;border:1px solid rgb(var(--cat-border-color, 235, 236, 240));border-radius:var(--cat-border-radius-m, 0.25rem);box-shadow:none;background-color:hsl(0, 0%, 100%);cursor:pointer;padding:calc(0.375em - 1px) 0.75em;height:2.25em;vertical-align:top;text-align:center;line-height:1.5;white-space:nowrap;color:hsl(0, 0%, 21%);font-size:0.9375rem}.datepicker-controls .button:focus,.datepicker-controls .button:active{outline:none}.datepicker-controls .button:hover{border-color:#b8b8b8;color:hsl(0, 0%, 21%)}.datepicker-controls .button:focus{border-color:hsl(217, 71%, 53%);color:hsl(0, 0%, 21%)}.datepicker-controls .button:focus:not(:active){box-shadow:0 0 0 0.125em rgba(50, 115, 220, 0.25)}.datepicker-controls .button:active{border-color:#474747;color:hsl(0, 0%, 21%)}.datepicker-controls .button[disabled]{cursor:not-allowed}.datepicker-header .datepicker-controls .button{border-color:transparent;font-weight:bold}.datepicker-header .datepicker-controls .button:hover{background-color:#f2f4f7}.datepicker-header .datepicker-controls .button:active{background-color:#f2f4f7}.datepicker-footer .datepicker-controls .button{flex:auto;margin:calc(0.375rem - 1px) 0.375rem;border-radius:var(--cat-border-radius-s, 0.125rem);font-size:0.875rem}.datepicker-controls .view-switch{flex:auto}.datepicker-controls .prev-button,.datepicker-controls .next-button{padding-right:0.375rem;padding-left:0.375rem;flex:0 0 14.2857142857%}.datepicker-controls .prev-button.disabled,.datepicker-controls .next-button.disabled{visibility:hidden}.datepicker-view,.datepicker-grid{display:flex}.datepicker-view{align-items:stretch;width:17.5rem}.datepicker-grid{flex-wrap:wrap;flex:auto}.datepicker .days{display:flex;flex-direction:column;flex:auto}.datepicker .days-of-week{display:flex}.datepicker .week-numbers{display:flex;flex-direction:column;flex:0 0 9.6774193548%}.datepicker .weeks{display:flex;flex-direction:column;align-items:stretch;flex:auto}.datepicker span{display:flex;align-items:center;justify-content:center;border-radius:var(--cat-border-radius-m, 0.25rem);cursor:default;-webkit-touch-callout:none;user-select:none}.datepicker .dow{height:2rem;font-size:0.875rem0.9375rem/2;font-weight:700}.datepicker .week{flex:auto;color:rgb(var(--cat-font-color-muted, 81, 92, 108));font-size:0.875rem}.datepicker-cell,.datepicker .days .dow{flex-basis:14.2857142857%}.datepicker-cell{height:2.5rem}.datepicker-cell:not(.day){flex-basis:25%;height:5rem}.datepicker-cell:not(.disabled):hover{background-color:transparent;cursor:pointer}.datepicker-cell.focused:not(.selected){background-color:#f2f4f7}.datepicker-cell.selected,.datepicker-cell.selected:hover{background-color:rgb(var(--cat-primary-bg, 0, 129, 148));color:rgb(var(--cat-primary-fill, 255, 255, 255));font-weight:700}.datepicker-cell.disabled{color:rgb(var(--cat-font-color-muted, 81, 92, 108))}.datepicker-cell.prev:not(.disabled),.datepicker-cell.next:not(.disabled){color:rgb(var(--cat-font-color-muted, 81, 92, 108))}.datepicker-cell.prev.selected,.datepicker-cell.next.selected{color:rgb(var(--cat-primary-fill, 255, 255, 255))}.datepicker-cell.highlighted:not(.selected):not(.range):not(.today){border-radius:0;background-color:#f2f4f7}.datepicker-cell.highlighted:not(.selected):not(.range):not(.today):not(.disabled):hover{background-color:#f2f4f7}.datepicker-cell.highlighted:not(.selected):not(.range):not(.today).focused{background-color:#f2f4f7}.datepicker-cell.today:not(.selected){background-color:transparent}.datepicker-cell.today:not(.selected):not(.disabled){color:rgb(var(--cat-primary-text, 0, 129, 148))}.datepicker-cell.today.focused:not(.selected){background-color:#f2f4f7}.datepicker-cell.range-end:not(.selected),.datepicker-cell.range-start:not(.selected){background-color:#b8b8b8;color:rgb(var(--cat-primary-fill, 255, 255, 255))}.datepicker-cell.range-end.focused:not(.selected),.datepicker-cell.range-start.focused:not(.selected){background-color:#b3b3b3}.datepicker-cell.range-start:not(.range-end){border-radius:var(--cat-border-radius-m, 0.25rem) 0 0 var(--cat-border-radius-m, 0.25rem)}.datepicker-cell.range-end:not(.range-start){border-radius:0 var(--cat-border-radius-m, 0.25rem) var(--cat-border-radius-m, 0.25rem) 0}.datepicker-cell.range{border-radius:0;background-color:gainsboro}.datepicker-cell.range:not(.disabled):not(.focused):not(.today):hover{background-color:#d7d7d7}.datepicker-cell.range.disabled{color:#c6c6c6}.datepicker-cell.range.focused{background-color:#d1d1d1}.datepicker-input.in-edit{border-color:#276bda}.datepicker-input.in-edit:focus,.datepicker-input.in-edit:active{box-shadow:none}.datepicker-picker{border:1px solid rgb(var(--cat-border-color, 235, 236, 240))}.datepicker-main{padding:0.5rem 1rem}.datepicker-view:has(.week-numbers){width:19.375rem}.datepicker-view.months,.datepicker-view.years{width:20rem}.datepicker .dow,.datepicker .week{font-size:0.75rem;line-height:1rem;font-weight:700;color:rgb(var(--cat-font-color-muted, 81, 92, 108))}.datepicker-cell.today:not(.selected){box-shadow:inset 0 0 0 2px rgb(var(--cat-primary-bg, 0, 129, 148))}.datepicker-cell.focused:not(.selected),.datepicker-cell:not(.selected):not(.disabled):hover{background-color:#f2f4f7}.datepicker-controls{gap:0.5rem}.datepicker-header .datepicker-controls{padding:1rem 1rem 0}.datepicker-header .datepicker-controls .button{height:2.5rem}.datepicker-header .datepicker-controls .prev-button,.datepicker-header .datepicker-controls .next-button{flex-basis:2.5rem;font-size:1.25rem}.datepicker-footer .datepicker-controls{padding:0 1rem 1rem}.datepicker-footer .datepicker-controls .button{margin:0;height:2.5rem;font-size:0.9375rem}.datepicker-footer .datepicker-controls .button:hover,.datepicker-footer .datepicker-controls .button:active{border-color:rgb(var(--cat-border-color-dark, 215, 219, 224))}.datepicker.weekly .datepicker-view:not(.months):not(.years) .datepicker-grid :nth-child(7n+1)::before{content:\"\";width:700%;height:100%;border-radius:var(--cat-border-radius-m, 0.25rem);position:absolute;top:0;left:0;opacity:0;z-index:1}.datepicker.weekly .datepicker-view:not(.months):not(.years) .datepicker-grid :nth-child(7n+1).today:not(.selected)::before{box-shadow:inset 0 0 0 1.5px #008194;border-radius:var(--cat-border-radius-m, 0.25rem);opacity:1}.datepicker.weekly .datepicker-view:not(.months):not(.years) .datepicker-grid :nth-child(7n+1):not(:hover)::before{background:none}.datepicker.weekly .datepicker-view:not(.months):not(.years) .datepicker-grid :nth-child(7n+1):hover::before{opacity:1;background-color:transparent}.datepicker.weekly .datepicker-view:not(.months):not(.years) .datepicker-grid :nth-child(7n+1).selected,.datepicker.weekly .datepicker-view:not(.months):not(.years) .datepicker-grid :nth-child(7n+1).selected.focused{color:white}.datepicker.weekly .datepicker-view:not(.months):not(.years) .datepicker-grid :nth-child(7n+1).selected::before,.datepicker.weekly .datepicker-view:not(.months):not(.years) .datepicker-grid :nth-child(7n+1).selected.focused::before{opacity:1;background-color:rgb(var(--cat-primary-bg, 0, 129, 148));z-index:-1}.datepicker.weekly .datepicker-view:not(.months):not(.years) .datepicker-grid :nth-child(7n+1).focused{background:none}.datepicker.weekly .datepicker-view:not(.months):not(.years) .datepicker-grid :nth-child(7n+1).focused::before{opacity:1;background-color:#f2f4f7;z-index:-1}.datepicker.weekly .datepicker-view:not(.months):not(.years) .datepicker-grid .datepicker-cell{position:relative}.datepicker.weekly .datepicker-view:not(.months):not(.years) .datepicker-grid .datepicker-cell.selected,.datepicker.weekly .datepicker-view:not(.months):not(.years) .datepicker-grid .datepicker-cell.focused{z-index:2}.datepicker.weekly .datepicker-view:not(.months):not(.years) .datepicker-grid .datepicker-cell.today:not(.selected){box-shadow:none}.datepicker.weekly .datepicker-view:not(.months):not(.years) .datepicker-grid .datepicker-cell:not(.disabled):hover{background-color:inherit}.datepicker.weekly .datepicker-view:not(.months):not(.years) .datepicker-grid .datepicker-cell.focused{background:none}";
2917
+
2918
+ const CatDatepicker$1 = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement$1 {
2919
+ constructor() {
2920
+ super();
2921
+ this.__registerHost();
2922
+ this.__attachShadow();
2923
+ this.catChange = createEvent(this, "catChange", 7);
2924
+ this.catFocus = createEvent(this, "catFocus", 7);
2925
+ this.catBlur = createEvent(this, "catBlur", 7);
2926
+ this.hasSlottedLabel = false;
2927
+ this.hasSlottedHint = false;
2928
+ this.requiredMarker = 'optional';
2929
+ this.horizontal = false;
2930
+ this.autoComplete = undefined;
2931
+ this.clearable = false;
2932
+ this.disabled = false;
2933
+ this.hint = undefined;
2934
+ this.icon = undefined;
2935
+ this.iconLeft = false;
2936
+ this.identifier = undefined;
2937
+ this.label = '';
2938
+ this.labelHidden = false;
2939
+ this.max = undefined;
2940
+ this.min = undefined;
2941
+ this.name = undefined;
2942
+ this.placeholder = undefined;
2943
+ this.textPrefix = undefined;
2944
+ this.textSuffix = undefined;
2945
+ this.readonly = false;
2946
+ this.required = false;
2947
+ this.format = 'mm/dd/yyyy';
2948
+ this.weekNumbers = true;
2949
+ this.type = 'date';
2950
+ this.datesDisabled = undefined;
2951
+ this.value = undefined;
2952
+ this.errors = undefined;
2953
+ this.errorUpdate = 0;
2954
+ this.nativeAttributes = undefined;
2955
+ }
2956
+ /**
2957
+ * Programmatically move focus to the input. Use this method instead of
2958
+ * `input.focus()`.
2959
+ *
2960
+ * @param options An optional object providing options to control aspects of
2961
+ * the focusing process.
2962
+ */
2963
+ async doFocus(options) {
2964
+ this.input.focus(options);
2965
+ }
2966
+ /**
2967
+ * Programmatically remove focus from the input. Use this method instead of
2968
+ * `input.blur()`.
2969
+ */
2970
+ async doBlur() {
2971
+ this.input.blur();
2972
+ }
2973
+ /**
2974
+ * Programmatically simulate a click on the input.
2975
+ */
2976
+ async doClick() {
2977
+ this.input.click();
2978
+ }
2979
+ /**
2980
+ * Clear the input.
2981
+ */
2982
+ async clear() {
2983
+ this.value = '';
2984
+ }
2985
+ componentWillRender() {
2986
+ this.hasSlottedLabel = !!this.hostElement.querySelector('[slot="label"]');
2987
+ this.hasSlottedHint = !!this.hostElement.querySelector('[slot="hint"]');
2988
+ }
2989
+ render() {
2990
+ return (h(Host, null, h("cat-input", { ref: el => (this.catInput = el), requiredMarker: this.requiredMarker, horizontal: this.horizontal, autoComplete: this.autoComplete, clearable: this.clearable, disabled: this.disabled, hint: this.hint, icon: this.icon, iconRight: !this.iconLeft, identifier: this.identifier, label: this.label, labelHidden: this.labelHidden, name: this.name, placeholder: this.placeholder, textPrefix: this.textPrefix, textSuffix: this.textSuffix, readonly: this.readonly, required: this.required, value: this.value, errors: this.errors, errorUpdate: this.errorUpdate, nativeAttributes: this.nativeAttributes, onCatChange: event => this.onCatChange(event), onCatFocus: event => this.onCatFocus(event.detail), onCatBlur: event => this.onCatBlur(event.detail) }, this.hasSlottedLabel && (h("span", { slot: "label" }, h("slot", { name: "label" }))), this.hasSlottedHint && (h("span", { slot: "hint" }, h("slot", { name: "hint" }))))));
2991
+ }
2992
+ componentDidLoad() {
2993
+ var _a;
2994
+ if (this.hostElement) {
2995
+ const inputWrapper = (_a = this.catInput.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.input-wrapper');
2996
+ const inputElement = inputWrapper === null || inputWrapper === void 0 ? void 0 : inputWrapper.querySelector('input');
2997
+ if (inputElement) {
2998
+ this.input = inputElement;
2999
+ }
3000
+ else {
3001
+ loglevel.error('[CatInput] Missing input element', this);
3002
+ return;
3003
+ }
3004
+ this.datepicker = new Datepicker(inputElement, Object.assign(Object.assign({}, getDatepickerOptions(this.type, this.value)), { container: inputWrapper, maxDate: this.max, minDate: this.min, datesDisabled: this.datesDisabled, prevArrow: '←', nextArrow: '→', weekNumbers: this.weekNumbers ? 1 : 0, format: {
3005
+ toValue: (dateStr) => this.type === 'week' ? this.fromISOWeek(dateStr) : Datepicker.parseDate(dateStr, this.dateFormat),
3006
+ toDisplay: (date) => this.type === 'week' ? this.toISOWeek(date).toString() : Datepicker.formatDate(date, this.dateFormat)
3007
+ }, beforeShowDay: (date) => (this.shouldHighlightAsToday(date) ? 'today' : null), beforeShowMonth: (date) => (this.shouldHighlightAsToday(date) ? 'today' : null), beforeShowYear: (date) => (this.shouldHighlightAsToday(date) ? 'today' : null) }));
3008
+ if (this.type === 'week') {
3009
+ this.datepicker.pickerElement.classList.add('weekly');
3010
+ }
3011
+ this.input.addEventListener('show', this.handleWeekDays.bind(this));
3012
+ this.input.addEventListener('changeDate', this.handleDateChange.bind(this));
3013
+ this.input.addEventListener('changeMonth', this.handleWeekDays.bind(this));
3014
+ this.input.addEventListener('changeView', this.handleWeekDays.bind(this));
3015
+ this.input.addEventListener('keydown', this.focusAllWeekDays.bind(this));
3016
+ }
3017
+ }
3018
+ disconnectedCallback() {
3019
+ this.input.removeEventListener('show', this.handleWeekDays.bind(this));
3020
+ this.input.removeEventListener('changeDate', this.handleDateChange.bind(this));
3021
+ this.input.removeEventListener('changeMonth', this.handleWeekDays.bind(this));
3022
+ this.input.removeEventListener('changeView', this.handleWeekDays.bind(this));
3023
+ this.input.removeEventListener('keydown', this.focusAllWeekDays.bind(this));
3024
+ }
3025
+ handleDateChange(event) {
3026
+ this.selectAllWeekDays(event.detail.date);
3027
+ this.value = this.input.value;
3028
+ this.catChange.emit();
3029
+ }
3030
+ handleWeekDays(event) {
3031
+ this.selectAllWeekDays(event);
3032
+ this.focusAllWeekDays();
3033
+ }
3034
+ selectAllWeekDays(event) {
3035
+ var _a, _b;
3036
+ const date = event instanceof Date ? event : (_a = event.detail) === null || _a === void 0 ? void 0 : _a.date;
3037
+ if (this.type !== 'week') {
3038
+ return;
3039
+ }
3040
+ if ((_b = this.input) === null || _b === void 0 ? void 0 : _b.value) {
3041
+ const firstDayOfWeek = dayjs_min(date).startOf('isoWeek');
3042
+ if (!firstDayOfWeek.isSame(dayjs_min(date).startOf('day'))) {
3043
+ this.datepicker.setDate(firstDayOfWeek.toDate());
3044
+ }
3045
+ else {
3046
+ this.addClassToAllWeekDays('selected');
3047
+ }
3048
+ }
3049
+ }
3050
+ focusAllWeekDays() {
3051
+ const date = dayjs_min(this.datepicker.picker.viewDate);
3052
+ if (this.type !== 'week' || !date) {
3053
+ return;
3054
+ }
3055
+ const firstDayOfWeek = dayjs_min(date).startOf('isoWeek');
3056
+ if (!firstDayOfWeek.isSame(dayjs_min(date).startOf('day'))) {
3057
+ this.datepicker.setFocusedDate(firstDayOfWeek.toDate());
3058
+ }
3059
+ this.addClassToAllWeekDays('focused');
3060
+ }
3061
+ addClassToAllWeekDays(className) {
3062
+ let weekdaysCount = 7;
3063
+ const pickerElement = this.datepicker.pickerElement;
3064
+ let selected = pickerElement.querySelector(`.datepicker-cell:not(.month):not(.year).${className}`);
3065
+ while (weekdaysCount > 1) {
3066
+ if (selected) {
3067
+ selected = selected.nextElementSibling;
3068
+ selected === null || selected === void 0 ? void 0 : selected.classList.add(className);
3069
+ weekdaysCount--;
3070
+ }
3071
+ else {
3072
+ break;
3073
+ }
3074
+ }
3075
+ }
3076
+ onCatChange(event) {
3077
+ this.value = this.input.value;
3078
+ this.catChange.emit(event);
3079
+ }
3080
+ onCatFocus(event) {
3081
+ this.catFocus.emit(event);
3082
+ }
3083
+ onCatBlur(event) {
3084
+ this.catBlur.emit(event);
3085
+ }
3086
+ shouldHighlightAsToday(date) {
3087
+ const now = new Date();
3088
+ const isSameYear = now.getFullYear() === date.getFullYear();
3089
+ const isSameMonth = now.getMonth() === date.getMonth();
3090
+ const isSameDay = now.getDate() === date.getDate();
3091
+ switch (this.type) {
3092
+ case 'date':
3093
+ return isSameYear && isSameMonth && isSameDay;
3094
+ case 'week':
3095
+ return isSameYear && this.toISOWeek(now) === this.toISOWeek(date);
3096
+ case 'month':
3097
+ return isSameYear && isSameMonth;
3098
+ case 'year':
3099
+ return isSameYear;
3100
+ default:
3101
+ return false;
3102
+ }
3103
+ }
3104
+ // ----- Date handling
3105
+ get dateFormat() {
3106
+ const date = new Date(Date.UTC(3333, 10, 22));
3107
+ const dateStr = new Intl.DateTimeFormat('en-US', {
3108
+ year: 'numeric',
3109
+ month: this.type !== 'year' ? 'numeric' : undefined,
3110
+ day: this.type === 'date' || this.type === 'week' ? 'numeric' : undefined
3111
+ }).format(date);
3112
+ return dateStr.replace('22', 'dd').replace('11', 'mm').replace('3333', 'yyyy');
3113
+ }
3114
+ fromISOWeek(week) {
3115
+ if (typeof week === 'string' || typeof week === 'number') {
3116
+ const weekNumber = parseInt(week.toString(), 10);
3117
+ return isNaN(weekNumber) ? new Date() : this.fromISOWeekNumber(weekNumber);
3118
+ }
3119
+ return week;
3120
+ }
3121
+ fromISOWeekNumber(weekNumber, year = new Date().getFullYear()) {
3122
+ const refDate = new Date(Date.UTC(year, 0, 4)); // January 4th
3123
+ const diffDays = (weekNumber - 1) * 7 - (refDate.getUTCDay() || 7) + 1;
3124
+ const date = new Date(refDate);
3125
+ date.setUTCDate(date.getUTCDate() + diffDays);
3126
+ return date;
3127
+ }
3128
+ toISOWeek(date) {
3129
+ const currentDate = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
3130
+ currentDate.setUTCDate(currentDate.getUTCDate() + 4 - (currentDate.getUTCDay() || 7));
3131
+ const firstDayOfYear = new Date(Date.UTC(currentDate.getUTCFullYear(), 0, 1));
3132
+ return Math.ceil(((currentDate.getTime() - firstDayOfYear.getTime()) / 86400000 + 1) / 7);
3133
+ }
3134
+ get hostElement() { return this; }
3135
+ static get style() { return catDatepickerCss; }
3136
+ }, [1, "cat-datepicker", {
3137
+ "requiredMarker": [1, "required-marker"],
3138
+ "horizontal": [4],
3139
+ "autoComplete": [1, "auto-complete"],
3140
+ "clearable": [4],
3141
+ "disabled": [4],
3142
+ "hint": [1],
3143
+ "icon": [1],
3144
+ "iconLeft": [4, "icon-left"],
3145
+ "identifier": [1],
3146
+ "label": [1],
3147
+ "labelHidden": [4, "label-hidden"],
3148
+ "max": [8],
3149
+ "min": [8],
3150
+ "name": [1],
3151
+ "placeholder": [1],
3152
+ "textPrefix": [1, "text-prefix"],
3153
+ "textSuffix": [1, "text-suffix"],
3154
+ "readonly": [4],
3155
+ "required": [4],
3156
+ "format": [1],
3157
+ "weekNumbers": [4, "week-numbers"],
3158
+ "type": [1],
3159
+ "datesDisabled": [16],
3160
+ "value": [1025],
3161
+ "errors": [4],
3162
+ "errorUpdate": [8, "error-update"],
3163
+ "nativeAttributes": [16],
3164
+ "hasSlottedLabel": [32],
3165
+ "hasSlottedHint": [32],
3166
+ "doFocus": [64],
3167
+ "doBlur": [64],
3168
+ "doClick": [64],
3169
+ "clear": [64]
3170
+ }]);
3171
+ function defineCustomElement$1() {
3172
+ if (typeof customElements === "undefined") {
3173
+ return;
3174
+ }
3175
+ const components = ["cat-datepicker", "cat-button", "cat-icon", "cat-input", "cat-spinner"];
3176
+ components.forEach(tagName => { switch (tagName) {
3177
+ case "cat-datepicker":
3178
+ if (!customElements.get(tagName)) {
3179
+ customElements.define(tagName, CatDatepicker$1);
3180
+ }
3181
+ break;
3182
+ case "cat-button":
3183
+ if (!customElements.get(tagName)) {
3184
+ defineCustomElement$5();
3185
+ }
3186
+ break;
3187
+ case "cat-icon":
3188
+ if (!customElements.get(tagName)) {
3189
+ defineCustomElement$4();
3190
+ }
3191
+ break;
3192
+ case "cat-input":
3193
+ if (!customElements.get(tagName)) {
3194
+ defineCustomElement$3();
3195
+ }
3196
+ break;
3197
+ case "cat-spinner":
3198
+ if (!customElements.get(tagName)) {
3199
+ defineCustomElement$2();
3200
+ }
3201
+ break;
3202
+ } });
3203
+ }
3204
+
3205
+ const CatDatepicker = CatDatepicker$1;
3206
+ const defineCustomElement = defineCustomElement$1;
3207
+
3208
+ export { CatDatepicker, defineCustomElement };
3209
+
3210
+ //# sourceMappingURL=cat-datepicker.js.map