premiumcalendar
Version:
A lightweight and customizable JavaScript + CSS calendar library for modern web applications.
1 lines • 8.3 kB
JavaScript
class MMKPremiumCalendar{constructor(t,e={}){this.container=document.querySelector(t),this.config=Object.assign({type:"range",color:"#4f46e5",disablePrevDates:!1,disableFutureDates:!1,shape:"default",handleChange:null,onMonthChange:null,disableDays:[],datesupto:null,dateRange:"onlyRange",disabledDates:[],darkMode:!1},e),this.state={currentMonth:luxon.DateTime.now().startOf("month"),selectedDates:[]},this.prevRenderedMonth=null,this.init()}init(){this.render(),this.attachEvents()}render(){this.container.innerHTML="";var t=document.createElement("div"),e=(t.className="mmk-calendar-container",this.config.darkMode&&t.classList.add("dark"),document.createElement("div")),n=(e.className="calendar-header",document.createElement("button")),a=(n.id="prevMonth",n.innerHTML="<i class='left-chevron mmk-icon'></i>",document.createElement("select")),s=(a.className="mmk-calendar-input",a.id="MmkmonthSelect",document.createElement("input")),i=(s.type="number",s.className="mmk-calendar-input",s.id="yearInput",document.createElement("button")),n=(i.id="nextMonth",i.innerHTML="<i class='right-chevron mmk-icon'></i>",e.append(n,a,s,i),document.createElement("div")),a=(n.className="calendar-grid-wrapper",document.createElement("div")),s=(a.className="calendar-grid fade",a.id="calendarDays",n.appendChild(a),document.createElement("div")),i=(s.style.marginTop="1rem",s.style.textAlign="center",document.createElement("button"));i.id="MmktodayBtn",i.textContent="Today",s.appendChild(i),t.append(e,n,s),this.container.appendChild(t),this.updateStyles(),this.renderCalendar(),this.updateNavButtons(),this.updateMonthYearFields()}getMonthOptions(){return luxon.Info.months("long").map((t,e)=>`<option value="${e}">${t}</option>`).join("")}updateStyles(){document.documentElement.style.setProperty("--selected-color",this.config.color),document.documentElement.style.setProperty("--button-bg",this.config.color),document.documentElement.style.setProperty("--highlight-color",this.config.color)}updateMonthYearFields(){let e=this.container.querySelector("#yearInput");var t=luxon.DateTime,n=t.now();let a=this.config.disablePrevDates?n.year:1950,s=(!this.config.disableFutureDates&&this.config.datesupto?t.fromISO(this.config.datesupto):n).year;e.min=a,e.max=s,e.value=this.state.currentMonth.year,e.addEventListener("change",()=>{let t=parseInt(e.value,10);(t=t<a?a:t)>s&&(t=s),this.state.currentMonth=this.state.currentMonth.set({year:t}),this.renderMonthOptions(),this.renderCalendar({animate:!0})}),this.renderMonthOptions()}renderMonthOptions(){let e=this.container.querySelector("#MmkmonthSelect");var{DateTime:t,Info:n}=luxon,a=t.now(),s=this.state.currentMonth.year;let i=this.config.disablePrevDates&&s===a.year?a.month:1,r=this.config.disableFutureDates&&s===a.year?a.month:this.config.datesupto&&s===t.fromISO(this.config.datesupto).year?t.fromISO(this.config.datesupto).month:12;e.innerHTML=n.months("long").map((t,e)=>{var n=e+1;return`<option value="${e}" ${n<i||n>r?"disabled":""}>${t}</option>`}).join(""),e.value=this.state.currentMonth.month-1,e.addEventListener("change",()=>{var t=parseInt(e.value,10)+1;this.state.currentMonth=this.state.currentMonth.set({month:t}),this.renderCalendar({animate:!0})})}renderCalendar({animate:t=!1}={}){let n=this.container.querySelector("#calendarDays");var e=luxon.DateTime;t&&(n.classList.remove("fade-in"),n.offsetWidth);let a=this.state.currentMonth.startOf("month");for(;7!==a.weekday;)a=a.minus({days:1});let s=this.state.currentMonth.endOf("month");for(;6!==s.weekday;)s=s.plus({days:1});var i=e.now().toISODate();let r={mon:1,tue:2,wed:3,thu:4,fri:5,sat:6,sun:7};var o,d,h,c=this.config.disableDays.map(t=>r[t.toLowerCase()]);let l=a;for(n.innerHTML="",["Sun","Mon","Tue","Wed","Thu","Fri","Sat"].forEach(t=>{var e=document.createElement("div");e.className="day-name",e.textContent=t,n.appendChild(e)});l<=s;){var u=document.createElement("div");u.className="day",u.textContent=l.day;let t=l.toISODate();var m=t===i,f=this.config.disablePrevDates&&l<e.now().startOf("day"),p=this.config.datesupto&&l>e.fromISO(this.config.datesupto)||this.config.disableFutureDates&&l>e.now().startOf("day"),g=this.config.disabledDates.includes(t),y=c.includes(l.weekday);m&&u.classList.add("today"),(f||p||g||y)&&(u.classList.add("disabled"),y)&&(u.style.color="red"),"range"===this.config.type&&2===this.state.selectedDates.length&&([m,f]=this.state.selectedDates,t>m)&&t<f&&u.classList.add("in-range"),this.state.selectedDates.includes(t)&&u.classList.add("selected"),"circle"===this.config.shape&&(u.style.borderRadius="50%"),u.addEventListener("click",()=>this.handleDateClick(t)),n.appendChild(u),l=l.plus({days:1})}"function"!=typeof this.config.onMonthChange||this.prevRenderedMonth&&this.state.currentMonth.hasSame(this.prevRenderedMonth,"month")||(o=parseInt(this.state.currentMonth.toFormat("M")),d=this.state.currentMonth.toFormat("MMM").toLowerCase(),h=parseInt(this.state.currentMonth.toFormat("yyyy")),this.config.onMonthChange({month:d,code:o,year:h})),this.prevRenderedMonth=this.state.currentMonth,this.updateNavButtons(),this.updateMonthYearFields(),t&&n.classList.add("fade-in")}handleDateClick(t){var n=luxon.DateTime,e=n.fromISO(t);let a={mon:1,tue:2,wed:3,thu:4,fri:5,sat:6,sun:7};var s=this.config.disableDays.map(t=>a[t.toLowerCase()]),i=this.config.disablePrevDates&&e<n.now().startOf("day"),r=this.config.datesupto&&e>n.fromISO(this.config.datesupto)||this.config.disableFutureDates&&e>n.now().startOf("day"),e=this.config.disabledDates.includes(t)||s.includes(e.weekday);if(!(i||r||e)){if("single"===this.config.type?this.state.selectedDates=[t]:"range"===this.config.type&&(this.state.selectedDates.length<2?(this.state.selectedDates.push(t),this.state.selectedDates.sort()):this.state.selectedDates=[t]),"function"==typeof this.config.handleChange){let t=[...this.state.selectedDates];if("range"===this.config.type&&2===this.state.selectedDates.length&&"all"===this.config.dateRange){var[i,r]=this.state.selectedDates,o=[];let e=n.fromISO(i);for(var d=n.fromISO(r);e<=d;){let t=e.toISODate();var h=s.includes(e.weekday);this.config.disabledDates.includes(t)||h||o.push(t),e=e.plus({days:1})}t=o}this.config.handleChange(t)}this.renderCalendar()}}updateNavButtons(){var t=this.container.querySelector("#prevMonth"),e=this.container.querySelector("#nextMonth"),n=luxon.DateTime.now().startOf("day"),a=this.state.currentMonth.minus({months:1}).endOf("month"),t=(t.disabled=this.config.disablePrevDates&&a<n,this.state.currentMonth.plus({months:1}).startOf("month")),a=this.config.datesupto?luxon.DateTime.fromISO(this.config.datesupto):null,n=this.config.disableFutureDates&&n<t;e.disabled=a&&a<t||n}attachEvents(){this.container.querySelector("#prevMonth").addEventListener("click",()=>{this.state.currentMonth=this.state.currentMonth.minus({months:1}),this.renderCalendar({animate:!0})}),this.container.querySelector("#nextMonth").addEventListener("click",()=>{var t=this.state.currentMonth.plus({months:1}).startOf("month"),e=this.config.datesupto?luxon.DateTime.fromISO(this.config.datesupto):null,n=luxon.DateTime.now().startOf("day");e&&e<t||this.config.disableFutureDates&&n<t||(this.state.currentMonth=t,this.renderCalendar({animate:!0}))}),this.container.querySelector("#MmktodayBtn").addEventListener("click",()=>{var t=luxon.DateTime.now(),e=t.toISODate();this.state.currentMonth=t.startOf("month"),this.state.selectedDates=[e],this.renderCalendar({animate:!0}),"function"==typeof this.config.handleChange&&this.config.handleChange([e])}),this.addSwipeListeners()}addSwipeListeners(){var t=this.container.querySelector("#calendarDays");let a=0,s;t.addEventListener("touchstart",t=>{a=t.changedTouches[0].screenX}),t.addEventListener("touchend",t=>{t=(s=t.changedTouches[0].screenX)-a;if(50<Math.abs(t)){var e=luxon.DateTime.now().startOf("day");if(t<0){var t=this.state.currentMonth.plus({months:1}).startOf("month"),n=this.config.datesupto?luxon.DateTime.fromISO(this.config.datesupto):null;if(n&&n<t||this.config.disableFutureDates&&e<t)return;this.state.currentMonth=t}else{n=this.state.currentMonth.minus({months:1}).endOf("month");if(this.config.disablePrevDates&&!(e<=n))return;this.state.currentMonth=this.state.currentMonth.minus({months:1})}this.renderCalendar({animate:!0})}})}}export default MMKPremiumCalendar;