[];\n\t}\n}\n\nwindow.addEventListener('load', () => {\n\tHSRangeSlider.autoInit();\n\n\t// Uncomment for debug\n\t// console.log('Range slider collection:', window.$hsRangeSliderCollection);\n});\n\nif (typeof window !== 'undefined') {\n\twindow.HSRangeSlider = HSRangeSlider;\n}\n\nexport default HSRangeSlider;\n", "/*! name: vanilla-calendar-pro v3.0.3 | url: https://github.com/uvarov-frontend/vanilla-calendar-pro */\nvar __defProp=Object.defineProperty,__defProps=Object.defineProperties,__getOwnPropDescs=Object.getOwnPropertyDescriptors,__getOwnPropSymbols=Object.getOwnPropertySymbols,__hasOwnProp=Object.prototype.hasOwnProperty,__propIsEnum=Object.prototype.propertyIsEnumerable,__defNormalProp=(e,t,n)=>t in e?__defProp(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,__spreadValues=(e,t)=>{for(var n in t||(t={}))__hasOwnProp.call(t,n)&&__defNormalProp(e,n,t[n]);if(__getOwnPropSymbols)for(var n of __getOwnPropSymbols(t))__propIsEnum.call(t,n)&&__defNormalProp(e,n,t[n]);return e},__spreadProps=(e,t)=>__defProps(e,__getOwnPropDescs(t)),__publicField=(e,t,n)=>(__defNormalProp(e,\"symbol\"!=typeof t?t+\"\":t,n),n);const errorMessages={notFoundSelector:e=>`${e} is not found, check the first argument passed to new Calendar.`,notInit:'The calendar has not been initialized, please initialize it using the \"init()\" method first.',notLocale:\"You specified an incorrect language label or did not specify the required number of values \u200B\u200Bfor \u00ABlocale.weekdays\u00BB or \u00ABlocale.months\u00BB.\",incorrectTime:\"The value of the time property can be: false, 12 or 24.\",incorrectMonthsCount:\"For the \u00ABmultiple\u00BB calendar type, the \u00ABdisplayMonthsCount\u00BB parameter can have a value from 2 to 12, and for all others it cannot be greater than 1.\"},setContext=(e,t,n)=>{e.context[t]=n},destroy=e=>{var t,n,a,l,o;if(!e.context.isInit)throw new Error(errorMessages.notInit);e.inputMode?(null==(t=e.context.mainElement.parentElement)||t.removeChild(e.context.mainElement),null==(a=null==(n=e.context.inputElement)?void 0:n.replaceWith)||a.call(n,e.context.originalElement),setContext(e,\"inputElement\",void 0)):null==(o=(l=e.context.mainElement).replaceWith)||o.call(l,e.context.originalElement),setContext(e,\"mainElement\",e.context.originalElement),e.onDestroy&&e.onDestroy(e)},hide=e=>{e.context.currentType&&(e.context.mainElement.dataset.vcCalendarHidden=\"\",e.onHide&&e.onHide(e))};function getOffset(e){if(!e||!e.getBoundingClientRect)return{top:0,bottom:0,left:0,right:0};const t=e.getBoundingClientRect(),n=document.documentElement;return{bottom:t.bottom,right:t.right,top:t.top+window.scrollY-n.clientTop,left:t.left+window.scrollX-n.clientLeft}}function getViewportDimensions(){return{vw:Math.max(document.documentElement.clientWidth||0,window.innerWidth||0),vh:Math.max(document.documentElement.clientHeight||0,window.innerHeight||0)}}function getWindowScrollPosition(){return{left:window.scrollX||document.documentElement.scrollLeft||0,top:window.scrollY||document.documentElement.scrollTop||0}}function calculateAvailableSpace(e){const{top:t,left:n}=getWindowScrollPosition(),{top:a,left:l}=getOffset(e),{vh:o,vw:s}=getViewportDimensions(),i=a-t,r=l-n;return{top:i,bottom:o-(i+e.clientHeight),left:r,right:s-(r+e.clientWidth)}}function getAvailablePosition(e,t,n=5){const a={top:!0,bottom:!0,left:!0,right:!0},l=[];if(!t||!e)return{canShow:a,parentPositions:l};const{bottom:o,top:s}=calculateAvailableSpace(e),{top:i,left:r}=getOffset(e),{height:c,width:d}=t.getBoundingClientRect(),{vh:u,vw:m}=getViewportDimensions(),h=m/2,p=u/2;return[{condition:ip,position:\"bottom\"},{condition:rh,position:\"right\"}].forEach((({condition:e,position:t})=>{e&&l.push(t)})),Object.assign(a,{top:c<=s-n,bottom:c<=o-n,left:d<=r,right:d<=m-r}),{canShow:a,parentPositions:l}}const handleDay=(e,t,n,a)=>{var l;const o=a.querySelector(`[data-vc-date=\"${t}\"]`),s=null==o?void 0:o.querySelector(\"[data-vc-date-btn]\");if(!o||!s)return;if((null==n?void 0:n.modifier)&&s.classList.add(...n.modifier.trim().split(\" \")),!(null==n?void 0:n.html))return;const i=document.createElement(\"div\");i.className=e.styles.datePopup,i.dataset.vcDatePopup=\"\",i.innerHTML=e.sanitizerHTML(n.html),s.ariaExpanded=\"true\",s.ariaLabel=`${s.ariaLabel}, ${null==(l=null==i?void 0:i.textContent)?void 0:l.replace(/^\\s+|\\s+(?=\\s)|\\s+$/g,\"\").replace(/ /g,\" \")}`,o.appendChild(i),requestAnimationFrame((()=>{if(!i)return;const{canShow:e}=getAvailablePosition(o,i),t=e.bottom?o.offsetHeight:-i.offsetHeight,n=e.left&&!e.right?o.offsetWidth-i.offsetWidth/2:!e.left&&e.right?i.offsetWidth/2:0;Object.assign(i.style,{left:`${n}px`,top:`${t}px`})}))},createDatePopup=(e,t)=>{var n;e.popups&&(null==(n=Object.entries(e.popups))||n.forEach((([n,a])=>handleDay(e,n,a,t))))},getDate=e=>new Date(`${e}T00:00:00`),getDateString=e=>`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,\"0\")}-${String(e.getDate()).padStart(2,\"0\")}`,parseDates=e=>e.reduce(((e,t)=>{if(t instanceof Date||\"number\"==typeof t){const n=t instanceof Date?t:new Date(t);e.push(n.toISOString().substring(0,10))}else t.match(/^(\\d{4}-\\d{2}-\\d{2})$/g)?e.push(t):t.replace(/(\\d{4}-\\d{2}-\\d{2}).*?(\\d{4}-\\d{2}-\\d{2})/g,((t,n,a)=>{const l=getDate(n),o=getDate(a),s=new Date(l.getTime());for(;s<=o;s.setDate(s.getDate()+1))e.push(getDateString(s));return t}));return e}),[]),updateAttribute=(e,t,n,a=\"\")=>{t?e.setAttribute(n,a):e.getAttribute(n)===a&&e.removeAttribute(n)},setDateModifier=(e,t,n,a,l,o,s)=>{var i,r,c,d;const u=getDate(e.context.displayDateMin)>getDate(o)||getDate(e.context.displayDateMax)1&&\"multiple-ranged\"===e.selectionDatesMode&&(e.context.selectedDates[0]===o&&e.context.selectedDates[e.context.selectedDates.length-1]===o?n.setAttribute(\"data-vc-date-selected\",\"first-and-last\"):e.context.selectedDates[0]===o?n.setAttribute(\"data-vc-date-selected\",\"first\"):e.context.selectedDates[e.context.selectedDates.length-1]===o&&n.setAttribute(\"data-vc-date-selected\",\"last\"),e.context.selectedDates[0]!==o&&e.context.selectedDates[e.context.selectedDates.length-1]!==o&&n.setAttribute(\"data-vc-date-selected\",\"middle\"))):n.hasAttribute(\"data-vc-date-selected\")&&(n.removeAttribute(\"data-vc-date-selected\"),a&&a.removeAttribute(\"aria-selected\")),!e.context.disableDates.includes(o)&&e.enableEdgeDatesOnly&&e.context.selectedDates.length>1&&\"multiple-ranged\"===e.selectionDatesMode){const t=getDate(e.context.selectedDates[0]),a=getDate(e.context.selectedDates[e.context.selectedDates.length-1]),l=getDate(o);updateAttribute(n,l>t&&lnew Date(`${e}T00:00:00.000Z`).toLocaleString(t,n),getWeekNumber=(e,t)=>{const n=getDate(e),a=(n.getDay()-t+7)%7;n.setDate(n.getDate()+4-a);const l=new Date(n.getFullYear(),0,1),o=Math.ceil(((+n-+l)/864e5+1)/7);return{year:n.getFullYear(),week:o}},addWeekNumberForDate=(e,t,n)=>{const a=getWeekNumber(n,e.firstWeekday);a&&(t.dataset.vcDateWeekNumber=String(a.week))},setDaysAsDisabled=(e,t,n)=>{var a,l,o,s,i;const r=null==(a=e.disableWeekdays)?void 0:a.includes(n),c=e.disableAllDates&&!!(null==(l=e.context.enableDates)?void 0:l[0]);!r&&!c||(null==(o=e.context.enableDates)?void 0:o.includes(t))||(null==(s=e.context.disableDates)?void 0:s.includes(t))||(e.context.disableDates.push(t),null==(i=e.context.disableDates)||i.sort(((e,t)=>+new Date(e)-+new Date(t))))},createDate=(e,t,n,a,l,o)=>{const s=getDate(l).getDay(),i=\"string\"==typeof e.locale&&e.locale.length?e.locale:\"en\",r=document.createElement(\"div\");let c;r.className=e.styles.date,r.dataset.vcDate=l,r.dataset.vcDateMonth=o,r.dataset.vcDateWeekDay=String(s),(\"current\"===o||e.displayDatesOutside)&&(c=document.createElement(\"button\"),c.className=e.styles.dateBtn,c.type=\"button\",c.role=\"gridcell\",c.ariaLabel=getLocaleString(l,i,{dateStyle:\"long\",timeZone:\"UTC\"}),c.dataset.vcDateBtn=\"\",c.innerText=String(a),r.appendChild(c)),e.enableWeekNumbers&&addWeekNumberForDate(e,r,l),setDaysAsDisabled(e,l,s),setDateModifier(e,t,r,c,s,l,o),n.appendChild(r),e.onCreateDateEls&&e.onCreateDateEls(e,r)},createDatesFromCurrentMonth=(e,t,n,a,l)=>{for(let o=1;o<=n;o++){const n=new Date(a,l,o);createDate(e,a,t,o,getDateString(n),\"current\")}},createDatesFromNextMonth=(e,t,n,a,l,o)=>{const s=o+n,i=7*Math.ceil(s/7)-s,r=l+1===12?a+1:a,c=l+1===12?\"01\":l+2<10?`0${l+2}`:l+2;for(let n=1;n<=i;n++){const l=n<10?`0${n}`:String(n);createDate(e,a,t,n,`${r}-${c}-${l}`,\"next\")}},createDatesFromPrevMonth=(e,t,n,a,l)=>{let o=new Date(n,a,0).getDate()-(l-1);const s=0===a?n-1:n,i=0===a?12:a<10?`0${a}`:a;for(let a=l;a>0;a--,o++){createDate(e,n,t,o,`${s}-${i}-${o}`,\"prev\")}},createWeekNumbers=(e,t,n,a,l)=>{if(!e.enableWeekNumbers)return;a.textContent=\"\";const o=document.createElement(\"b\");o.className=e.styles.weekNumbersTitle,o.innerText=\"#\",o.dataset.vcWeekNumbers=\"title\",a.appendChild(o);const s=document.createElement(\"div\");s.className=e.styles.weekNumbersContent,s.dataset.vcWeekNumbers=\"content\",a.appendChild(s);const i=document.createElement(\"button\");i.type=\"button\",i.className=e.styles.weekNumber;const r=l.querySelectorAll(\"[data-vc-date]\"),c=Math.ceil((t+n)/7);for(let t=0;t{const t=new Date(e.context.selectedYear,e.context.selectedMonth,1),n=e.context.mainElement.querySelectorAll('[data-vc=\"dates\"]'),a=e.context.mainElement.querySelectorAll('[data-vc-week=\"numbers\"]');n.forEach(((n,l)=>{e.selectionDatesMode||(n.dataset.vcDatesDisabled=\"\"),n.textContent=\"\";const o=new Date(t);o.setMonth(o.getMonth()+l);const s=o.getMonth(),i=o.getFullYear(),r=(new Date(i,s,1).getDay()-e.firstWeekday+7)%7,c=new Date(i,s+1,0).getDate();createDatesFromPrevMonth(e,n,i,s,r),createDatesFromCurrentMonth(e,n,c,i,s),createDatesFromNextMonth(e,n,c,i,s,r),createDatePopup(e,n),createWeekNumbers(e,r,c,a[l],n)}))},layoutDefault=e=>`\\n \\n \\n <#WeekNumbers />\\n
\\n <#Week />\\n <#Dates />\\n <#DateRangeTooltip />\\n
\\n
\\n <#ControlTime />\\n`,layoutMonths=e=>`\\n \\n \\n
\\n <#Months />\\n
\\n
\\n`,layoutMultiple=e=>`\\n \\n <#ArrowPrev [month] />\\n <#ArrowNext [month] />\\n
\\n \\n <#Multiple>\\n
\\n \\n
\\n <#WeekNumbers />\\n
\\n <#Week />\\n <#Dates />\\n
\\n
\\n
\\n <#/Multiple>\\n <#DateRangeTooltip />\\n
\\n <#ControlTime />\\n`,layoutYears=e=>`\\n \\n \\n
\\n <#Years />\\n
\\n
\\n`,ArrowNext=(e,t)=>``,ArrowPrev=(e,t)=>``,ControlTime=e=>e.selectionTimeMode?``:\"\",DateRangeTooltip=e=>e.onCreateDateRangeTooltip?``:\"\",Dates=e=>``,Month=e=>``,Months=e=>``,Week=e=>``,WeekNumbers=e=>e.enableWeekNumbers?``:\"\",Year=e=>``,Years=e=>``,components={ArrowNext:ArrowNext,ArrowPrev:ArrowPrev,ControlTime:ControlTime,Dates:Dates,DateRangeTooltip:DateRangeTooltip,Month:Month,Months:Months,Week:Week,WeekNumbers:WeekNumbers,Year:Year,Years:Years},getComponent=e=>components[e],parseLayout=(e,t)=>t.replace(/[\\n\\t]/g,\"\").replace(/<#(?!\\/?Multiple)(.*?)>/g,((t,n)=>{const a=(n.match(/\\[(.*?)\\]/)||[])[1],l=n.replace(/[/\\s\\n\\t]|\\[(.*?)\\]/g,\"\"),o=getComponent(l),s=o?o(e,null!=a?a:null):\"\";return e.sanitizerHTML(s)})).replace(/[\\n\\t]/g,\"\"),parseMultipleLayout=(e,t)=>t.replace(new RegExp(\"<#Multiple>(.*?)<#\\\\/Multiple>\",\"gs\"),((t,n)=>{const a=Array(e.context.displayMonthsCount).fill(n).join(\"\");return e.sanitizerHTML(a)})).replace(/[\\n\\t]/g,\"\"),createLayouts=(e,t)=>{const n={default:layoutDefault,month:layoutMonths,year:layoutYears,multiple:layoutMultiple};if(Object.keys(n).forEach((t=>{const a=t;e.layouts[a].length||(e.layouts[a]=n[a](e))})),e.context.mainElement.className=e.styles.calendar,e.context.mainElement.dataset.vc=\"calendar\",e.context.mainElement.dataset.vcType=e.context.currentType,e.context.mainElement.role=\"application\",e.context.mainElement.tabIndex=0,e.context.mainElement.ariaLabel=e.labels.application,\"multiple\"!==e.context.currentType){if(\"multiple\"===e.type&&t){const n=e.context.mainElement.querySelector('[data-vc=\"controls\"]'),a=e.context.mainElement.querySelector('[data-vc=\"grid\"]'),l=t.closest('[data-vc=\"column\"]');return n&&e.context.mainElement.removeChild(n),a&&(a.dataset.vcGrid=\"hidden\"),l&&(l.dataset.vcColumn=e.context.currentType),void(l&&(l.innerHTML=e.sanitizerHTML(parseLayout(e,e.layouts[e.context.currentType]))))}e.context.mainElement.innerHTML=e.sanitizerHTML(parseLayout(e,e.layouts[e.context.currentType]))}else e.context.mainElement.innerHTML=e.sanitizerHTML(parseMultipleLayout(e,parseLayout(e,e.layouts[e.context.currentType])))},setVisibilityArrows=(e,t,n,a)=>{e.style.visibility=n?\"hidden\":\"\",t.style.visibility=a?\"hidden\":\"\"},handleDefaultType=(e,t,n)=>{const a=getDate(getDateString(new Date(e.context.selectedYear,e.context.selectedMonth,1))),l=new Date(a.getTime()),o=new Date(a.getTime());l.setMonth(l.getMonth()-e.monthsToSwitch),o.setMonth(o.getMonth()+e.monthsToSwitch);const s=getDate(e.context.dateMin),i=getDate(e.context.dateMax);e.selectionYearsMode||(s.setFullYear(a.getFullYear()),i.setFullYear(a.getFullYear()));const r=!e.selectionMonthsMode||l.getFullYear()i.getFullYear()||o.getFullYear()===i.getFullYear()&&o.getMonth()>i.getMonth()-(e.context.displayMonthsCount-1);setVisibilityArrows(t,n,r,c)},handleYearType=(e,t,n)=>{const a=getDate(e.context.dateMin),l=getDate(e.context.dateMax),o=!!(a.getFullYear()&&e.context.displayYear-7<=a.getFullYear()),s=!!(l.getFullYear()&&e.context.displayYear+7>=l.getFullYear());setVisibilityArrows(t,n,o,s)},visibilityArrows=e=>{if(\"month\"===e.context.currentType)return;const t=e.context.mainElement.querySelector('[data-vc-arrow=\"prev\"]'),n=e.context.mainElement.querySelector('[data-vc-arrow=\"next\"]');if(!t||!n)return;({default:()=>handleDefaultType(e,t,n),year:()=>handleYearType(e,t,n)})[\"multiple\"===e.context.currentType?\"default\":e.context.currentType]()},visibilityHandler=(e,t,n,a,l)=>{const o=new Date(a.setFullYear(e.context.selectedYear,e.context.selectedMonth+n)).getFullYear(),s=new Date(a.setMonth(e.context.selectedMonth+n)).getMonth(),i=e.context.locale.months.long[s],r=t.closest('[data-vc=\"column\"]');r&&(r.ariaLabel=`${i} ${o}`);const c={month:{id:s,label:i},year:{id:o,label:o}};t.innerText=String(c[l].label),t.dataset[`vc${l.charAt(0).toUpperCase()+l.slice(1)}`]=String(c[l].id),t.ariaLabel=`${e.labels[l]} ${c[l].label}`;const d={month:e.selectionMonthsMode,year:e.selectionYearsMode},u=!1===d[l]||\"only-arrows\"===d[l];u&&(t.tabIndex=-1),t.disabled=u},visibilityTitle=e=>{const t=e.context.mainElement.querySelectorAll('[data-vc=\"month\"]'),n=e.context.mainElement.querySelectorAll('[data-vc=\"year\"]'),a=new Date(e.context.selectedYear,e.context.selectedMonth,1);[t,n].forEach((t=>null==t?void 0:t.forEach(((t,n)=>visibilityHandler(e,t,n,a,t.dataset.vc)))))},setYearModifier=(e,t,n,a,l)=>{var o;const s={month:\"[data-vc-months-month]\",year:\"[data-vc-years-year]\"},i={month:{selected:\"data-vc-months-month-selected\",aria:\"aria-selected\",value:\"vcMonthsMonth\",selectedProperty:\"selectedMonth\"},year:{selected:\"data-vc-years-year-selected\",aria:\"aria-selected\",value:\"vcYearsYear\",selectedProperty:\"selectedYear\"}};l&&(null==(o=e.context.mainElement.querySelectorAll(s[n]))||o.forEach((e=>{e.removeAttribute(i[n].selected),e.removeAttribute(i[n].aria)})),setContext(e,i[n].selectedProperty,Number(t.dataset[i[n].value])),visibilityTitle(e),\"year\"===n&&visibilityArrows(e)),a&&(t.setAttribute(i[n].selected,\"\"),t.setAttribute(i[n].aria,\"true\"))},getColumnID=(e,t)=>{var n;if(\"multiple\"!==e.type)return{currentValue:null,columnID:0};const a=e.context.mainElement.querySelectorAll('[data-vc=\"column\"]'),l=Array.from(a).findIndex((e=>e.closest(`[data-vc-column=\"${t}\"]`)));return{currentValue:l>=0?Number(null==(n=a[l].querySelector(`[data-vc=\"${t}\"]`))?void 0:n.getAttribute(`data-vc-${t}`)):null,columnID:Math.max(l,0)}},createMonthEl=(e,t,n,a,l,o,s)=>{const i=t.cloneNode(!1);return i.className=e.styles.monthsMonth,i.innerText=a,i.ariaLabel=l,i.role=\"gridcell\",i.dataset.vcMonthsMonth=`${s}`,o&&(i.ariaDisabled=\"true\"),o&&(i.tabIndex=-1),i.disabled=o,setYearModifier(e,i,\"month\",n===s,!1),i},createMonths=(e,t)=>{var n,a;const l=null==(n=null==t?void 0:t.closest('[data-vc=\"header\"]'))?void 0:n.querySelector('[data-vc=\"year\"]'),o=l?Number(l.dataset.vcYear):e.context.selectedYear,s=(null==t?void 0:t.dataset.vcMonth)?Number(t.dataset.vcMonth):e.context.selectedMonth;setContext(e,\"currentType\",\"month\"),createLayouts(e,t),visibilityTitle(e);const i=e.context.mainElement.querySelector('[data-vc=\"months\"]');if(!e.selectionMonthsMode||!i)return;const r=e.monthsToSwitch>1?e.context.locale.months.long.map(((t,n)=>s-e.monthsToSwitch*n)).concat(e.context.locale.months.long.map(((t,n)=>s+e.monthsToSwitch*n))).filter((e=>e>=0&&e<=12)):Array.from(Array(12).keys()),c=document.createElement(\"button\");c.type=\"button\";for(let t=0;t<12;t++){const n=getDate(e.context.dateMin),a=getDate(e.context.dateMax),l=e.context.displayMonthsCount-1,{columnID:d}=getColumnID(e,\"month\"),u=o<=n.getFullYear()&&t=a.getFullYear()&&t>a.getMonth()-l+d||o>a.getFullYear()||t!==s&&!r.includes(t),m=createMonthEl(e,c,s,e.context.locale.months.short[t],e.context.locale.months.long[t],u,t);i.appendChild(m),e.onCreateMonthEls&&e.onCreateMonthEls(e,m)}null==(a=e.context.mainElement.querySelector(\"[data-vc-months-month]:not([disabled])\"))||a.focus()},TimeInput=(e,t,n,a,l)=>`\\n \\n`,TimeRange=(e,t,n,a,l,o,s)=>`\\n \\n`,handleActions=(e,t,n,a)=>{({hour:()=>setContext(e,\"selectedHours\",n),minute:()=>setContext(e,\"selectedMinutes\",n)})[a](),setContext(e,\"selectedTime\",`${e.context.selectedHours}:${e.context.selectedMinutes}${e.context.selectedKeeping?` ${e.context.selectedKeeping}`:\"\"}`),e.onChangeTime&&e.onChangeTime(e,t,!1),e.inputMode&&e.context.inputElement&&e.context.mainElement&&e.onChangeToInput&&e.onChangeToInput(e,t)},transformTime24=(e,t)=>{var n;return(null==(n={0:{AM:\"00\",PM:\"12\"},1:{AM:\"01\",PM:\"13\"},2:{AM:\"02\",PM:\"14\"},3:{AM:\"03\",PM:\"15\"},4:{AM:\"04\",PM:\"16\"},5:{AM:\"05\",PM:\"17\"},6:{AM:\"06\",PM:\"18\"},7:{AM:\"07\",PM:\"19\"},8:{AM:\"08\",PM:\"20\"},9:{AM:\"09\",PM:\"21\"},10:{AM:\"10\",PM:\"22\"},11:{AM:\"11\",PM:\"23\"},12:{AM:\"00\",PM:\"12\"}}[Number(e)])?void 0:n[t])||String(e)},handleClickKeepingTime=(e,t,n,a,l)=>{const o=o=>{const s=\"AM\"===e.context.selectedKeeping?\"PM\":\"AM\",i=transformTime24(e.context.selectedHours,s);Number(i)<=a&&Number(i)>=l?(setContext(e,\"selectedKeeping\",s),n.value=i,handleActions(e,o,e.context.selectedHours,\"hour\"),t.ariaLabel=`${e.labels.btnKeeping} ${e.context.selectedKeeping}`,t.innerText=e.context.selectedKeeping):e.onChangeTime&&e.onChangeTime(e,o,!0)};return t.addEventListener(\"click\",o),()=>{t.removeEventListener(\"click\",o)}},transformTime12=e=>({0:\"12\",13:\"01\",14:\"02\",15:\"03\",16:\"04\",17:\"05\",18:\"06\",19:\"07\",20:\"08\",21:\"09\",22:\"10\",23:\"11\"}[Number(e)]||String(e)),updateInputAndRange=(e,t,n,a)=>{e.value=n,t.value=a},updateKeepingTime$1=(e,t,n)=>{t&&n&&(setContext(e,\"selectedKeeping\",n),t.innerText=n)},handleInput$1=(e,t,n,a,l,o,s)=>{const i={hour:(i,r,c)=>{if(!e.selectionTimeMode)return;({12:()=>{if(!e.context.selectedKeeping)return;const d=Number(transformTime24(r,e.context.selectedKeeping));if(!(d<=o&&d>=s))return updateInputAndRange(n,t,e.context.selectedHours,e.context.selectedHours),void(e.onChangeTime&&e.onChangeTime(e,c,!0));updateInputAndRange(n,t,transformTime12(r),transformTime24(r,e.context.selectedKeeping)),i>12&&updateKeepingTime$1(e,a,\"PM\"),handleActions(e,c,transformTime12(r),l)},24:()=>{if(!(i<=o&&i>=s))return updateInputAndRange(n,t,e.context.selectedHours,e.context.selectedHours),void(e.onChangeTime&&e.onChangeTime(e,c,!0));updateInputAndRange(n,t,r,r),handleActions(e,c,r,l)}})[e.selectionTimeMode]()},minute:(a,i,r)=>{if(!(a<=o&&a>=s))return n.value=e.context.selectedMinutes,void(e.onChangeTime&&e.onChangeTime(e,r,!0));n.value=i,t.value=i,handleActions(e,r,i,l)}},r=e=>{const t=Number(n.value),a=n.value.padStart(2,\"0\");i[l]&&i[l](t,a,e)};return n.addEventListener(\"change\",r),()=>{n.removeEventListener(\"change\",r)}},updateInputAndTime=(e,t,n,a,l)=>{t.value=l,handleActions(e,n,l,a)},updateKeepingTime=(e,t,n)=>{t&&(setContext(e,\"selectedKeeping\",n),t.innerText=n)},handleRange=(e,t,n,a,l)=>{const o=o=>{const s=Number(t.value),i=t.value.padStart(2,\"0\"),r=\"hour\"===l,c=24===e.selectionTimeMode,d=s>0&&s<12;r&&!c&&updateKeepingTime(e,a,0===s||d?\"AM\":\"PM\"),updateInputAndTime(e,n,o,l,!r||c||d?i:transformTime12(t.value))};return t.addEventListener(\"input\",o),()=>{t.removeEventListener(\"input\",o)}},handleMouseOver=e=>e.setAttribute(\"data-vc-input-focus\",\"\"),handleMouseOut=e=>e.removeAttribute(\"data-vc-input-focus\"),handleTime=(e,t)=>{const n=t.querySelector('[data-vc-time-range=\"hour\"] input[name=\"hour\"]'),a=t.querySelector('[data-vc-time-range=\"minute\"] input[name=\"minute\"]'),l=t.querySelector('[data-vc-time-input=\"hour\"] input[name=\"hour\"]'),o=t.querySelector('[data-vc-time-input=\"minute\"] input[name=\"minute\"]'),s=t.querySelector('[data-vc-time=\"keeping\"]');if(!(n&&a&&l&&o))return;const i=e=>{e.target===n&&handleMouseOver(l),e.target===a&&handleMouseOver(o)},r=e=>{e.target===n&&handleMouseOut(l),e.target===a&&handleMouseOut(o)};return t.addEventListener(\"mouseover\",i),t.addEventListener(\"mouseout\",r),handleInput$1(e,n,l,s,\"hour\",e.timeMaxHour,e.timeMinHour),handleInput$1(e,a,o,s,\"minute\",e.timeMaxMinute,e.timeMinMinute),handleRange(e,n,l,s,\"hour\"),handleRange(e,a,o,s,\"minute\"),s&&handleClickKeepingTime(e,s,n,e.timeMaxHour,e.timeMinHour),()=>{t.removeEventListener(\"mouseover\",i),t.removeEventListener(\"mouseout\",r)}},createTime=e=>{const t=e.context.mainElement.querySelector('[data-vc=\"time\"]');if(!e.selectionTimeMode||!t)return;const[n,a]=[e.timeMinHour,e.timeMaxHour],[l,o]=[e.timeMinMinute,e.timeMaxMinute],s=e.context.selectedKeeping?transformTime24(e.context.selectedHours,e.context.selectedKeeping):e.context.selectedHours,i=\"range\"===e.timeControls;var r;t.innerHTML=e.sanitizerHTML(`\\n \\n ${TimeInput(\"hour\",e.styles.timeHour,e.labels,e.context.selectedHours,i)}\\n ${TimeInput(\"minute\",e.styles.timeMinute,e.labels,e.context.selectedMinutes,i)}\\n ${12===e.selectionTimeMode?(r=e.context.selectedKeeping,``):\"\"}\\n
\\n \\n ${TimeRange(\"hour\",e.styles.timeRange,e.labels,n,a,e.timeStepHour,s)}\\n ${TimeRange(\"minute\",e.styles.timeRange,e.labels,l,o,e.timeStepMinute,e.context.selectedMinutes)}\\n
\\n `),handleTime(e,t)},createWeek=e=>{const t=e.selectedWeekends?[...e.selectedWeekends]:[],n=[...e.context.locale.weekdays.long].reduce(((n,a,l)=>[...n,{id:l,titleShort:e.context.locale.weekdays.short[l],titleLong:a,isWeekend:t.includes(l)}]),[]),a=[...n.slice(e.firstWeekday),...n.slice(0,e.firstWeekday)];e.context.mainElement.querySelectorAll('[data-vc=\"week\"]').forEach((t=>{const n=e.onClickWeekDay?document.createElement(\"button\"):document.createElement(\"b\");e.onClickWeekDay&&(n.type=\"button\"),a.forEach((a=>{const l=n.cloneNode(!0);l.innerText=a.titleShort,l.className=e.styles.weekDay,l.role=\"columnheader\",l.ariaLabel=a.titleLong,l.dataset.vcWeekDay=String(a.id),a.isWeekend&&(l.dataset.vcWeekDayOff=\"\"),t.appendChild(l)}))}))},createYearEl=(e,t,n,a,l)=>{const o=t.cloneNode(!1);return o.className=e.styles.yearsYear,o.innerText=String(l),o.ariaLabel=String(l),o.role=\"gridcell\",o.dataset.vcYearsYear=`${l}`,a&&(o.ariaDisabled=\"true\"),a&&(o.tabIndex=-1),o.disabled=a,setYearModifier(e,o,\"year\",n===l,!1),o},createYears=(e,t)=>{var n;const a=(null==t?void 0:t.dataset.vcYear)?Number(t.dataset.vcYear):e.context.selectedYear;setContext(e,\"currentType\",\"year\"),createLayouts(e,t),visibilityTitle(e),visibilityArrows(e);const l=e.context.mainElement.querySelector('[data-vc=\"years\"]');if(!e.selectionYearsMode||!l)return;const o=\"multiple\"!==e.type||e.context.selectedYear===a?0:1,s=document.createElement(\"button\");s.type=\"button\";for(let t=e.context.displayYear-7;tgetDate(e.context.dateMax).getFullYear(),i=createYearEl(e,s,a,n,t);l.appendChild(i),e.onCreateYearEls&&e.onCreateYearEls(e,i)}null==(n=e.context.mainElement.querySelector(\"[data-vc-years-year]:not([disabled])\"))||n.focus()},trackChangesHTMLElement=(e,t,n)=>{new MutationObserver((e=>{for(let a=0;ahaveListener.value=!0,check:()=>haveListener.value},setTheme=(e,t)=>e.dataset.vcTheme=t,trackChangesThemeInSystemSettings=(e,t)=>{if(setTheme(e.context.mainElement,t.matches?\"dark\":\"light\"),\"system\"!==e.selectedTheme||haveListener.check())return;const n=e=>{const t=document.querySelectorAll('[data-vc=\"calendar\"]');null==t||t.forEach((t=>setTheme(t,e.matches?\"dark\":\"light\")))};t.addEventListener?t.addEventListener(\"change\",n):t.addListener(n),haveListener.set()},detectTheme=(e,t)=>{const n=e.themeAttrDetect.length?document.querySelector(e.themeAttrDetect):null,a=e.themeAttrDetect.replace(/^.*\\[(.+)\\]/g,((e,t)=>t));if(!n||\"system\"===n.getAttribute(a))return void trackChangesThemeInSystemSettings(e,t);const l=n.getAttribute(a);l?(setTheme(e.context.mainElement,l),trackChangesHTMLElement(n,a,(()=>{const t=n.getAttribute(a);t&&setTheme(e.context.mainElement,t)}))):trackChangesThemeInSystemSettings(e,t)},handleTheme=e=>{\"not all\"!==window.matchMedia(\"(prefers-color-scheme)\").media?\"system\"===e.selectedTheme?detectTheme(e,window.matchMedia(\"(prefers-color-scheme: dark)\")):setTheme(e.context.mainElement,e.selectedTheme):setTheme(e.context.mainElement,\"light\")},capitalizeFirstLetter=e=>e.charAt(0).toUpperCase()+e.slice(1).replace(/\\./,\"\"),getLocaleWeekday=(e,t,n)=>{const a=new Date(`1978-01-0${t+1}T00:00:00.000Z`),l=a.toLocaleString(n,{weekday:\"short\",timeZone:\"UTC\"}),o=a.toLocaleString(n,{weekday:\"long\",timeZone:\"UTC\"});e.context.locale.weekdays.short.push(capitalizeFirstLetter(l)),e.context.locale.weekdays.long.push(capitalizeFirstLetter(o))},getLocaleMonth=(e,t,n)=>{const a=new Date(`1978-${String(t+1).padStart(2,\"0\")}-01T00:00:00.000Z`),l=a.toLocaleString(n,{month:\"short\",timeZone:\"UTC\"}),o=a.toLocaleString(n,{month:\"long\",timeZone:\"UTC\"});e.context.locale.months.short.push(capitalizeFirstLetter(l)),e.context.locale.months.long.push(capitalizeFirstLetter(o))},getLocale=e=>{var t,n,a,l,o,s,i,r;if(!(e.context.locale.weekdays.short[6]&&e.context.locale.weekdays.long[6]&&e.context.locale.months.short[11]&&e.context.locale.months.long[11]))if(\"string\"==typeof e.locale){if(\"string\"==typeof e.locale&&!e.locale.length)throw new Error(errorMessages.notLocale);Array.from({length:7},((t,n)=>getLocaleWeekday(e,n,e.locale))),Array.from({length:12},((t,n)=>getLocaleMonth(e,n,e.locale)))}else{if(!((null==(n=null==(t=e.locale)?void 0:t.weekdays)?void 0:n.short[6])&&(null==(l=null==(a=e.locale)?void 0:a.weekdays)?void 0:l.long[6])&&(null==(s=null==(o=e.locale)?void 0:o.months)?void 0:s.short[11])&&(null==(r=null==(i=e.locale)?void 0:i.months)?void 0:r.long[11])))throw new Error(errorMessages.notLocale);setContext(e,\"locale\",__spreadValues({},e.locale))}},create=e=>{const t={default:()=>{createWeek(e),createDates(e)},multiple:()=>{createWeek(e),createDates(e)},month:()=>createMonths(e),year:()=>createYears(e)};handleTheme(e),getLocale(e),createLayouts(e),visibilityTitle(e),visibilityArrows(e),createTime(e),t[e.context.currentType]()},handleArrowKeys=e=>{const t=()=>Array.from(e.context.mainElement.querySelectorAll('[data-vc=\"calendar\"] button'));let n=0;const a={ArrowUp:(e,t)=>Math.max(0,e-t),ArrowDown:(e,n)=>Math.min(t().length-1,e+n),ArrowLeft:e=>Math.max(0,e-1),ArrowRight:e=>Math.min(t().length-1,e+1)},l=e=>{var l,o;if(!a[e.key]||\"button\"!==(null==(l=e.target)?void 0:l.localName))return;const s=t(),i=s[n].hasAttribute(\"data-vc-date-btn\")?7:s[n].hasAttribute(\"data-vc-months-month\")?4:s[n].hasAttribute(\"data-vc-years-year\")?5:1;n=a[e.key](n,i),null==(o=s[n])||o.focus()};return e.context.mainElement.addEventListener(\"keydown\",l),()=>{e.context.mainElement.removeEventListener(\"keydown\",l)}},handleMonth=(e,t)=>{const n=getDate(getDateString(new Date(e.context.selectedYear,e.context.selectedMonth,1)));({prev:()=>n.setMonth(n.getMonth()-e.monthsToSwitch),next:()=>n.setMonth(n.getMonth()+e.monthsToSwitch)})[t](),setContext(e,\"selectedMonth\",n.getMonth()),setContext(e,\"selectedYear\",n.getFullYear()),visibilityTitle(e),visibilityArrows(e),createDates(e)},handleClickArrow=(e,t)=>{const n=t.target.closest(\"[data-vc-arrow]\");if(n){if([\"default\",\"multiple\"].includes(e.context.currentType))handleMonth(e,n.dataset.vcArrow);else if(\"year\"===e.context.currentType&&void 0!==e.context.displayYear){const a={prev:-15,next:15}[n.dataset.vcArrow];setContext(e,\"displayYear\",e.context.displayYear+a),createYears(e,t.target)}e.onClickArrow&&e.onClickArrow(e,t)}},canToggleSelection=e=>void 0===e.enableDateToggle||(\"function\"==typeof e.enableDateToggle?e.enableDateToggle(e):e.enableDateToggle),handleSelectDate=(e,t,n)=>{const a=t.dataset.vcDate,l=t.closest(\"[data-vc-date][data-vc-date-selected]\"),o=canToggleSelection(e);if(l&&!o)return;const s=l?e.context.selectedDates.filter((e=>e!==a)):n?[...e.context.selectedDates,a]:[a];setContext(e,\"selectedDates\",s)},createDateRangeTooltip=(e,t,n)=>{if(!t)return;if(!n)return t.dataset.vcDateRangeTooltip=\"hidden\",void(t.textContent=\"\");const a=e.context.mainElement.getBoundingClientRect(),l=n.getBoundingClientRect();t.style.left=l.left-a.left+l.width/2+\"px\",t.style.top=l.bottom-a.top-l.height+\"px\",t.dataset.vcDateRangeTooltip=\"visible\",t.innerHTML=e.sanitizerHTML(e.onCreateDateRangeTooltip(e,n,t,l,a))},state={self:null,lastDateEl:null,isHovering:!1,rangeMin:void 0,rangeMax:void 0,tooltipEl:null,timeoutId:null},addHoverEffect=(e,t,n)=>{var a,l,o;if(!(null==(l=null==(a=state.self)?void 0:a.context)?void 0:l.selectedDates[0]))return;const s=getDateString(e);(null==(o=state.self.context.disableDates)?void 0:o.includes(s))||(state.self.context.mainElement.querySelectorAll(`[data-vc-date=\"${s}\"]`).forEach((e=>e.dataset.vcDateHover=\"\")),t.forEach((e=>e.dataset.vcDateHover=\"first\")),n.forEach((e=>{\"first\"===e.dataset.vcDateHover?e.dataset.vcDateHover=\"first-and-last\":e.dataset.vcDateHover=\"last\"})))},removeHoverEffect=()=>{var e,t;if(!(null==(t=null==(e=state.self)?void 0:e.context)?void 0:t.mainElement))return;state.self.context.mainElement.querySelectorAll(\"[data-vc-date-hover]\").forEach((e=>e.removeAttribute(\"data-vc-date-hover\")))},handleHoverDatesEvent=e=>{var t,n;if(!e.target||!(null==(n=null==(t=state.self)?void 0:t.context)?void 0:n.selectedDates[0]))return;if(!e.target.closest('[data-vc=\"dates\"]'))return state.lastDateEl=null,createDateRangeTooltip(state.self,state.tooltipEl,null),void removeHoverEffect();const a=e.target.closest(\"[data-vc-date]\");if(!a||state.lastDateEl===a)return;state.lastDateEl=a,createDateRangeTooltip(state.self,state.tooltipEl,a),removeHoverEffect();const l=a.dataset.vcDate,o=getDate(state.self.context.selectedDates[0]),s=getDate(l),i=state.self.context.mainElement.querySelectorAll(`[data-vc-date=\"${state.self.context.selectedDates[0]}\"]`),r=state.self.context.mainElement.querySelectorAll(`[data-vc-date=\"${l}\"]`),[c,d]=o{const t=e.target.closest(\"[data-vc-date-selected]\");if(!t&&state.lastDateEl)return state.lastDateEl=null,void createDateRangeTooltip(state.self,state.tooltipEl,null);t&&state.lastDateEl!==t&&(state.lastDateEl=t,createDateRangeTooltip(state.self,state.tooltipEl,t))},optimizedHoverHandler=e=>t=>{state.isHovering||(state.isHovering=!0,requestAnimationFrame((()=>{e(t),state.isHovering=!1})))},optimizedHandleHoverDatesEvent=optimizedHoverHandler(handleHoverDatesEvent),optimizedHandleHoverSelectedDatesRangeEvent=optimizedHoverHandler(handleHoverSelectedDatesRangeEvent),handleCancelSelectionDates=e=>{state.self&&\"Escape\"===e.key&&(state.lastDateEl=null,setContext(state.self,\"selectedDates\",[]),state.self.context.mainElement.removeEventListener(\"mousemove\",optimizedHandleHoverDatesEvent),state.self.context.mainElement.removeEventListener(\"keydown\",handleCancelSelectionDates),createDateRangeTooltip(state.self,state.tooltipEl,null),removeHoverEffect())},handleMouseLeave=()=>{null!==state.timeoutId&&clearTimeout(state.timeoutId),state.timeoutId=setTimeout((()=>{state.lastDateEl=null,createDateRangeTooltip(state.self,state.tooltipEl,null),removeHoverEffect()}),50)},updateDisabledDates=()=>{var e,t,n,a;if(!(null==(n=null==(t=null==(e=state.self)?void 0:e.context)?void 0:t.selectedDates)?void 0:n[0])||!(null==(a=state.self.context.disableDates)?void 0:a[0]))return;const l=getDate(state.self.context.selectedDates[0]),[o,s]=state.self.context.disableDates.map((e=>getDate(e))).reduce((([e,t],n)=>[l>=n?n:e,l{state.self=e,state.lastDateEl=t,removeHoverEffect(),e.disableDatesGaps&&(state.rangeMin=state.rangeMin?state.rangeMin:e.context.displayDateMin,state.rangeMax=state.rangeMax?state.rangeMax:e.context.displayDateMax),e.onCreateDateRangeTooltip&&(state.tooltipEl=e.context.mainElement.querySelector(\"[data-vc-date-range-tooltip]\"));const n=null==t?void 0:t.dataset.vcDate;if(n){const t=1===e.context.selectedDates.length&&e.context.selectedDates[0].includes(n),a=t&&!canToggleSelection(e)?[n,n]:t&&canToggleSelection(e)?[]:e.context.selectedDates.length>1?[n]:[...e.context.selectedDates,n];setContext(e,\"selectedDates\",a),e.context.selectedDates.length>1&&e.context.selectedDates.sort(((e,t)=>+new Date(e)-+new Date(t)))}({set:()=>(e.disableDatesGaps&&updateDisabledDates(),createDateRangeTooltip(state.self,state.tooltipEl,t),state.self.context.mainElement.removeEventListener(\"mousemove\",optimizedHandleHoverSelectedDatesRangeEvent),state.self.context.mainElement.removeEventListener(\"mouseleave\",handleMouseLeave),state.self.context.mainElement.removeEventListener(\"keydown\",handleCancelSelectionDates),state.self.context.mainElement.addEventListener(\"mousemove\",optimizedHandleHoverDatesEvent),state.self.context.mainElement.addEventListener(\"mouseleave\",handleMouseLeave),state.self.context.mainElement.addEventListener(\"keydown\",handleCancelSelectionDates),()=>{state.self.context.mainElement.removeEventListener(\"mousemove\",optimizedHandleHoverDatesEvent),state.self.context.mainElement.removeEventListener(\"mouseleave\",handleMouseLeave),state.self.context.mainElement.removeEventListener(\"keydown\",handleCancelSelectionDates)}),reset:()=>{const[n,a]=[e.context.selectedDates[0],e.context.selectedDates[e.context.selectedDates.length-1]],l=e.context.selectedDates[0]!==e.context.selectedDates[e.context.selectedDates.length-1],o=parseDates([`${n}:${a}`]).filter((t=>!e.context.disableDates.includes(t))),s=l?e.enableEdgeDatesOnly?[n,a]:o:[e.context.selectedDates[0],e.context.selectedDates[0]];if(setContext(e,\"selectedDates\",s),e.disableDatesGaps&&(setContext(e,\"displayDateMin\",state.rangeMin),setContext(e,\"displayDateMax\",state.rangeMax)),state.self.context.mainElement.removeEventListener(\"mousemove\",optimizedHandleHoverDatesEvent),state.self.context.mainElement.removeEventListener(\"mouseleave\",handleMouseLeave),state.self.context.mainElement.removeEventListener(\"keydown\",handleCancelSelectionDates),e.onCreateDateRangeTooltip)return e.context.selectedDates[0]||(state.self.context.mainElement.removeEventListener(\"mousemove\",optimizedHandleHoverSelectedDatesRangeEvent),state.self.context.mainElement.removeEventListener(\"mouseleave\",handleMouseLeave),createDateRangeTooltip(state.self,state.tooltipEl,null)),e.context.selectedDates[0]&&(state.self.context.mainElement.addEventListener(\"mousemove\",optimizedHandleHoverSelectedDatesRangeEvent),state.self.context.mainElement.addEventListener(\"mouseleave\",handleMouseLeave),createDateRangeTooltip(state.self,state.tooltipEl,t)),()=>{state.self.context.mainElement.removeEventListener(\"mousemove\",optimizedHandleHoverSelectedDatesRangeEvent),state.self.context.mainElement.removeEventListener(\"mouseleave\",handleMouseLeave)}}})[1===e.context.selectedDates.length?\"set\":\"reset\"]()},updateDateModifier=e=>{e.context.mainElement.querySelectorAll(\"[data-vc-date]\").forEach((t=>{const n=t.querySelector(\"[data-vc-date-btn]\"),a=t.dataset.vcDate,l=getDate(a).getDay();setDateModifier(e,e.context.selectedYear,t,n,l,a,\"current\")}))},handleClickDate=(e,t)=>{var n;const a=t.target,l=a.closest(\"[data-vc-date-btn]\");if(!e.selectionDatesMode||![\"single\",\"multiple\",\"multiple-ranged\"].includes(e.selectionDatesMode)||!l)return;const o=l.closest(\"[data-vc-date]\");({single:()=>handleSelectDate(e,o,!1),multiple:()=>handleSelectDate(e,o,!0),\"multiple-ranged\":()=>handleSelectDateRange(e,o)})[e.selectionDatesMode](),null==(n=e.context.selectedDates)||n.sort(((e,t)=>+new Date(e)-+new Date(t))),e.onClickDate&&e.onClickDate(e,t),e.inputMode&&e.context.inputElement&&e.context.mainElement&&e.onChangeToInput&&e.onChangeToInput(e,t);const s=a.closest('[data-vc-date-month=\"prev\"]'),i=a.closest('[data-vc-date-month=\"next\"]');({prev:()=>e.enableMonthChangeOnDayClick?handleMonth(e,\"prev\"):updateDateModifier(e),next:()=>e.enableMonthChangeOnDayClick?handleMonth(e,\"next\"):updateDateModifier(e),current:()=>updateDateModifier(e)})[s?\"prev\":i?\"next\":\"current\"]()},typeClick=[\"month\",\"year\"],getValue=(e,t,n)=>{const{currentValue:a,columnID:l}=getColumnID(e,t);return\"month\"===e.context.currentType&&l>=0?n-l:\"year\"===e.context.currentType&&e.context.selectedYear!==a?n-1:n},handleMultipleYearSelection=(e,t)=>{const n=getValue(e,\"year\",Number(t.dataset.vcYearsYear)),a=getDate(e.context.dateMin),l=getDate(e.context.dateMax),o=e.context.displayMonthsCount-1,{columnID:s}=getColumnID(e,\"year\"),i=e.context.selectedMonthl.getMonth()-o+s&&n>=l.getFullYear(),c=nl.getFullYear(),u=i||c?a.getFullYear():r||d?l.getFullYear():n,m=i||c?a.getMonth():r||d?l.getMonth()-o+s:e.context.selectedMonth;setContext(e,\"selectedYear\",u),setContext(e,\"selectedMonth\",m)},handleMultipleMonthSelection=(e,t)=>{const n=t.closest('[data-vc-column=\"month\"]').querySelector('[data-vc=\"year\"]'),a=getValue(e,\"month\",Number(t.dataset.vcMonthsMonth)),l=Number(n.dataset.vcYear),o=getDate(e.context.dateMin),s=getDate(e.context.dateMax),i=as.getMonth()&&l>=s.getFullYear();setContext(e,\"selectedYear\",l),setContext(e,\"selectedMonth\",i?o.getMonth():r?s.getMonth():a)},handleItemClick=(e,t,n,a)=>{var l;({year:()=>{if(\"multiple\"===e.type)return handleMultipleYearSelection(e,a);setContext(e,\"selectedYear\",Number(a.dataset.vcYearsYear))},month:()=>{if(\"multiple\"===e.type)return handleMultipleMonthSelection(e,a);setContext(e,\"selectedMonth\",Number(a.dataset.vcMonthsMonth))}})[n]();({year:()=>{var n;return null==(n=e.onClickYear)?void 0:n.call(e,e,t)},month:()=>{var n;return null==(n=e.onClickMonth)?void 0:n.call(e,e,t)}})[n](),e.context.currentType!==e.type?(setContext(e,\"currentType\",e.type),create(e),null==(l=e.context.mainElement.querySelector(`[data-vc=\"${n}\"]`))||l.focus()):setYearModifier(e,a,n,!0,!0)},handleClickType=(e,t,n)=>{var a;const l=t.target,o=l.closest(`[data-vc=\"${n}\"]`),s={year:()=>createYears(e,l),month:()=>createMonths(e,l)};if(o&&e.onClickTitle&&e.onClickTitle(e,t),o&&e.context.currentType!==n)return s[n]();const i=l.closest(`[data-vc-${n}s-${n}]`);if(i)return handleItemClick(e,t,n,i);const r=l.closest('[data-vc=\"grid\"]'),c=l.closest('[data-vc=\"column\"]');(e.context.currentType===n&&o||\"multiple\"===e.type&&e.context.currentType===n&&r&&!c)&&(setContext(e,\"currentType\",e.type),create(e),null==(a=e.context.mainElement.querySelector(`[data-vc=\"${n}\"]`))||a.focus())},handleClickMonthOrYear=(e,t)=>{const n={month:e.selectionMonthsMode,year:e.selectionYearsMode};typeClick.forEach((a=>{n[a]&&t.target&&handleClickType(e,t,a)}))},handleClickWeekNumber=(e,t)=>{if(!e.enableWeekNumbers||!e.onClickWeekNumber)return;const n=t.target.closest(\"[data-vc-week-number]\"),a=e.context.mainElement.querySelectorAll(\"[data-vc-date-week-number]\");if(!n||!a[0])return;const l=Number(n.innerText),o=Number(n.dataset.vcWeekYear),s=Array.from(a).filter((e=>Number(e.dataset.vcDateWeekNumber)===l));e.onClickWeekNumber(e,l,o,s,t)},handleClickWeekDay=(e,t)=>{if(!e.onClickWeekDay)return;const n=t.target.closest(\"[data-vc-week-day]\"),a=t.target.closest('[data-vc=\"column\"]'),l=a?a.querySelectorAll(\"[data-vc-date-week-day]\"):e.context.mainElement.querySelectorAll(\"[data-vc-date-week-day]\");if(!n||!l[0])return;const o=Number(n.dataset.vcWeekDay),s=Array.from(l).filter((e=>Number(e.dataset.vcDateWeekDay)===o));e.onClickWeekDay(e,o,s,t)},handleClick=e=>{const t=t=>{handleClickArrow(e,t),handleClickWeekDay(e,t),handleClickWeekNumber(e,t),handleClickDate(e,t),handleClickMonthOrYear(e,t)};return e.context.mainElement.addEventListener(\"click\",t),()=>e.context.mainElement.removeEventListener(\"click\",t)},initMonthsCount=e=>{if(\"multiple\"===e.type&&(e.displayMonthsCount<=1||e.displayMonthsCount>12))throw new Error(errorMessages.incorrectMonthsCount);if(\"multiple\"!==e.type&&e.displayMonthsCount>1)throw new Error(errorMessages.incorrectMonthsCount);setContext(e,\"displayMonthsCount\",e.displayMonthsCount?e.displayMonthsCount:\"multiple\"===e.type?2:1)},getLocalDate=()=>{const e=new Date;return new Date(e.getTime()-6e4*e.getTimezoneOffset()).toISOString().substring(0,10)},resolveDate=(e,t)=>\"today\"===e?getLocalDate():e instanceof Date||\"number\"==typeof e||\"string\"==typeof e?parseDates([e])[0]:t,initRange=e=>{var t,n,a;const l=resolveDate(e.dateMin,e.dateMin),o=resolveDate(e.dateMax,e.dateMax),s=resolveDate(e.displayDateMin,l),i=resolveDate(e.displayDateMax,o);setContext(e,\"dateToday\",resolveDate(e.dateToday,e.dateToday)),setContext(e,\"displayDateMin\",s?getDate(l)>=getDate(s)?l:s:l),setContext(e,\"displayDateMax\",i?getDate(o)<=getDate(i)?o:i:o);const r=e.disableDatesPast&&!e.disableAllDates&&getDate(s)1&&e.context.disableDates.sort(((e,t)=>+new Date(e)-+new Date(t))),setContext(e,\"enableDates\",e.enableDates[0]?parseDates(e.enableDates):[]),(null==(t=e.context.enableDates)?void 0:t[0])&&(null==(n=e.context.disableDates)?void 0:n[0])&&setContext(e,\"disableDates\",e.context.disableDates.filter((t=>!e.context.enableDates.includes(t)))),e.context.enableDates.length>1&&e.context.enableDates.sort(((e,t)=>+new Date(e)-+new Date(t))),(null==(a=e.context.enableDates)?void 0:a[0])&&e.disableAllDates&&(setContext(e,\"displayDateMin\",e.context.enableDates[0]),setContext(e,\"displayDateMax\",e.context.enableDates[e.context.enableDates.length-1])),setContext(e,\"dateMin\",e.displayDisabledDates?l:e.context.displayDateMin),setContext(e,\"dateMax\",e.displayDisabledDates?o:e.context.displayDateMax)},initSelectedDates=e=>{var t;setContext(e,\"selectedDates\",(null==(t=e.selectedDates)?void 0:t[0])?parseDates(e.selectedDates):[])},setInitialContext=(e,t,n)=>{setContext(e,\"selectedMonth\",t),setContext(e,\"selectedYear\",n),setContext(e,\"displayYear\",n)},initSelectedMonthYear=e=>{var t;if(e.enableJumpToSelectedDate&&(null==(t=e.selectedDates)?void 0:t[0])&&void 0===e.selectedMonth&&void 0===e.selectedYear){const t=getDate(parseDates(e.selectedDates)[0]);return void setInitialContext(e,t.getMonth(),t.getFullYear())}const n=void 0!==e.selectedMonth&&Number(e.selectedMonth)>=0&&Number(e.selectedMonth)<12,a=void 0!==e.selectedYear&&Number(e.selectedYear)>=0&&Number(e.selectedYear)<=9999;setInitialContext(e,n?Number(e.selectedMonth):getDate(e.context.dateToday).getMonth(),a?Number(e.selectedYear):getDate(e.context.dateToday).getFullYear())},initTime=e=>{var t,n,a;if(!e.selectionTimeMode)return;if(![12,24].includes(e.selectionTimeMode))throw new Error(errorMessages.incorrectTime);const l=12===e.selectionTimeMode,o=l?/^(0[1-9]|1[0-2]):([0-5][0-9]) ?(AM|PM)?$/i:/^([0-1]?[0-9]|2[0-3]):([0-5][0-9])$/;let[s,i,r]=null!=(a=null==(n=null==(t=e.selectedTime)?void 0:t.match(o))?void 0:n.slice(1))?a:[];s?l&&!r&&(r=\"AM\"):(s=l?transformTime12(String(e.timeMinHour)):String(e.timeMinHour),i=String(e.timeMinMinute),r=l?Number(transformTime12(String(e.timeMinHour)))>=12?\"PM\":\"AM\":null),setContext(e,\"selectedHours\",s.padStart(2,\"0\")),setContext(e,\"selectedMinutes\",i.padStart(2,\"0\")),setContext(e,\"selectedKeeping\",r),setContext(e,\"selectedTime\",`${e.context.selectedHours}:${e.context.selectedMinutes}${r?` ${r}`:\"\"}`)},initAllVariables=e=>{setContext(e,\"currentType\",e.type),initMonthsCount(e),initRange(e),initSelectedMonthYear(e),initSelectedDates(e),initTime(e)},reset=(e,{year:t,month:n,dates:a,time:l,locale:o},s=!0)=>{var i;const r={year:e.selectedYear,month:e.selectedMonth,dates:e.selectedDates,time:e.selectedTime};if(e.selectedYear=t?r.year:e.context.selectedYear,e.selectedMonth=n?r.month:e.context.selectedMonth,e.selectedTime=l?r.time:e.context.selectedTime,e.selectedDates=\"only-first\"===a&&(null==(i=e.context.selectedDates)?void 0:i[0])?[e.context.selectedDates[0]]:!0===a?r.dates:e.context.selectedDates,o){setContext(e,\"locale\",{months:{short:[],long:[]},weekdays:{short:[],long:[]}})}initAllVariables(e),s&&create(e),e.selectedYear=r.year,e.selectedMonth=r.month,e.selectedDates=r.dates,e.selectedTime=r.time,\"multiple-ranged\"===e.selectionDatesMode&&a&&handleSelectDateRange(e,null)};function findBestPickerPosition(e,t){const n=\"left\";if(!t||!e)return n;const{canShow:a,parentPositions:l}=getAvailablePosition(e,t),o=a.left&&a.right;return(o&&a.bottom?\"center\":o&&a.top?[\"top\",\"center\"]:Array.isArray(l)?[\"bottom\"===l[0]?\"top\":\"bottom\",...l.slice(1)]:l)||n}const setPosition=(e,t,n)=>{if(!e)return;const a=\"auto\"===n?findBestPickerPosition(e,t):n,l={top:-t.offsetHeight,bottom:e.offsetHeight,left:0,center:e.offsetWidth/2-t.offsetWidth/2,right:e.offsetWidth-t.offsetWidth},o=Array.isArray(a)?a[0]:\"bottom\",s=Array.isArray(a)?a[1]:a;t.dataset.vcPosition=o;const{top:i,left:r}=getOffset(e),c=i+l[o];let d=r+l[s];const{vw:u}=getViewportDimensions();if(d+t.clientWidth>u){const e=window.innerWidth-document.body.clientWidth;d=u-t.clientWidth-e}else d<0&&(d=0);Object.assign(t.style,{left:`${d}px`,top:`${c}px`})},createToInput=(e,t=!0)=>{const n=document.createElement(\"div\");return n.className=e.styles.calendar,n.dataset.vc=\"calendar\",n.dataset.vcInput=\"\",n.dataset.vcCalendarHidden=\"\",n.style.visibility=\"hidden\",setContext(e,\"inputModeInit\",!0),setContext(e,\"mainElement\",n),document.body.appendChild(e.context.mainElement),t&&queueMicrotask((()=>{setPosition(e.context.inputElement,n,e.positionToInput),e.context.mainElement.style.visibility=\"visible\",e.show()})),reset(e,{year:!0,month:!0,dates:!0,time:!0,locale:!0}),e.onInit&&e.onInit(e),handleArrowKeys(e),handleClick(e)},handleInput=e=>{const t=[];setContext(e,\"inputElement\",e.context.mainElement);const n=()=>setPosition(e.context.inputElement,e.context.mainElement,e.positionToInput),a=t=>{var n,l;\"Escape\"===t.key&&((null==(n=null==e?void 0:e.context)?void 0:n.inputElement)&&(null==(l=null==e?void 0:e.context)?void 0:l.mainElement)&&e.hide(),document.removeEventListener(\"keydown\",a))},l=t=>{e&&t.target!==e.context.inputElement&&!e.context.mainElement.contains(t.target)&&(e.context.inputElement&&e.context.mainElement&&e.hide(),window.removeEventListener(\"resize\",n),document.removeEventListener(\"click\",l,{capture:!0}))},o=()=>{e.context.inputModeInit?(setPosition(e.context.inputElement,e.context.mainElement,e.positionToInput),e.context.mainElement.style.visibility=\"visible\",e.show()):t.push(createToInput(e)),window.addEventListener(\"resize\",n),document.addEventListener(\"click\",l,{capture:!0}),document.addEventListener(\"keydown\",a)};return e.context.inputElement.addEventListener(\"click\",o),e.context.inputElement.addEventListener(\"focus\",o),()=>{t.forEach((e=>e()))}},init=e=>(setContext(e,\"originalElement\",e.context.mainElement.cloneNode(!0)),setContext(e,\"isInit\",!0),e.inputMode?handleInput(e):(initAllVariables(e),create(e),e.onInit&&e.onInit(e),handleArrowKeys(e),handleClick(e))),update=(e,t)=>{if(!e.context.isInit)throw new Error(errorMessages.notInit);reset(e,__spreadValues(__spreadValues({},{year:!0,month:!0,dates:!0,time:!0,locale:!0}),t),!(e.inputMode&&!e.context.inputModeInit)),e.onUpdate&&e.onUpdate(e)},replaceProperties=(e,t)=>{const n=Object.keys(t);for(let a=0;a{replaceProperties(e,t),e.context.isInit&&update(e,n)},show=e=>{e.context.currentType?(e.context.mainElement.removeAttribute(\"data-vc-calendar-hidden\"),e.onShow&&e.onShow(e)):e.context.mainElement.click()},labels={application:\"Calendar\",navigation:\"Calendar Navigation\",arrowNext:{month:\"Next month\",year:\"Next list of years\"},arrowPrev:{month:\"Previous month\",year:\"Previous list of years\"},month:\"Select month, current selected month:\",months:\"List of months\",year:\"Select year, current selected year:\",years:\"List of years\",week:\"Days of the week\",weekNumber:\"Numbers of weeks in a year\",dates:\"Dates in the current month\",selectingTime:\"Selecting a time \",inputHour:\"Hours\",inputMinute:\"Minutes\",rangeHour:\"Slider for selecting hours\",rangeMinute:\"Slider for selecting minutes\",btnKeeping:\"Switch AM/PM, current position:\"},styles={calendar:\"vc\",controls:\"vc-controls\",grid:\"vc-grid\",column:\"vc-column\",header:\"vc-header\",headerContent:\"vc-header__content\",month:\"vc-month\",year:\"vc-year\",arrowPrev:\"vc-arrow vc-arrow_prev\",arrowNext:\"vc-arrow vc-arrow_next\",wrapper:\"vc-wrapper\",content:\"vc-content\",months:\"vc-months\",monthsMonth:\"vc-months__month\",years:\"vc-years\",yearsYear:\"vc-years__year\",week:\"vc-week\",weekDay:\"vc-week__day\",weekNumbers:\"vc-week-numbers\",weekNumbersTitle:\"vc-week-numbers__title\",weekNumbersContent:\"vc-week-numbers__content\",weekNumber:\"vc-week-number\",dates:\"vc-dates\",date:\"vc-date\",dateBtn:\"vc-date__btn\",datePopup:\"vc-date__popup\",dateRangeTooltip:\"vc-date-range-tooltip\",time:\"vc-time\",timeContent:\"vc-time__content\",timeHour:\"vc-time__hour\",timeMinute:\"vc-time__minute\",timeKeeping:\"vc-time__keeping\",timeRanges:\"vc-time__ranges\",timeRange:\"vc-time__range\"};class OptionsCalendar{constructor(){__publicField(this,\"type\",\"default\"),__publicField(this,\"inputMode\",!1),__publicField(this,\"positionToInput\",\"left\"),__publicField(this,\"firstWeekday\",1),__publicField(this,\"monthsToSwitch\",1),__publicField(this,\"themeAttrDetect\",\"html[data-theme]\"),__publicField(this,\"locale\",\"en\"),__publicField(this,\"dateToday\",\"today\"),__publicField(this,\"dateMin\",\"1970-01-01\"),__publicField(this,\"dateMax\",\"2470-12-31\"),__publicField(this,\"displayDateMin\"),__publicField(this,\"displayDateMax\"),__publicField(this,\"displayDatesOutside\",!0),__publicField(this,\"displayDisabledDates\",!1),__publicField(this,\"displayMonthsCount\"),__publicField(this,\"disableDates\",[]),__publicField(this,\"disableAllDates\",!1),__publicField(this,\"disableDatesPast\",!1),__publicField(this,\"disableDatesGaps\",!1),__publicField(this,\"disableWeekdays\",[]),__publicField(this,\"disableToday\",!1),__publicField(this,\"enableDates\",[]),__publicField(this,\"enableEdgeDatesOnly\",!0),__publicField(this,\"enableDateToggle\",!0),__publicField(this,\"enableWeekNumbers\",!1),__publicField(this,\"enableMonthChangeOnDayClick\",!0),__publicField(this,\"enableJumpToSelectedDate\",!1),__publicField(this,\"selectionDatesMode\",\"single\"),__publicField(this,\"selectionMonthsMode\",!0),__publicField(this,\"selectionYearsMode\",!0),__publicField(this,\"selectionTimeMode\",!1),__publicField(this,\"selectedDates\",[]),__publicField(this,\"selectedMonth\"),__publicField(this,\"selectedYear\"),__publicField(this,\"selectedHolidays\",[]),__publicField(this,\"selectedWeekends\",[0,6]),__publicField(this,\"selectedTime\"),__publicField(this,\"selectedTheme\",\"system\"),__publicField(this,\"timeMinHour\",0),__publicField(this,\"timeMaxHour\",23),__publicField(this,\"timeMinMinute\",0),__publicField(this,\"timeMaxMinute\",59),__publicField(this,\"timeControls\",\"all\"),__publicField(this,\"timeStepHour\",1),__publicField(this,\"timeStepMinute\",1),__publicField(this,\"sanitizerHTML\",(e=>e)),__publicField(this,\"onClickDate\"),__publicField(this,\"onClickWeekDay\"),__publicField(this,\"onClickWeekNumber\"),__publicField(this,\"onClickTitle\"),__publicField(this,\"onClickMonth\"),__publicField(this,\"onClickYear\"),__publicField(this,\"onClickArrow\"),__publicField(this,\"onChangeTime\"),__publicField(this,\"onChangeToInput\"),__publicField(this,\"onCreateDateRangeTooltip\"),__publicField(this,\"onCreateDateEls\"),__publicField(this,\"onCreateMonthEls\"),__publicField(this,\"onCreateYearEls\"),__publicField(this,\"onInit\"),__publicField(this,\"onUpdate\"),__publicField(this,\"onDestroy\"),__publicField(this,\"onShow\"),__publicField(this,\"onHide\"),__publicField(this,\"popups\",{}),__publicField(this,\"labels\",__spreadValues({},labels)),__publicField(this,\"layouts\",{default:\"\",multiple:\"\",month:\"\",year:\"\"}),__publicField(this,\"styles\",__spreadValues({},styles))}}const _Calendar=class e extends OptionsCalendar{constructor(t,n){var a;super(),__publicField(this,\"init\",(()=>init(this))),__publicField(this,\"update\",(e=>update(this,e))),__publicField(this,\"destroy\",(()=>destroy(this))),__publicField(this,\"show\",(()=>show(this))),__publicField(this,\"hide\",(()=>hide(this))),__publicField(this,\"set\",((e,t)=>set(this,e,t))),__publicField(this,\"context\"),this.context=__spreadProps(__spreadValues({},this.context),{locale:{months:{short:[],long:[]},weekdays:{short:[],long:[]}}}),setContext(this,\"mainElement\",\"string\"==typeof t?null!=(a=e.memoizedElements.get(t))?a:this.queryAndMemoize(t):t),n&&replaceProperties(this,n)}queryAndMemoize(t){const n=document.querySelector(t);if(!n)throw new Error(errorMessages.notFoundSelector(t));return e.memoizedElements.set(t,n),n}};__publicField(_Calendar,\"memoizedElements\",new Map);let Calendar=_Calendar;export{Calendar};", "import { Calendar } from \"vanilla-calendar-pro\";\nimport { Options, Reset, Styles } from \"vanilla-calendar-pro/types\";\n\nclass CustomVanillaCalendar extends Calendar {\n\tconstructor(selector: HTMLElement | string, options?: Partial) {\n\t\tsuper(selector, options);\n\n\t\tconst parentSet = this.set;\n\n\t\tthis.set = (options: Options, resetOptions?: Partial) => {\n\t\t\tif (parentSet) parentSet.call(this, options, resetOptions);\n\n\t\t\tif (options.selectedTime && this.onChangeTime) {\n\t\t\t\tthis.onChangeTime(this, null, true);\n\t\t\t}\n\t\t\tif (options.selectedMonth && this.onClickMonth) {\n\t\t\t\tthis.onClickMonth(this, null);\n\t\t\t}\n\t\t\tif (options.selectedYear && this.onClickYear) {\n\t\t\t\tthis.onClickYear(this, null);\n\t\t\t}\n\t\t};\n\t}\n\n\tstatic get defaultStyles() {\n\t\treturn {\n\t\t\tcalendar: \"vc\",\n\t\t\tcontrols: \"vc-controls\",\n\t\t\tgrid: \"vc-grid\",\n\t\t\tcolumn: \"vc-column\",\n\t\t\theader: \"vc-header\",\n\t\t\theaderContent: \"vc-header__content\",\n\t\t\tmonth: \"vc-month\",\n\t\t\tyear: \"vc-year\",\n\t\t\tarrowPrev: \"vc-arrow vc-arrow_prev\",\n\t\t\tarrowNext: \"vc-arrow vc-arrow_next\",\n\t\t\twrapper: \"vc-wrapper\",\n\t\t\tcontent: \"vc-content\",\n\t\t\tmonths: \"vc-months\",\n\t\t\tmonthsMonth: \"vc-months__month\",\n\t\t\tyears: \"vc-years\",\n\t\t\tyearsYear: \"vc-years__year\",\n\t\t\tweek: \"vc-week\",\n\t\t\tweekDay: \"vc-week__day\",\n\t\t\tweekNumbers: \"vc-week-numbers\",\n\t\t\tweekNumbersTitle: \"vc-week-numbers__title\",\n\t\t\tweekNumbersContent: \"vc-week-numbers__content\",\n\t\t\tweekNumber: \"vc-week-number\",\n\t\t\tdates: \"vc-dates\",\n\t\t\tdate: \"vc-date\",\n\t\t\tdateBtn: \"vc-date__btn\",\n\t\t\tdatePopup: \"vc-date__popup\",\n\t\t\tdateRangeTooltip: \"vc-date-range-tooltip\",\n\t\t\ttime: \"vc-time\",\n\t\t\ttimeContent: \"vc-time__content\",\n\t\t\ttimeHour: \"vc-time__hour\",\n\t\t\ttimeMinute: \"vc-time__minute\",\n\t\t\ttimeKeeping: \"vc-time__keeping\",\n\t\t\ttimeRanges: \"vc-time__ranges\",\n\t\t\ttimeRange: \"vc-time__range\",\n\t\t};\n\t}\n\n\tpublic logInfo() {\n\t\tconsole.log(\"This log is from CustomVanillaCalendar!\", this);\n\t}\n}\n\nexport default CustomVanillaCalendar;\n", "export const templates = {\n default: `\n
\n
\n <#CustomArrowPrev />\n
\n
\n <#CustomMonth />\n /\n <#CustomYear />\n
\n
\n <#CustomArrowNext />\n
\n
\n
\n
\n <#Week />\n <#Dates />\n
\n
\n
`,\n multiple: `\n
\n <#CustomArrowPrev />\n
\n
\n <#CustomArrowNext />\n
\n
\n <#Multiple>\n
\n
\n
\n <#CustomMonth />\n /\n <#CustomYear />\n
\n
\n
\n
\n <#Week />\n <#Dates />\n
\n
\n
\n <#/Multiple>\n
\n
`,\n year: `\n
\n
\n <#CustomArrowPrev />\n
\n
\n <#Month />\n /\n <#Year />\n
\n
\n <#CustomArrowNext />\n
\n
\n
\n `,\n month: `\n
\n <#Month />\n /\n <#Year />\n
\n
\n `,\n // Custom\n years: (options: string) => {\n return `\n \n \n
`;\n },\n months: `\n \n \n
`,\n hours: `\n
\n
\n
`,\n minutes: `\n
\n
\n
`,\n meridiem: ``\n};", "/*\n * HSDatepicker\n * @version: 3.0.1\n * @author: Preline Labs Ltd.\n * @license: Licensed under MIT and Preline UI Fair Use License (https://preline.co/docs/license.html)\n * Copyright 2024 Preline Labs Ltd.\n */\n\nimport { dispatch } from \"../../utils\";\nimport { Calendar, DatesArr, Range } from \"vanilla-calendar-pro\";\n\nimport CustomVanillaCalendar from \"./vanilla-datepicker-pro\";\nimport { templates } from \"./templates\";\nimport { classToClassList, htmlToElement } from \"../../utils\";\nimport HSSelect from \"../select\";\nimport { ISelectOptions } from \"../select/interfaces\";\n\nimport { ICustomDatepickerOptions, IDatepicker } from \"./interfaces\";\n\nimport HSBasePlugin from \"../base-plugin\";\nimport { ICollectionItem } from \"../../interfaces\";\n\ndeclare var _: any;\n\nclass HSDatepicker extends HSBasePlugin<{}> implements IDatepicker {\n\tprivate dataOptions: ICustomDatepickerOptions;\n\tprivate updatedStyles: ICustomDatepickerOptions[\"styles\"];\n\n\tprivate vanillaCalendar: Calendar;\n\n\tconstructor(el: HTMLElement, options?: {}, events?: {}) {\n\t\tsuper(el, options, events);\n\n\t\tconst dataOptions: ICustomDatepickerOptions =\n\t\t\tel.getAttribute(\"data-hs-datepicker\")\n\t\t\t\t? JSON.parse(el.getAttribute(\"data-hs-datepicker\")!)\n\t\t\t\t: {};\n\n\t\tthis.dataOptions = {\n\t\t\t...dataOptions,\n\t\t\t...options,\n\t\t};\n\n\t\tconst removeDefaultStyles =\n\t\t\ttypeof this.dataOptions?.removeDefaultStyles !== \"undefined\"\n\t\t\t\t? this.dataOptions?.removeDefaultStyles\n\t\t\t\t: false;\n\n\t\tthis.updatedStyles = _.mergeWith(\n\t\t\tremoveDefaultStyles ? {} : CustomVanillaCalendar.defaultStyles,\n\t\t\tthis.dataOptions?.styles || {},\n\t\t\t(a: any, b: any) => {\n\t\t\t\tif (typeof a === \"string\" && typeof b === \"string\") {\n\t\t\t\t\treturn `${a} ${b}`;\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tconst today = new Date();\n\t\tconst defaults = {\n\t\t\tstyles: this.updatedStyles,\n\t\t\tdateMin: this.dataOptions.dateMin ?? today.toISOString().split(\"T\")[0],\n\t\t\tdateMax: this.dataOptions.dateMax ?? \"2470-12-31\",\n\t\t\tmode: this.dataOptions.mode ?? \"default\",\n\t\t\tinputMode: typeof this.dataOptions.inputMode !== \"undefined\"\n\t\t\t\t? this.dataOptions.inputMode\n\t\t\t\t: true,\n\t\t};\n\n\t\tconst chainCallbacks = (\n\t\t\tsuperCallback?: Function,\n\t\t\tcustomCallback?: (self: Calendar) => void,\n\t\t) =>\n\t\t(self: Calendar) => {\n\t\t\tsuperCallback?.(self);\n\t\t\tcustomCallback?.(self);\n\t\t};\n\t\tconst initTime = (self: Calendar) => {\n\t\t\tif (this.hasTime(self)) this.initCustomTime(self);\n\t\t};\n\n\t\tconst _options = {\n\t\t\tlayouts: {\n\t\t\t\tmonth: templates.month,\n\t\t\t},\n\t\t\tonInit: chainCallbacks(this.dataOptions.onInit, (self) => {\n\t\t\t\tif (defaults.mode === \"custom-select\" && !this.dataOptions.inputMode) {\n\t\t\t\t\tinitTime(self);\n\t\t\t\t}\n\t\t\t}),\n\t\t\tonShow: chainCallbacks(this.dataOptions.onShow, (self) => {\n\t\t\t\tif (defaults.mode === \"custom-select\") {\n\t\t\t\t\tthis.updateCustomSelects(self);\n\t\t\t\t\tinitTime(self);\n\t\t\t\t}\n\t\t\t}),\n\t\t\tonHide: chainCallbacks(this.dataOptions.onHide, (self) => {\n\t\t\t\tif (defaults.mode === \"custom-select\") {\n\t\t\t\t\tthis.destroySelects(self.context.mainElement);\n\t\t\t\t}\n\t\t\t}),\n\t\t\tonUpdate: chainCallbacks(this.dataOptions.onUpdate, (self) => {\n\t\t\t\tthis.updateCalendar(self.context.mainElement);\n\t\t\t}),\n\t\t\tonCreateDateEls: chainCallbacks(\n\t\t\t\tthis.dataOptions.onCreateDateEls,\n\t\t\t\t(self) => {\n\t\t\t\t\tif (defaults.mode === \"custom-select\") this.updateCustomSelects(self);\n\t\t\t\t},\n\t\t\t),\n\t\t\tonChangeToInput: chainCallbacks(\n\t\t\t\tthis.dataOptions.onChangeToInput,\n\t\t\t\t(self) => {\n\t\t\t\t\tif (!self.context.inputElement) return;\n\n\t\t\t\t\tthis.setInputValue(\n\t\t\t\t\t\tself.context.inputElement,\n\t\t\t\t\t\tself.context.selectedDates,\n\t\t\t\t\t);\n\n\t\t\t\t\tconst data = {\n\t\t\t\t\t\tselectedDates: self.context.selectedDates,\n\t\t\t\t\t\tselectedTime: self.context.selectedTime,\n\t\t\t\t\t\trest: self.context,\n\t\t\t\t\t};\n\n\t\t\t\t\tthis.fireEvent(\"change\", data);\n\t\t\t\t\tdispatch(\"change.hs.datepicker\", this.el, data);\n\t\t\t\t},\n\t\t\t),\n\t\t\tonChangeTime: chainCallbacks(this.dataOptions.onChangeTime, initTime),\n\t\t\tonClickYear: chainCallbacks(this.dataOptions.onClickYear, initTime),\n\t\t\tonClickMonth: chainCallbacks(this.dataOptions.onClickMonth, initTime),\n\t\t\tonClickArrow: chainCallbacks(this.dataOptions.onClickArrow, (self) => {\n\t\t\t\tif (defaults.mode === \"custom-select\") {\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tthis.disableNav();\n\t\t\t\t\t\tthis.disableOptions();\n\t\t\t\t\t\tthis.updateCalendar(self.context.mainElement);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}),\n\t\t};\n\n\t\tconst processedOptions = {\n\t\t\t...defaults,\n\t\t\tlayouts: {\n\t\t\t\tdefault: this.processCustomTemplate(templates.default, \"default\"),\n\t\t\t\tmultiple: this.processCustomTemplate(templates.multiple, \"multiple\"),\n\t\t\t\tyear: this.processCustomTemplate(templates.year, \"default\"),\n\t\t\t},\n\t\t};\n\n\t\tthis.vanillaCalendar = new CustomVanillaCalendar(\n\t\t\tthis.el,\n\t\t\t_.merge(_options, this.dataOptions, processedOptions),\n\t\t);\n\n\t\tthis.init();\n\t}\n\n\tprivate init() {\n\t\tthis.createCollection(window.$hsDatepickerCollection, this);\n\n\t\tthis.vanillaCalendar.init();\n\n\t\tif (this.dataOptions?.selectedDates) {\n\t\t\tthis.setInputValue(\n\t\t\t\tthis.vanillaCalendar.context.inputElement,\n\t\t\t\tthis.formatDateArrayToIndividualDates(this.dataOptions?.selectedDates),\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate getTimeParts(time: string) {\n\t\tconst [_time, meridiem] = time.split(\" \");\n\t\tconst [hours, minutes] = _time.split(\":\");\n\n\t\treturn [hours, minutes, meridiem];\n\t}\n\n\tprivate getCurrentMonthAndYear(el: HTMLElement) {\n\t\tconst currentMonthHolder = el.querySelector('[data-vc=\"month\"]');\n\t\tconst currentYearHolder = el.querySelector('[data-vc=\"year\"]');\n\n\t\treturn {\n\t\t\tmonth: +currentMonthHolder.getAttribute(\"data-vc-month\"),\n\t\t\tyear: +currentYearHolder.getAttribute(\"data-vc-year\"),\n\t\t};\n\t}\n\n\tprivate setInputValue(target: HTMLInputElement, dates: DatesArr) {\n\t\tconst dateSeparator = this.dataOptions?.inputModeOptions?.dateSeparator ??\n\t\t\t\".\";\n\t\tconst itemsSeparator = this.dataOptions?.inputModeOptions?.itemsSeparator ??\n\t\t\t\", \";\n\t\tconst selectionDatesMode = this.dataOptions?.selectionDatesMode ?? \"single\";\n\n\t\tif (dates.length && dates.length > 1) {\n\t\t\tif (selectionDatesMode === \"multiple\") {\n\t\t\t\tconst temp: string[] = [];\n\t\t\t\tdates.forEach((date) =>\n\t\t\t\t\ttemp.push(this.changeDateSeparator(date, dateSeparator))\n\t\t\t\t);\n\n\t\t\t\ttarget.value = temp.join(itemsSeparator);\n\t\t\t} else {\n\t\t\t\ttarget.value = [\n\t\t\t\t\tthis.changeDateSeparator(dates[0], dateSeparator),\n\t\t\t\t\tthis.changeDateSeparator(dates[1], dateSeparator),\n\t\t\t\t].join(itemsSeparator);\n\t\t\t}\n\t\t} else if (dates.length && dates.length === 1) {\n\t\t\ttarget.value = this.changeDateSeparator(dates[0], dateSeparator);\n\t\t} else target.value = \"\";\n\t}\n\n\tprivate changeDateSeparator(\n\t\tdate: string | number | Date,\n\t\tseparator = \".\",\n\t\tdefaultSeparator = \"-\",\n\t) {\n\t\tconst newDate = (date as string).split(defaultSeparator);\n\n\t\treturn newDate.join(separator);\n\t}\n\n\tprivate formatDateArrayToIndividualDates(dates: DatesArr): string[] {\n\t\tconst selectionDatesMode = this.dataOptions?.selectionDatesMode ?? \"single\";\n\t\tconst expandDateRange = (start: string, end: string): string[] => {\n\t\t\tconst startDate = new Date(start);\n\t\t\tconst endDate = new Date(end);\n\t\t\tconst result: string[] = [];\n\n\t\t\twhile (startDate <= endDate) {\n\t\t\t\tresult.push(startDate.toISOString().split(\"T\")[0]);\n\t\t\t\tstartDate.setDate(startDate.getDate() + 1);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t};\n\t\tconst formatDate = (date: string | number | Date): string[] => {\n\t\t\tif (typeof date === \"string\") {\n\t\t\t\tconst rangeMatch = date.match(\n\t\t\t\t\t/^(\\d{4}-\\d{2}-\\d{2})\\s*[^a-zA-Z0-9]*\\s*(\\d{4}-\\d{2}-\\d{2})$/,\n\t\t\t\t);\n\n\t\t\t\tif (rangeMatch) {\n\t\t\t\t\tconst [_, start, end] = rangeMatch;\n\n\t\t\t\t\treturn selectionDatesMode === \"multiple-ranged\"\n\t\t\t\t\t\t? [start, end]\n\t\t\t\t\t\t: expandDateRange(start.trim(), end.trim());\n\t\t\t\t}\n\n\t\t\t\treturn [date];\n\t\t\t} else if (typeof date === \"number\") {\n\t\t\t\treturn [new Date(date).toISOString().split(\"T\")[0]];\n\t\t\t} else if (date instanceof Date) {\n\t\t\t\treturn [date.toISOString().split(\"T\")[0]];\n\t\t\t}\n\n\t\t\treturn [];\n\t\t};\n\n\t\treturn dates.flatMap(formatDate);\n\t}\n\n\tprivate hasTime(el: Calendar) {\n\t\tconst { mainElement } = el.context;\n\t\tconst hours = mainElement.querySelector(\n\t\t\t\"[data-hs-select].--hours\",\n\t\t) as HTMLElement;\n\t\tconst minutes = mainElement.querySelector(\n\t\t\t\"[data-hs-select].--minutes\",\n\t\t) as HTMLElement;\n\t\tconst meridiem = mainElement.querySelector(\n\t\t\t\"[data-hs-select].--meridiem\",\n\t\t) as HTMLElement;\n\n\t\treturn hours && minutes && meridiem;\n\t}\n\n\tprivate createArrowFromTemplate(\n\t\ttemplate: string,\n\t\tclasses: string | boolean = false,\n\t) {\n\t\tif (!classes) return template;\n\n\t\tconst temp = htmlToElement(template);\n\t\tclassToClassList(classes as string, temp);\n\n\t\treturn temp.outerHTML;\n\t}\n\n\tprivate concatObjectProperties<\n\t\tT extends ISelectOptions,\n\t\tU extends ISelectOptions,\n\t>(\n\t\tshared: T,\n\t\tother: U,\n\t): Partial {\n\t\tconst result: Partial = {};\n\t\tconst allKeys = new Set([\n\t\t\t...Object.keys(shared || {}),\n\t\t\t...Object.keys(other || {}),\n\t\t] as Array);\n\n\t\tallKeys.forEach((key) => {\n\t\t\tconst sharedValue = shared[key as keyof T] || \"\";\n\t\t\tconst otherValue = other[key as keyof U] || \"\";\n\n\t\t\tresult[key as keyof T & keyof U] = `${sharedValue} ${otherValue}`\n\t\t\t\t.trim() as T[keyof T & keyof U] & U[keyof T & keyof U];\n\t\t});\n\n\t\treturn result;\n\t}\n\n\tprivate updateTemplate(\n\t\ttemplate: string,\n\t\tshared: ISelectOptions,\n\t\tspecific: ISelectOptions,\n\t) {\n\t\tif (!shared) return template;\n\n\t\tconst defaultOptions = JSON.parse(\n\t\t\ttemplate.match(/data-hs-select='([^']+)'/)[1],\n\t\t);\n\t\tconst concatOptions = this.concatObjectProperties(shared, specific);\n\t\tconst mergedOptions = _.merge(defaultOptions, concatOptions);\n\t\tconst updatedTemplate = template.replace(\n\t\t\t/data-hs-select='[^']+'/,\n\t\t\t`data-hs-select='${JSON.stringify(mergedOptions)}'`,\n\t\t);\n\n\t\treturn updatedTemplate;\n\t}\n\n\tprivate initCustomTime(self: Calendar) {\n\t\tconst { mainElement } = self.context;\n\t\tconst timeParts = this.getTimeParts(self.selectedTime ?? \"12:00 PM\");\n\t\tconst selectors = {\n\t\t\thours: mainElement.querySelector(\n\t\t\t\t\"[data-hs-select].--hours\",\n\t\t\t) as HTMLElement,\n\t\t\tminutes: mainElement.querySelector(\n\t\t\t\t\"[data-hs-select].--minutes\",\n\t\t\t) as HTMLElement,\n\t\t\tmeridiem: mainElement.querySelector(\n\t\t\t\t\"[data-hs-select].--meridiem\",\n\t\t\t) as HTMLElement,\n\t\t};\n\n\t\tObject.entries(selectors).forEach(([key, element]) => {\n\t\t\tif (!HSSelect.getInstance(element, true)) {\n\t\t\t\tconst instance = new HSSelect(element);\n\n\t\t\t\tinstance.setValue(\n\t\t\t\t\ttimeParts[key === \"meridiem\" ? 2 : key === \"minutes\" ? 1 : 0],\n\t\t\t\t);\n\t\t\t\tinstance.el.addEventListener(\"change.hs.select\", (evt: CustomEvent) => {\n\t\t\t\t\tthis.destroySelects(mainElement);\n\t\t\t\t\tconst updatedTime = {\n\t\t\t\t\t\thours: key === \"hours\" ? evt.detail.payload : timeParts[0],\n\t\t\t\t\t\tminutes: key === \"minutes\" ? evt.detail.payload : timeParts[1],\n\t\t\t\t\t\tmeridiem: key === \"meridiem\" ? evt.detail.payload : timeParts[2],\n\t\t\t\t\t};\n\n\t\t\t\t\tself.set({\n\t\t\t\t\t\tselectedTime:\n\t\t\t\t\t\t\t`${updatedTime.hours}:${updatedTime.minutes} ${updatedTime.meridiem}`,\n\t\t\t\t\t}, {\n\t\t\t\t\t\tdates: false,\n\t\t\t\t\t\tyear: false,\n\t\t\t\t\t\tmonth: false,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate initCustomMonths(self: Calendar) {\n\t\tconst { mainElement } = self.context;\n\t\tconst columns = Array.from(mainElement.querySelectorAll(\".--single-month\"));\n\n\t\tif (columns.length) {\n\t\t\tcolumns.forEach((column: HTMLElement, idx: number) => {\n\t\t\t\tconst _month = column.querySelector(\n\t\t\t\t\t\"[data-hs-select].--month\",\n\t\t\t\t) as HTMLElement;\n\t\t\t\tconst isInstanceExists = HSSelect.getInstance(_month, true);\n\n\t\t\t\tif (isInstanceExists) return false;\n\n\t\t\t\tconst instance = new HSSelect(_month);\n\t\t\t\tconst { month, year } = this.getCurrentMonthAndYear(column);\n\n\t\t\t\tinstance.setValue(`${month}`);\n\n\t\t\t\tinstance.el.addEventListener(\"change.hs.select\", (evt: CustomEvent) => {\n\t\t\t\t\tthis.destroySelects(mainElement);\n\t\t\t\t\tself.set({\n\t\t\t\t\t\tselectedMonth: (+evt.detail.payload - idx < 0\n\t\t\t\t\t\t\t? 11\n\t\t\t\t\t\t\t: +evt.detail.payload - idx) as Range<12>,\n\t\t\t\t\t\tselectedYear:\n\t\t\t\t\t\t\t(+evt.detail.payload - idx < 0 ? +year - 1 : year) as number,\n\t\t\t\t\t}, {\n\t\t\t\t\t\tdates: false,\n\t\t\t\t\t\ttime: false,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate initCustomYears(self: Calendar) {\n\t\tconst { mainElement } = self.context;\n\t\tconst columns = Array.from(mainElement.querySelectorAll(\".--single-month\"));\n\n\t\tif (columns.length) {\n\t\t\tcolumns.forEach((column: HTMLElement) => {\n\t\t\t\tconst _year = column.querySelector(\n\t\t\t\t\t\"[data-hs-select].--year\",\n\t\t\t\t) as HTMLElement;\n\t\t\t\tconst isInstanceExists = HSSelect.getInstance(_year, true);\n\n\t\t\t\tif (isInstanceExists) return false;\n\n\t\t\t\tconst instance = new HSSelect(_year);\n\t\t\t\tconst { month, year } = this.getCurrentMonthAndYear(column);\n\n\t\t\t\tinstance.setValue(`${year}`);\n\n\t\t\t\tinstance.el.addEventListener(\"change.hs.select\", (evt: CustomEvent) => {\n\t\t\t\t\tconst { dateMax, displayMonthsCount } = this.vanillaCalendar.context;\n\t\t\t\t\tconst maxYear = new Date(dateMax).getFullYear();\n\t\t\t\t\tconst maxMonth = new Date(dateMax).getMonth();\n\n\t\t\t\t\tthis.destroySelects(mainElement);\n\t\t\t\t\tself.set({\n\t\t\t\t\t\tselectedMonth: ((month > maxMonth - displayMonthsCount) &&\n\t\t\t\t\t\t\t\t+evt.detail.payload === maxYear\n\t\t\t\t\t\t\t? maxMonth - displayMonthsCount + 1\n\t\t\t\t\t\t\t: month) as Range<12>,\n\t\t\t\t\t\tselectedYear: evt.detail.payload,\n\t\t\t\t\t}, {\n\t\t\t\t\t\tdates: false,\n\t\t\t\t\t\ttime: false,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate generateCustomTimeMarkup() {\n\t\tconst customSelectOptions = this.updatedStyles?.customSelect;\n\t\tconst hours = customSelectOptions\n\t\t\t? this.updateTemplate(\n\t\t\t\ttemplates.hours,\n\t\t\t\tcustomSelectOptions?.shared || {} as ISelectOptions,\n\t\t\t\tcustomSelectOptions?.hours || {} as ISelectOptions,\n\t\t\t)\n\t\t\t: templates.hours;\n\t\tconst minutes = customSelectOptions\n\t\t\t? this.updateTemplate(\n\t\t\t\ttemplates.minutes,\n\t\t\t\tcustomSelectOptions?.shared || {} as ISelectOptions,\n\t\t\t\tcustomSelectOptions?.minutes || {} as ISelectOptions,\n\t\t\t)\n\t\t\t: templates.minutes;\n\t\tconst meridiem = customSelectOptions\n\t\t\t? this.updateTemplate(\n\t\t\t\ttemplates.meridiem,\n\t\t\t\tcustomSelectOptions?.shared || {} as ISelectOptions,\n\t\t\t\tcustomSelectOptions?.meridiem || {} as ISelectOptions,\n\t\t\t)\n\t\t\t: templates.meridiem;\n\t\tconst time = this?.dataOptions?.templates?.time ?? `\n\t\t\t\n ${hours}\n :\n ${minutes}\n ${meridiem}\n
\n\t\t`;\n\n\t\treturn `${time}
`;\n\t}\n\n\tprivate generateCustomMonthMarkup() {\n\t\tconst mode = this?.dataOptions?.mode ?? \"default\";\n\t\tconst customSelectOptions = this.updatedStyles?.customSelect;\n\t\tconst updatedTemplate = customSelectOptions\n\t\t\t? this.updateTemplate(\n\t\t\t\ttemplates.months,\n\t\t\t\tcustomSelectOptions?.shared || {} as ISelectOptions,\n\t\t\t\tcustomSelectOptions?.months || {} as ISelectOptions,\n\t\t\t)\n\t\t\t: templates.months;\n\t\tconst month = mode === \"custom-select\" ? updatedTemplate : \"<#Month />\";\n\n\t\treturn month;\n\t}\n\n\tprivate generateCustomYearMarkup() {\n\t\tconst mode = this?.dataOptions?.mode ?? \"default\";\n\n\t\tif (mode === \"custom-select\") {\n\t\t\tconst today = new Date();\n\t\t\tconst dateMin = this?.dataOptions?.dateMin ??\n\t\t\t\ttoday.toISOString().split(\"T\")[0];\n\t\t\tconst tempDateMax = this?.dataOptions?.dateMax ?? \"2470-12-31\";\n\t\t\tconst dateMax = tempDateMax;\n\t\t\tconst startDate = new Date(dateMin);\n\t\t\tconst endDate = new Date(dateMax);\n\t\t\tconst startDateYear = startDate.getFullYear();\n\t\t\tconst endDateYear = endDate.getFullYear();\n\t\t\tconst generateOptions = () => {\n\t\t\t\tlet result = \"\";\n\n\t\t\t\tfor (let i = startDateYear; i <= endDateYear; i++) {\n\t\t\t\t\tresult += ``;\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t};\n\t\t\tconst years = templates.years(generateOptions());\n\t\t\tconst customSelectOptions = this.updatedStyles?.customSelect;\n\t\t\tconst updatedTemplate = customSelectOptions\n\t\t\t\t? this.updateTemplate(\n\t\t\t\t\tyears,\n\t\t\t\t\tcustomSelectOptions?.shared || {} as ISelectOptions,\n\t\t\t\t\tcustomSelectOptions?.years || {} as ISelectOptions,\n\t\t\t\t)\n\t\t\t\t: years;\n\n\t\t\treturn updatedTemplate;\n\t\t} else {\n\t\t\treturn \"<#Year />\";\n\t\t}\n\t}\n\n\tprivate generateCustomArrowPrevMarkup() {\n\t\tconst arrowPrev = this?.dataOptions?.templates?.arrowPrev\n\t\t\t? this.createArrowFromTemplate(\n\t\t\t\tthis.dataOptions.templates.arrowPrev,\n\t\t\t\tthis.updatedStyles.arrowPrev,\n\t\t\t)\n\t\t\t: \"<#ArrowPrev [month] />\";\n\n\t\treturn arrowPrev;\n\t}\n\n\tprivate generateCustomArrowNextMarkup() {\n\t\tconst arrowNext = this?.dataOptions?.templates?.arrowNext\n\t\t\t? this.createArrowFromTemplate(\n\t\t\t\tthis.dataOptions.templates.arrowNext,\n\t\t\t\tthis.updatedStyles.arrowNext,\n\t\t\t)\n\t\t\t: \"<#ArrowNext [month] />\";\n\n\t\treturn arrowNext;\n\t}\n\n\tprivate parseCustomTime(template: string) {\n\t\ttemplate = template.replace(\n\t\t\t/<#CustomTime\\s*\\/>/g,\n\t\t\tthis.generateCustomTimeMarkup(),\n\t\t);\n\n\t\treturn template;\n\t}\n\n\tprivate parseCustomMonth(template: string) {\n\t\ttemplate = template.replace(\n\t\t\t/<#CustomMonth\\s*\\/>/g,\n\t\t\tthis.generateCustomMonthMarkup(),\n\t\t);\n\n\t\treturn template;\n\t}\n\n\tprivate parseCustomYear(template: string) {\n\t\ttemplate = template.replace(\n\t\t\t/<#CustomYear\\s*\\/>/g,\n\t\t\tthis.generateCustomYearMarkup(),\n\t\t);\n\n\t\treturn template;\n\t}\n\n\tprivate parseArrowPrev(template: string) {\n\t\ttemplate = template.replace(\n\t\t\t/<#CustomArrowPrev\\s*\\/>/g,\n\t\t\tthis.generateCustomArrowPrevMarkup(),\n\t\t);\n\n\t\treturn template;\n\t}\n\n\tprivate parseArrowNext(template: string) {\n\t\ttemplate = template.replace(\n\t\t\t/<#CustomArrowNext\\s*\\/>/g,\n\t\t\tthis.generateCustomArrowNextMarkup(),\n\t\t);\n\n\t\treturn template;\n\t}\n\n\tprivate processCustomTemplate(\n\t\ttemplate: string,\n\t\ttype: \"default\" | \"multiple\",\n\t): string {\n\t\tconst templateAccordingToType = type === \"default\"\n\t\t\t? this?.dataOptions?.layouts?.default\n\t\t\t: this?.dataOptions?.layouts?.multiple;\n\t\tconst processedCustomMonth = this.parseCustomMonth(\n\t\t\ttemplateAccordingToType ?? template,\n\t\t);\n\t\tconst processedCustomYear = this.parseCustomYear(processedCustomMonth);\n\t\tconst processedCustomTime = this.parseCustomTime(processedCustomYear);\n\t\tconst processedCustomArrowPrev = this.parseArrowPrev(processedCustomTime);\n\t\tconst processedCustomTemplate = this.parseArrowNext(\n\t\t\tprocessedCustomArrowPrev,\n\t\t);\n\n\t\treturn processedCustomTemplate;\n\t}\n\n\tprivate disableOptions() {\n\t\tconst { mainElement, dateMax, displayMonthsCount } =\n\t\t\tthis.vanillaCalendar.context;\n\t\tconst maxDate = new Date(dateMax);\n\t\tconst columns = Array.from(mainElement.querySelectorAll(\".--single-month\"));\n\n\t\tcolumns.forEach((column, idx) => {\n\t\t\tconst year = +column.querySelector('[data-vc=\"year\"]')?.getAttribute(\n\t\t\t\t\"data-vc-year\",\n\t\t\t)!;\n\t\t\tconst monthOptions = column.querySelectorAll(\n\t\t\t\t\"[data-hs-select].--month option\",\n\t\t\t);\n\t\t\tconst pseudoOptions = column.querySelectorAll(\n\t\t\t\t\"[data-hs-select-dropdown] [data-value]\",\n\t\t\t);\n\t\t\tconst isDisabled = (option: HTMLOptionElement | HTMLElement) => {\n\t\t\t\tconst value = +option.getAttribute(\"data-value\")!;\n\n\t\t\t\treturn value > maxDate.getMonth() - displayMonthsCount + idx + 1 &&\n\t\t\t\t\tyear === maxDate.getFullYear();\n\t\t\t};\n\n\t\t\tArray.from(monthOptions).forEach((option: HTMLOptionElement) =>\n\t\t\t\toption.toggleAttribute(\"disabled\", isDisabled(option))\n\t\t\t);\n\t\t\tArray.from(pseudoOptions).forEach((option: HTMLOptionElement) =>\n\t\t\t\toption.classList.toggle(\"disabled\", isDisabled(option))\n\t\t\t);\n\t\t});\n\t}\n\n\tprivate disableNav() {\n\t\tconst {\n\t\t\tmainElement,\n\t\t\tdateMax,\n\t\t\tselectedYear,\n\t\t\tselectedMonth,\n\t\t\tdisplayMonthsCount,\n\t\t} = this.vanillaCalendar.context;\n\t\tconst maxYear = new Date(dateMax).getFullYear();\n\t\tconst next = mainElement.querySelector(\n\t\t\t'[data-vc-arrow=\"next\"]',\n\t\t) as HTMLElement;\n\n\t\tif (selectedYear === maxYear && selectedMonth + displayMonthsCount > 11) {\n\t\t\tnext.style.visibility = \"hidden\";\n\t\t} else next.style.visibility = \"\";\n\t}\n\n\tprivate destroySelects(container: HTMLElement) {\n\t\tconst selects = Array.from(container.querySelectorAll(\"[data-hs-select]\"));\n\n\t\tselects.forEach((select: HTMLElement) => {\n\t\t\tconst instance = HSSelect.getInstance(select, true) as ICollectionItem<\n\t\t\t\tHSSelect\n\t\t\t>;\n\n\t\t\tif (instance) instance.element.destroy();\n\t\t});\n\t}\n\n\tprivate updateSelect(el: HTMLElement, value: string) {\n\t\tconst instance = HSSelect.getInstance(el, true) as ICollectionItem<\n\t\t\tHSSelect\n\t\t>;\n\n\t\tif (instance) instance.element.setValue(value);\n\t}\n\n\tprivate updateCalendar(calendar: HTMLElement) {\n\t\tconst columns = calendar.querySelectorAll(\".--single-month\");\n\n\t\tif (columns.length) {\n\t\t\tcolumns.forEach((column: HTMLElement) => {\n\t\t\t\tconst { month, year } = this.getCurrentMonthAndYear(column);\n\n\t\t\t\tthis.updateSelect(\n\t\t\t\t\tcolumn.querySelector(\"[data-hs-select].--month\"),\n\t\t\t\t\t`${month}`,\n\t\t\t\t);\n\t\t\t\tthis.updateSelect(\n\t\t\t\t\tcolumn.querySelector(\"[data-hs-select].--year\"),\n\t\t\t\t\t`${year}`,\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate updateCustomSelects(el: Calendar) {\n\t\tsetTimeout(() => {\n\t\t\tthis.disableOptions();\n\t\t\tthis.disableNav();\n\n\t\t\tthis.initCustomMonths(el);\n\t\t\tthis.initCustomYears(el);\n\t\t});\n\t}\n\n\t// Public methods\n\tpublic getCurrentState() {\n\t\treturn {\n\t\t\tselectedDates: this.vanillaCalendar.selectedDates,\n\t\t\tselectedTime: this.vanillaCalendar.selectedTime,\n\t\t};\n\t}\n\n\t// Static methods\n\tstatic getInstance(target: HTMLElement | string, isInstance?: boolean) {\n\t\tconst elInCollection = window.$hsDatepickerCollection.find(\n\t\t\t(el) =>\n\t\t\t\tel.element.el ===\n\t\t\t\t\t(typeof target === \"string\"\n\t\t\t\t\t\t? document.querySelector(target)\n\t\t\t\t\t\t: target),\n\t\t);\n\n\t\treturn elInCollection\n\t\t\t? isInstance ? elInCollection : elInCollection.element.el\n\t\t\t: null;\n\t}\n\n\tstatic autoInit() {\n\t\tif (!window.$hsDatepickerCollection) window.$hsDatepickerCollection = [];\n\n\t\tdocument\n\t\t\t.querySelectorAll(\".hs-datepicker:not(.--prevent-on-load-init)\")\n\t\t\t.forEach((el: HTMLElement) => {\n\t\t\t\tif (\n\t\t\t\t\t!window.$hsDatepickerCollection.find(\n\t\t\t\t\t\t(elC) => (elC?.element?.el as HTMLElement) === el,\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tnew HSDatepicker(el);\n\t\t\t\t}\n\t\t\t});\n\t}\n}\n\ndeclare global {\n\tinterface Window {\n\t\tHSDatepicker: Function;\n\t\t$hsDatepickerCollection: ICollectionItem[];\n\t}\n}\n\nwindow.addEventListener(\"load\", () => {\n\tHSDatepicker.autoInit();\n\n\t// Uncomment for debug\n\t// console.log('Datepicker collection:', window.$hsDatepickerCollection);\n});\n\nif (typeof window !== \"undefined\") {\n\twindow.HSDatepicker = HSDatepicker;\n}\n\nexport default HSDatepicker;\n", "/*!\nTurbo 8.0.13\nCopyright \u00A9 2025 37signals LLC\n */\n/**\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 Javan Makhmali\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n(function (prototype) {\n if (typeof prototype.requestSubmit == \"function\") return\n\n prototype.requestSubmit = function (submitter) {\n if (submitter) {\n validateSubmitter(submitter, this);\n submitter.click();\n } else {\n submitter = document.createElement(\"input\");\n submitter.type = \"submit\";\n submitter.hidden = true;\n this.appendChild(submitter);\n submitter.click();\n this.removeChild(submitter);\n }\n };\n\n function validateSubmitter(submitter, form) {\n submitter instanceof HTMLElement || raise(TypeError, \"parameter 1 is not of type 'HTMLElement'\");\n submitter.type == \"submit\" || raise(TypeError, \"The specified element is not a submit button\");\n submitter.form == form ||\n raise(DOMException, \"The specified element is not owned by this form element\", \"NotFoundError\");\n }\n\n function raise(errorConstructor, message, name) {\n throw new errorConstructor(\"Failed to execute 'requestSubmit' on 'HTMLFormElement': \" + message + \".\", name)\n }\n})(HTMLFormElement.prototype);\n\nconst submittersByForm = new WeakMap();\n\nfunction findSubmitterFromClickTarget(target) {\n const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;\n const candidate = element ? element.closest(\"input, button\") : null;\n return candidate?.type == \"submit\" ? candidate : null\n}\n\nfunction clickCaptured(event) {\n const submitter = findSubmitterFromClickTarget(event.target);\n\n if (submitter && submitter.form) {\n submittersByForm.set(submitter.form, submitter);\n }\n}\n\n(function () {\n if (\"submitter\" in Event.prototype) return\n\n let prototype = window.Event.prototype;\n // Certain versions of Safari 15 have a bug where they won't\n // populate the submitter. This hurts TurboDrive's enable/disable detection.\n // See https://bugs.webkit.org/show_bug.cgi?id=229660\n if (\"SubmitEvent\" in window) {\n const prototypeOfSubmitEvent = window.SubmitEvent.prototype;\n\n if (/Apple Computer/.test(navigator.vendor) && !(\"submitter\" in prototypeOfSubmitEvent)) {\n prototype = prototypeOfSubmitEvent;\n } else {\n return // polyfill not needed\n }\n }\n\n addEventListener(\"click\", clickCaptured, true);\n\n Object.defineProperty(prototype, \"submitter\", {\n get() {\n if (this.type == \"submit\" && this.target instanceof HTMLFormElement) {\n return submittersByForm.get(this.target)\n }\n }\n });\n})();\n\nconst FrameLoadingStyle = {\n eager: \"eager\",\n lazy: \"lazy\"\n};\n\n/**\n * Contains a fragment of HTML which is updated based on navigation within\n * it (e.g. via links or form submissions).\n *\n * @customElement turbo-frame\n * @example\n * \n * \n * Show all expanded messages in this frame.\n * \n *\n * \n * \n */\nclass FrameElement extends HTMLElement {\n static delegateConstructor = undefined\n\n loaded = Promise.resolve()\n\n static get observedAttributes() {\n return [\"disabled\", \"loading\", \"src\"]\n }\n\n constructor() {\n super();\n this.delegate = new FrameElement.delegateConstructor(this);\n }\n\n connectedCallback() {\n this.delegate.connect();\n }\n\n disconnectedCallback() {\n this.delegate.disconnect();\n }\n\n reload() {\n return this.delegate.sourceURLReloaded()\n }\n\n attributeChangedCallback(name) {\n if (name == \"loading\") {\n this.delegate.loadingStyleChanged();\n } else if (name == \"src\") {\n this.delegate.sourceURLChanged();\n } else if (name == \"disabled\") {\n this.delegate.disabledChanged();\n }\n }\n\n /**\n * Gets the URL to lazily load source HTML from\n */\n get src() {\n return this.getAttribute(\"src\")\n }\n\n /**\n * Sets the URL to lazily load source HTML from\n */\n set src(value) {\n if (value) {\n this.setAttribute(\"src\", value);\n } else {\n this.removeAttribute(\"src\");\n }\n }\n\n /**\n * Gets the refresh mode for the frame.\n */\n get refresh() {\n return this.getAttribute(\"refresh\")\n }\n\n /**\n * Sets the refresh mode for the frame.\n */\n set refresh(value) {\n if (value) {\n this.setAttribute(\"refresh\", value);\n } else {\n this.removeAttribute(\"refresh\");\n }\n }\n\n get shouldReloadWithMorph() {\n return this.src && this.refresh === \"morph\"\n }\n\n /**\n * Determines if the element is loading\n */\n get loading() {\n return frameLoadingStyleFromString(this.getAttribute(\"loading\") || \"\")\n }\n\n /**\n * Sets the value of if the element is loading\n */\n set loading(value) {\n if (value) {\n this.setAttribute(\"loading\", value);\n } else {\n this.removeAttribute(\"loading\");\n }\n }\n\n /**\n * Gets the disabled state of the frame.\n *\n * If disabled, no requests will be intercepted by the frame.\n */\n get disabled() {\n return this.hasAttribute(\"disabled\")\n }\n\n /**\n * Sets the disabled state of the frame.\n *\n * If disabled, no requests will be intercepted by the frame.\n */\n set disabled(value) {\n if (value) {\n this.setAttribute(\"disabled\", \"\");\n } else {\n this.removeAttribute(\"disabled\");\n }\n }\n\n /**\n * Gets the autoscroll state of the frame.\n *\n * If true, the frame will be scrolled into view automatically on update.\n */\n get autoscroll() {\n return this.hasAttribute(\"autoscroll\")\n }\n\n /**\n * Sets the autoscroll state of the frame.\n *\n * If true, the frame will be scrolled into view automatically on update.\n */\n set autoscroll(value) {\n if (value) {\n this.setAttribute(\"autoscroll\", \"\");\n } else {\n this.removeAttribute(\"autoscroll\");\n }\n }\n\n /**\n * Determines if the element has finished loading\n */\n get complete() {\n return !this.delegate.isLoading\n }\n\n /**\n * Gets the active state of the frame.\n *\n * If inactive, source changes will not be observed.\n */\n get isActive() {\n return this.ownerDocument === document && !this.isPreview\n }\n\n /**\n * Sets the active state of the frame.\n *\n * If inactive, source changes will not be observed.\n */\n get isPreview() {\n return this.ownerDocument?.documentElement?.hasAttribute(\"data-turbo-preview\")\n }\n}\n\nfunction frameLoadingStyleFromString(style) {\n switch (style.toLowerCase()) {\n case \"lazy\":\n return FrameLoadingStyle.lazy\n default:\n return FrameLoadingStyle.eager\n }\n}\n\nconst drive = {\n enabled: true,\n progressBarDelay: 500,\n unvisitableExtensions: new Set(\n [\n \".7z\", \".aac\", \".apk\", \".avi\", \".bmp\", \".bz2\", \".css\", \".csv\", \".deb\", \".dmg\", \".doc\",\n \".docx\", \".exe\", \".gif\", \".gz\", \".heic\", \".heif\", \".ico\", \".iso\", \".jpeg\", \".jpg\",\n \".js\", \".json\", \".m4a\", \".mkv\", \".mov\", \".mp3\", \".mp4\", \".mpeg\", \".mpg\", \".msi\",\n \".ogg\", \".ogv\", \".pdf\", \".pkg\", \".png\", \".ppt\", \".pptx\", \".rar\", \".rtf\",\n \".svg\", \".tar\", \".tif\", \".tiff\", \".txt\", \".wav\", \".webm\", \".webp\", \".wma\", \".wmv\",\n \".xls\", \".xlsx\", \".xml\", \".zip\"\n ]\n )\n};\n\nfunction activateScriptElement(element) {\n if (element.getAttribute(\"data-turbo-eval\") == \"false\") {\n return element\n } else {\n const createdScriptElement = document.createElement(\"script\");\n const cspNonce = getCspNonce();\n if (cspNonce) {\n createdScriptElement.nonce = cspNonce;\n }\n createdScriptElement.textContent = element.textContent;\n createdScriptElement.async = false;\n copyElementAttributes(createdScriptElement, element);\n return createdScriptElement\n }\n}\n\nfunction copyElementAttributes(destinationElement, sourceElement) {\n for (const { name, value } of sourceElement.attributes) {\n destinationElement.setAttribute(name, value);\n }\n}\n\nfunction createDocumentFragment(html) {\n const template = document.createElement(\"template\");\n template.innerHTML = html;\n return template.content\n}\n\nfunction dispatch(eventName, { target, cancelable, detail } = {}) {\n const event = new CustomEvent(eventName, {\n cancelable,\n bubbles: true,\n composed: true,\n detail\n });\n\n if (target && target.isConnected) {\n target.dispatchEvent(event);\n } else {\n document.documentElement.dispatchEvent(event);\n }\n\n return event\n}\n\nfunction cancelEvent(event) {\n event.preventDefault();\n event.stopImmediatePropagation();\n}\n\nfunction nextRepaint() {\n if (document.visibilityState === \"hidden\") {\n return nextEventLoopTick()\n } else {\n return nextAnimationFrame()\n }\n}\n\nfunction nextAnimationFrame() {\n return new Promise((resolve) => requestAnimationFrame(() => resolve()))\n}\n\nfunction nextEventLoopTick() {\n return new Promise((resolve) => setTimeout(() => resolve(), 0))\n}\n\nfunction nextMicrotask() {\n return Promise.resolve()\n}\n\nfunction parseHTMLDocument(html = \"\") {\n return new DOMParser().parseFromString(html, \"text/html\")\n}\n\nfunction unindent(strings, ...values) {\n const lines = interpolate(strings, values).replace(/^\\n/, \"\").split(\"\\n\");\n const match = lines[0].match(/^\\s+/);\n const indent = match ? match[0].length : 0;\n return lines.map((line) => line.slice(indent)).join(\"\\n\")\n}\n\nfunction interpolate(strings, values) {\n return strings.reduce((result, string, i) => {\n const value = values[i] == undefined ? \"\" : values[i];\n return result + string + value\n }, \"\")\n}\n\nfunction uuid() {\n return Array.from({ length: 36 })\n .map((_, i) => {\n if (i == 8 || i == 13 || i == 18 || i == 23) {\n return \"-\"\n } else if (i == 14) {\n return \"4\"\n } else if (i == 19) {\n return (Math.floor(Math.random() * 4) + 8).toString(16)\n } else {\n return Math.floor(Math.random() * 15).toString(16)\n }\n })\n .join(\"\")\n}\n\nfunction getAttribute(attributeName, ...elements) {\n for (const value of elements.map((element) => element?.getAttribute(attributeName))) {\n if (typeof value == \"string\") return value\n }\n\n return null\n}\n\nfunction hasAttribute(attributeName, ...elements) {\n return elements.some((element) => element && element.hasAttribute(attributeName))\n}\n\nfunction markAsBusy(...elements) {\n for (const element of elements) {\n if (element.localName == \"turbo-frame\") {\n element.setAttribute(\"busy\", \"\");\n }\n element.setAttribute(\"aria-busy\", \"true\");\n }\n}\n\nfunction clearBusyState(...elements) {\n for (const element of elements) {\n if (element.localName == \"turbo-frame\") {\n element.removeAttribute(\"busy\");\n }\n\n element.removeAttribute(\"aria-busy\");\n }\n}\n\nfunction waitForLoad(element, timeoutInMilliseconds = 2000) {\n return new Promise((resolve) => {\n const onComplete = () => {\n element.removeEventListener(\"error\", onComplete);\n element.removeEventListener(\"load\", onComplete);\n resolve();\n };\n\n element.addEventListener(\"load\", onComplete, { once: true });\n element.addEventListener(\"error\", onComplete, { once: true });\n setTimeout(resolve, timeoutInMilliseconds);\n })\n}\n\nfunction getHistoryMethodForAction(action) {\n switch (action) {\n case \"replace\":\n return history.replaceState\n case \"advance\":\n case \"restore\":\n return history.pushState\n }\n}\n\nfunction isAction(action) {\n return action == \"advance\" || action == \"replace\" || action == \"restore\"\n}\n\nfunction getVisitAction(...elements) {\n const action = getAttribute(\"data-turbo-action\", ...elements);\n\n return isAction(action) ? action : null\n}\n\nfunction getMetaElement(name) {\n return document.querySelector(`meta[name=\"${name}\"]`)\n}\n\nfunction getMetaContent(name) {\n const element = getMetaElement(name);\n return element && element.content\n}\n\nfunction getCspNonce() {\n const element = getMetaElement(\"csp-nonce\");\n\n if (element) {\n const { nonce, content } = element;\n return nonce == \"\" ? content : nonce\n }\n}\n\nfunction setMetaContent(name, content) {\n let element = getMetaElement(name);\n\n if (!element) {\n element = document.createElement(\"meta\");\n element.setAttribute(\"name\", name);\n\n document.head.appendChild(element);\n }\n\n element.setAttribute(\"content\", content);\n\n return element\n}\n\nfunction findClosestRecursively(element, selector) {\n if (element instanceof Element) {\n return (\n element.closest(selector) || findClosestRecursively(element.assignedSlot || element.getRootNode()?.host, selector)\n )\n }\n}\n\nfunction elementIsFocusable(element) {\n const inertDisabledOrHidden = \"[inert], :disabled, [hidden], details:not([open]), dialog:not([open])\";\n\n return !!element && element.closest(inertDisabledOrHidden) == null && typeof element.focus == \"function\"\n}\n\nfunction queryAutofocusableElement(elementOrDocumentFragment) {\n return Array.from(elementOrDocumentFragment.querySelectorAll(\"[autofocus]\")).find(elementIsFocusable)\n}\n\nasync function around(callback, reader) {\n const before = reader();\n\n callback();\n\n await nextAnimationFrame();\n\n const after = reader();\n\n return [before, after]\n}\n\nfunction doesNotTargetIFrame(name) {\n if (name === \"_blank\") {\n return false\n } else if (name) {\n for (const element of document.getElementsByName(name)) {\n if (element instanceof HTMLIFrameElement) return false\n }\n\n return true\n } else {\n return true\n }\n}\n\nfunction findLinkFromClickTarget(target) {\n return findClosestRecursively(target, \"a[href]:not([target^=_]):not([download])\")\n}\n\nfunction getLocationForLink(link) {\n return expandURL(link.getAttribute(\"href\") || \"\")\n}\n\nfunction debounce(fn, delay) {\n let timeoutId = null;\n\n return (...args) => {\n const callback = () => fn.apply(this, args);\n clearTimeout(timeoutId);\n timeoutId = setTimeout(callback, delay);\n }\n}\n\nconst submitter = {\n \"aria-disabled\": {\n beforeSubmit: submitter => {\n submitter.setAttribute(\"aria-disabled\", \"true\");\n submitter.addEventListener(\"click\", cancelEvent);\n },\n\n afterSubmit: submitter => {\n submitter.removeAttribute(\"aria-disabled\");\n submitter.removeEventListener(\"click\", cancelEvent);\n }\n },\n\n \"disabled\": {\n beforeSubmit: submitter => submitter.disabled = true,\n afterSubmit: submitter => submitter.disabled = false\n }\n};\n\nclass Config {\n #submitter = null\n\n constructor(config) {\n Object.assign(this, config);\n }\n\n get submitter() {\n return this.#submitter\n }\n\n set submitter(value) {\n this.#submitter = submitter[value] || value;\n }\n}\n\nconst forms = new Config({\n mode: \"on\",\n submitter: \"disabled\"\n});\n\nconst config = {\n drive,\n forms\n};\n\nfunction expandURL(locatable) {\n return new URL(locatable.toString(), document.baseURI)\n}\n\nfunction getAnchor(url) {\n let anchorMatch;\n if (url.hash) {\n return url.hash.slice(1)\n // eslint-disable-next-line no-cond-assign\n } else if ((anchorMatch = url.href.match(/#(.*)$/))) {\n return anchorMatch[1]\n }\n}\n\nfunction getAction$1(form, submitter) {\n const action = submitter?.getAttribute(\"formaction\") || form.getAttribute(\"action\") || form.action;\n\n return expandURL(action)\n}\n\nfunction getExtension(url) {\n return (getLastPathComponent(url).match(/\\.[^.]*$/) || [])[0] || \"\"\n}\n\nfunction isPrefixedBy(baseURL, url) {\n const prefix = getPrefix(url);\n return baseURL.href === expandURL(prefix).href || baseURL.href.startsWith(prefix)\n}\n\nfunction locationIsVisitable(location, rootLocation) {\n return isPrefixedBy(location, rootLocation) && !config.drive.unvisitableExtensions.has(getExtension(location))\n}\n\nfunction getRequestURL(url) {\n const anchor = getAnchor(url);\n return anchor != null ? url.href.slice(0, -(anchor.length + 1)) : url.href\n}\n\nfunction toCacheKey(url) {\n return getRequestURL(url)\n}\n\nfunction urlsAreEqual(left, right) {\n return expandURL(left).href == expandURL(right).href\n}\n\nfunction getPathComponents(url) {\n return url.pathname.split(\"/\").slice(1)\n}\n\nfunction getLastPathComponent(url) {\n return getPathComponents(url).slice(-1)[0]\n}\n\nfunction getPrefix(url) {\n return addTrailingSlash(url.origin + url.pathname)\n}\n\nfunction addTrailingSlash(value) {\n return value.endsWith(\"/\") ? value : value + \"/\"\n}\n\nclass FetchResponse {\n constructor(response) {\n this.response = response;\n }\n\n get succeeded() {\n return this.response.ok\n }\n\n get failed() {\n return !this.succeeded\n }\n\n get clientError() {\n return this.statusCode >= 400 && this.statusCode <= 499\n }\n\n get serverError() {\n return this.statusCode >= 500 && this.statusCode <= 599\n }\n\n get redirected() {\n return this.response.redirected\n }\n\n get location() {\n return expandURL(this.response.url)\n }\n\n get isHTML() {\n return this.contentType && this.contentType.match(/^(?:text\\/([^\\s;,]+\\b)?html|application\\/xhtml\\+xml)\\b/)\n }\n\n get statusCode() {\n return this.response.status\n }\n\n get contentType() {\n return this.header(\"Content-Type\")\n }\n\n get responseText() {\n return this.response.clone().text()\n }\n\n get responseHTML() {\n if (this.isHTML) {\n return this.response.clone().text()\n } else {\n return Promise.resolve(undefined)\n }\n }\n\n header(name) {\n return this.response.headers.get(name)\n }\n}\n\nclass LimitedSet extends Set {\n constructor(maxSize) {\n super();\n this.maxSize = maxSize;\n }\n\n add(value) {\n if (this.size >= this.maxSize) {\n const iterator = this.values();\n const oldestValue = iterator.next().value;\n this.delete(oldestValue);\n }\n super.add(value);\n }\n}\n\nconst recentRequests = new LimitedSet(20);\n\nconst nativeFetch = window.fetch;\n\nfunction fetchWithTurboHeaders(url, options = {}) {\n const modifiedHeaders = new Headers(options.headers || {});\n const requestUID = uuid();\n recentRequests.add(requestUID);\n modifiedHeaders.append(\"X-Turbo-Request-Id\", requestUID);\n\n return nativeFetch(url, {\n ...options,\n headers: modifiedHeaders\n })\n}\n\nfunction fetchMethodFromString(method) {\n switch (method.toLowerCase()) {\n case \"get\":\n return FetchMethod.get\n case \"post\":\n return FetchMethod.post\n case \"put\":\n return FetchMethod.put\n case \"patch\":\n return FetchMethod.patch\n case \"delete\":\n return FetchMethod.delete\n }\n}\n\nconst FetchMethod = {\n get: \"get\",\n post: \"post\",\n put: \"put\",\n patch: \"patch\",\n delete: \"delete\"\n};\n\nfunction fetchEnctypeFromString(encoding) {\n switch (encoding.toLowerCase()) {\n case FetchEnctype.multipart:\n return FetchEnctype.multipart\n case FetchEnctype.plain:\n return FetchEnctype.plain\n default:\n return FetchEnctype.urlEncoded\n }\n}\n\nconst FetchEnctype = {\n urlEncoded: \"application/x-www-form-urlencoded\",\n multipart: \"multipart/form-data\",\n plain: \"text/plain\"\n};\n\nclass FetchRequest {\n abortController = new AbortController()\n #resolveRequestPromise = (_value) => {}\n\n constructor(delegate, method, location, requestBody = new URLSearchParams(), target = null, enctype = FetchEnctype.urlEncoded) {\n const [url, body] = buildResourceAndBody(expandURL(location), method, requestBody, enctype);\n\n this.delegate = delegate;\n this.url = url;\n this.target = target;\n this.fetchOptions = {\n credentials: \"same-origin\",\n redirect: \"follow\",\n method: method.toUpperCase(),\n headers: { ...this.defaultHeaders },\n body: body,\n signal: this.abortSignal,\n referrer: this.delegate.referrer?.href\n };\n this.enctype = enctype;\n }\n\n get method() {\n return this.fetchOptions.method\n }\n\n set method(value) {\n const fetchBody = this.isSafe ? this.url.searchParams : this.fetchOptions.body || new FormData();\n const fetchMethod = fetchMethodFromString(value) || FetchMethod.get;\n\n this.url.search = \"\";\n\n const [url, body] = buildResourceAndBody(this.url, fetchMethod, fetchBody, this.enctype);\n\n this.url = url;\n this.fetchOptions.body = body;\n this.fetchOptions.method = fetchMethod.toUpperCase();\n }\n\n get headers() {\n return this.fetchOptions.headers\n }\n\n set headers(value) {\n this.fetchOptions.headers = value;\n }\n\n get body() {\n if (this.isSafe) {\n return this.url.searchParams\n } else {\n return this.fetchOptions.body\n }\n }\n\n set body(value) {\n this.fetchOptions.body = value;\n }\n\n get location() {\n return this.url\n }\n\n get params() {\n return this.url.searchParams\n }\n\n get entries() {\n return this.body ? Array.from(this.body.entries()) : []\n }\n\n cancel() {\n this.abortController.abort();\n }\n\n async perform() {\n const { fetchOptions } = this;\n this.delegate.prepareRequest(this);\n const event = await this.#allowRequestToBeIntercepted(fetchOptions);\n try {\n this.delegate.requestStarted(this);\n\n if (event.detail.fetchRequest) {\n this.response = event.detail.fetchRequest.response;\n } else {\n this.response = fetchWithTurboHeaders(this.url.href, fetchOptions);\n }\n\n const response = await this.response;\n return await this.receive(response)\n } catch (error) {\n if (error.name !== \"AbortError\") {\n if (this.#willDelegateErrorHandling(error)) {\n this.delegate.requestErrored(this, error);\n }\n throw error\n }\n } finally {\n this.delegate.requestFinished(this);\n }\n }\n\n async receive(response) {\n const fetchResponse = new FetchResponse(response);\n const event = dispatch(\"turbo:before-fetch-response\", {\n cancelable: true,\n detail: { fetchResponse },\n target: this.target\n });\n if (event.defaultPrevented) {\n this.delegate.requestPreventedHandlingResponse(this, fetchResponse);\n } else if (fetchResponse.succeeded) {\n this.delegate.requestSucceededWithResponse(this, fetchResponse);\n } else {\n this.delegate.requestFailedWithResponse(this, fetchResponse);\n }\n return fetchResponse\n }\n\n get defaultHeaders() {\n return {\n Accept: \"text/html, application/xhtml+xml\"\n }\n }\n\n get isSafe() {\n return isSafe(this.method)\n }\n\n get abortSignal() {\n return this.abortController.signal\n }\n\n acceptResponseType(mimeType) {\n this.headers[\"Accept\"] = [mimeType, this.headers[\"Accept\"]].join(\", \");\n }\n\n async #allowRequestToBeIntercepted(fetchOptions) {\n const requestInterception = new Promise((resolve) => (this.#resolveRequestPromise = resolve));\n const event = dispatch(\"turbo:before-fetch-request\", {\n cancelable: true,\n detail: {\n fetchOptions,\n url: this.url,\n resume: this.#resolveRequestPromise\n },\n target: this.target\n });\n this.url = event.detail.url;\n if (event.defaultPrevented) await requestInterception;\n\n return event\n }\n\n #willDelegateErrorHandling(error) {\n const event = dispatch(\"turbo:fetch-request-error\", {\n target: this.target,\n cancelable: true,\n detail: { request: this, error: error }\n });\n\n return !event.defaultPrevented\n }\n}\n\nfunction isSafe(fetchMethod) {\n return fetchMethodFromString(fetchMethod) == FetchMethod.get\n}\n\nfunction buildResourceAndBody(resource, method, requestBody, enctype) {\n const searchParams =\n Array.from(requestBody).length > 0 ? new URLSearchParams(entriesExcludingFiles(requestBody)) : resource.searchParams;\n\n if (isSafe(method)) {\n return [mergeIntoURLSearchParams(resource, searchParams), null]\n } else if (enctype == FetchEnctype.urlEncoded) {\n return [resource, searchParams]\n } else {\n return [resource, requestBody]\n }\n}\n\nfunction entriesExcludingFiles(requestBody) {\n const entries = [];\n\n for (const [name, value] of requestBody) {\n if (value instanceof File) continue\n else entries.push([name, value]);\n }\n\n return entries\n}\n\nfunction mergeIntoURLSearchParams(url, requestBody) {\n const searchParams = new URLSearchParams(entriesExcludingFiles(requestBody));\n\n url.search = searchParams.toString();\n\n return url\n}\n\nclass AppearanceObserver {\n started = false\n\n constructor(delegate, element) {\n this.delegate = delegate;\n this.element = element;\n this.intersectionObserver = new IntersectionObserver(this.intersect);\n }\n\n start() {\n if (!this.started) {\n this.started = true;\n this.intersectionObserver.observe(this.element);\n }\n }\n\n stop() {\n if (this.started) {\n this.started = false;\n this.intersectionObserver.unobserve(this.element);\n }\n }\n\n intersect = (entries) => {\n const lastEntry = entries.slice(-1)[0];\n if (lastEntry?.isIntersecting) {\n this.delegate.elementAppearedInViewport(this.element);\n }\n }\n}\n\nclass StreamMessage {\n static contentType = \"text/vnd.turbo-stream.html\"\n\n static wrap(message) {\n if (typeof message == \"string\") {\n return new this(createDocumentFragment(message))\n } else {\n return message\n }\n }\n\n constructor(fragment) {\n this.fragment = importStreamElements(fragment);\n }\n}\n\nfunction importStreamElements(fragment) {\n for (const element of fragment.querySelectorAll(\"turbo-stream\")) {\n const streamElement = document.importNode(element, true);\n\n for (const inertScriptElement of streamElement.templateElement.content.querySelectorAll(\"script\")) {\n inertScriptElement.replaceWith(activateScriptElement(inertScriptElement));\n }\n\n element.replaceWith(streamElement);\n }\n\n return fragment\n}\n\nconst PREFETCH_DELAY = 100;\n\nclass PrefetchCache {\n #prefetchTimeout = null\n #prefetched = null\n\n get(url) {\n if (this.#prefetched && this.#prefetched.url === url && this.#prefetched.expire > Date.now()) {\n return this.#prefetched.request\n }\n }\n\n setLater(url, request, ttl) {\n this.clear();\n\n this.#prefetchTimeout = setTimeout(() => {\n request.perform();\n this.set(url, request, ttl);\n this.#prefetchTimeout = null;\n }, PREFETCH_DELAY);\n }\n\n set(url, request, ttl) {\n this.#prefetched = { url, request, expire: new Date(new Date().getTime() + ttl) };\n }\n\n clear() {\n if (this.#prefetchTimeout) clearTimeout(this.#prefetchTimeout);\n this.#prefetched = null;\n }\n}\n\nconst cacheTtl = 10 * 1000;\nconst prefetchCache = new PrefetchCache();\n\nconst FormSubmissionState = {\n initialized: \"initialized\",\n requesting: \"requesting\",\n waiting: \"waiting\",\n receiving: \"receiving\",\n stopping: \"stopping\",\n stopped: \"stopped\"\n};\n\nclass FormSubmission {\n state = FormSubmissionState.initialized\n\n static confirmMethod(message) {\n return Promise.resolve(confirm(message))\n }\n\n constructor(delegate, formElement, submitter, mustRedirect = false) {\n const method = getMethod(formElement, submitter);\n const action = getAction(getFormAction(formElement, submitter), method);\n const body = buildFormData(formElement, submitter);\n const enctype = getEnctype(formElement, submitter);\n\n this.delegate = delegate;\n this.formElement = formElement;\n this.submitter = submitter;\n this.fetchRequest = new FetchRequest(this, method, action, body, formElement, enctype);\n this.mustRedirect = mustRedirect;\n }\n\n get method() {\n return this.fetchRequest.method\n }\n\n set method(value) {\n this.fetchRequest.method = value;\n }\n\n get action() {\n return this.fetchRequest.url.toString()\n }\n\n set action(value) {\n this.fetchRequest.url = expandURL(value);\n }\n\n get body() {\n return this.fetchRequest.body\n }\n\n get enctype() {\n return this.fetchRequest.enctype\n }\n\n get isSafe() {\n return this.fetchRequest.isSafe\n }\n\n get location() {\n return this.fetchRequest.url\n }\n\n // The submission process\n\n async start() {\n const { initialized, requesting } = FormSubmissionState;\n const confirmationMessage = getAttribute(\"data-turbo-confirm\", this.submitter, this.formElement);\n\n if (typeof confirmationMessage === \"string\") {\n const confirmMethod = typeof config.forms.confirm === \"function\" ?\n config.forms.confirm :\n FormSubmission.confirmMethod;\n\n const answer = await confirmMethod(confirmationMessage, this.formElement, this.submitter);\n if (!answer) {\n return\n }\n }\n\n if (this.state == initialized) {\n this.state = requesting;\n return this.fetchRequest.perform()\n }\n }\n\n stop() {\n const { stopping, stopped } = FormSubmissionState;\n if (this.state != stopping && this.state != stopped) {\n this.state = stopping;\n this.fetchRequest.cancel();\n return true\n }\n }\n\n // Fetch request delegate\n\n prepareRequest(request) {\n if (!request.isSafe) {\n const token = getCookieValue(getMetaContent(\"csrf-param\")) || getMetaContent(\"csrf-token\");\n if (token) {\n request.headers[\"X-CSRF-Token\"] = token;\n }\n }\n\n if (this.requestAcceptsTurboStreamResponse(request)) {\n request.acceptResponseType(StreamMessage.contentType);\n }\n }\n\n requestStarted(_request) {\n this.state = FormSubmissionState.waiting;\n if (this.submitter) config.forms.submitter.beforeSubmit(this.submitter);\n this.setSubmitsWith();\n markAsBusy(this.formElement);\n dispatch(\"turbo:submit-start\", {\n target: this.formElement,\n detail: { formSubmission: this }\n });\n this.delegate.formSubmissionStarted(this);\n }\n\n requestPreventedHandlingResponse(request, response) {\n prefetchCache.clear();\n\n this.result = { success: response.succeeded, fetchResponse: response };\n }\n\n requestSucceededWithResponse(request, response) {\n if (response.clientError || response.serverError) {\n this.delegate.formSubmissionFailedWithResponse(this, response);\n return\n }\n\n prefetchCache.clear();\n\n if (this.requestMustRedirect(request) && responseSucceededWithoutRedirect(response)) {\n const error = new Error(\"Form responses must redirect to another location\");\n this.delegate.formSubmissionErrored(this, error);\n } else {\n this.state = FormSubmissionState.receiving;\n this.result = { success: true, fetchResponse: response };\n this.delegate.formSubmissionSucceededWithResponse(this, response);\n }\n }\n\n requestFailedWithResponse(request, response) {\n this.result = { success: false, fetchResponse: response };\n this.delegate.formSubmissionFailedWithResponse(this, response);\n }\n\n requestErrored(request, error) {\n this.result = { success: false, error };\n this.delegate.formSubmissionErrored(this, error);\n }\n\n requestFinished(_request) {\n this.state = FormSubmissionState.stopped;\n if (this.submitter) config.forms.submitter.afterSubmit(this.submitter);\n this.resetSubmitterText();\n clearBusyState(this.formElement);\n dispatch(\"turbo:submit-end\", {\n target: this.formElement,\n detail: { formSubmission: this, ...this.result }\n });\n this.delegate.formSubmissionFinished(this);\n }\n\n // Private\n\n setSubmitsWith() {\n if (!this.submitter || !this.submitsWith) return\n\n if (this.submitter.matches(\"button\")) {\n this.originalSubmitText = this.submitter.innerHTML;\n this.submitter.innerHTML = this.submitsWith;\n } else if (this.submitter.matches(\"input\")) {\n const input = this.submitter;\n this.originalSubmitText = input.value;\n input.value = this.submitsWith;\n }\n }\n\n resetSubmitterText() {\n if (!this.submitter || !this.originalSubmitText) return\n\n if (this.submitter.matches(\"button\")) {\n this.submitter.innerHTML = this.originalSubmitText;\n } else if (this.submitter.matches(\"input\")) {\n const input = this.submitter;\n input.value = this.originalSubmitText;\n }\n }\n\n requestMustRedirect(request) {\n return !request.isSafe && this.mustRedirect\n }\n\n requestAcceptsTurboStreamResponse(request) {\n return !request.isSafe || hasAttribute(\"data-turbo-stream\", this.submitter, this.formElement)\n }\n\n get submitsWith() {\n return this.submitter?.getAttribute(\"data-turbo-submits-with\")\n }\n}\n\nfunction buildFormData(formElement, submitter) {\n const formData = new FormData(formElement);\n const name = submitter?.getAttribute(\"name\");\n const value = submitter?.getAttribute(\"value\");\n\n if (name) {\n formData.append(name, value || \"\");\n }\n\n return formData\n}\n\nfunction getCookieValue(cookieName) {\n if (cookieName != null) {\n const cookies = document.cookie ? document.cookie.split(\"; \") : [];\n const cookie = cookies.find((cookie) => cookie.startsWith(cookieName));\n if (cookie) {\n const value = cookie.split(\"=\").slice(1).join(\"=\");\n return value ? decodeURIComponent(value) : undefined\n }\n }\n}\n\nfunction responseSucceededWithoutRedirect(response) {\n return response.statusCode == 200 && !response.redirected\n}\n\nfunction getFormAction(formElement, submitter) {\n const formElementAction = typeof formElement.action === \"string\" ? formElement.action : null;\n\n if (submitter?.hasAttribute(\"formaction\")) {\n return submitter.getAttribute(\"formaction\") || \"\"\n } else {\n return formElement.getAttribute(\"action\") || formElementAction || \"\"\n }\n}\n\nfunction getAction(formAction, fetchMethod) {\n const action = expandURL(formAction);\n\n if (isSafe(fetchMethod)) {\n action.search = \"\";\n }\n\n return action\n}\n\nfunction getMethod(formElement, submitter) {\n const method = submitter?.getAttribute(\"formmethod\") || formElement.getAttribute(\"method\") || \"\";\n return fetchMethodFromString(method.toLowerCase()) || FetchMethod.get\n}\n\nfunction getEnctype(formElement, submitter) {\n return fetchEnctypeFromString(submitter?.getAttribute(\"formenctype\") || formElement.enctype)\n}\n\nclass Snapshot {\n constructor(element) {\n this.element = element;\n }\n\n get activeElement() {\n return this.element.ownerDocument.activeElement\n }\n\n get children() {\n return [...this.element.children]\n }\n\n hasAnchor(anchor) {\n return this.getElementForAnchor(anchor) != null\n }\n\n getElementForAnchor(anchor) {\n return anchor ? this.element.querySelector(`[id='${anchor}'], a[name='${anchor}']`) : null\n }\n\n get isConnected() {\n return this.element.isConnected\n }\n\n get firstAutofocusableElement() {\n return queryAutofocusableElement(this.element)\n }\n\n get permanentElements() {\n return queryPermanentElementsAll(this.element)\n }\n\n getPermanentElementById(id) {\n return getPermanentElementById(this.element, id)\n }\n\n getPermanentElementMapForSnapshot(snapshot) {\n const permanentElementMap = {};\n\n for (const currentPermanentElement of this.permanentElements) {\n const { id } = currentPermanentElement;\n const newPermanentElement = snapshot.getPermanentElementById(id);\n if (newPermanentElement) {\n permanentElementMap[id] = [currentPermanentElement, newPermanentElement];\n }\n }\n\n return permanentElementMap\n }\n}\n\nfunction getPermanentElementById(node, id) {\n return node.querySelector(`#${id}[data-turbo-permanent]`)\n}\n\nfunction queryPermanentElementsAll(node) {\n return node.querySelectorAll(\"[id][data-turbo-permanent]\")\n}\n\nclass FormSubmitObserver {\n started = false\n\n constructor(delegate, eventTarget) {\n this.delegate = delegate;\n this.eventTarget = eventTarget;\n }\n\n start() {\n if (!this.started) {\n this.eventTarget.addEventListener(\"submit\", this.submitCaptured, true);\n this.started = true;\n }\n }\n\n stop() {\n if (this.started) {\n this.eventTarget.removeEventListener(\"submit\", this.submitCaptured, true);\n this.started = false;\n }\n }\n\n submitCaptured = () => {\n this.eventTarget.removeEventListener(\"submit\", this.submitBubbled, false);\n this.eventTarget.addEventListener(\"submit\", this.submitBubbled, false);\n }\n\n submitBubbled = (event) => {\n if (!event.defaultPrevented) {\n const form = event.target instanceof HTMLFormElement ? event.target : undefined;\n const submitter = event.submitter || undefined;\n\n if (\n form &&\n submissionDoesNotDismissDialog(form, submitter) &&\n submissionDoesNotTargetIFrame(form, submitter) &&\n this.delegate.willSubmitForm(form, submitter)\n ) {\n event.preventDefault();\n event.stopImmediatePropagation();\n this.delegate.formSubmitted(form, submitter);\n }\n }\n }\n}\n\nfunction submissionDoesNotDismissDialog(form, submitter) {\n const method = submitter?.getAttribute(\"formmethod\") || form.getAttribute(\"method\");\n\n return method != \"dialog\"\n}\n\nfunction submissionDoesNotTargetIFrame(form, submitter) {\n const target = submitter?.getAttribute(\"formtarget\") || form.getAttribute(\"target\");\n\n return doesNotTargetIFrame(target)\n}\n\nclass View {\n #resolveRenderPromise = (_value) => {}\n #resolveInterceptionPromise = (_value) => {}\n\n constructor(delegate, element) {\n this.delegate = delegate;\n this.element = element;\n }\n\n // Scrolling\n\n scrollToAnchor(anchor) {\n const element = this.snapshot.getElementForAnchor(anchor);\n if (element) {\n this.scrollToElement(element);\n this.focusElement(element);\n } else {\n this.scrollToPosition({ x: 0, y: 0 });\n }\n }\n\n scrollToAnchorFromLocation(location) {\n this.scrollToAnchor(getAnchor(location));\n }\n\n scrollToElement(element) {\n element.scrollIntoView();\n }\n\n focusElement(element) {\n if (element instanceof HTMLElement) {\n if (element.hasAttribute(\"tabindex\")) {\n element.focus();\n } else {\n element.setAttribute(\"tabindex\", \"-1\");\n element.focus();\n element.removeAttribute(\"tabindex\");\n }\n }\n }\n\n scrollToPosition({ x, y }) {\n this.scrollRoot.scrollTo(x, y);\n }\n\n scrollToTop() {\n this.scrollToPosition({ x: 0, y: 0 });\n }\n\n get scrollRoot() {\n return window\n }\n\n // Rendering\n\n async render(renderer) {\n const { isPreview, shouldRender, willRender, newSnapshot: snapshot } = renderer;\n\n // A workaround to ignore tracked element mismatch reloads when performing\n // a promoted Visit from a frame navigation\n const shouldInvalidate = willRender;\n\n if (shouldRender) {\n try {\n this.renderPromise = new Promise((resolve) => (this.#resolveRenderPromise = resolve));\n this.renderer = renderer;\n await this.prepareToRenderSnapshot(renderer);\n\n const renderInterception = new Promise((resolve) => (this.#resolveInterceptionPromise = resolve));\n const options = { resume: this.#resolveInterceptionPromise, render: this.renderer.renderElement, renderMethod: this.renderer.renderMethod };\n const immediateRender = this.delegate.allowsImmediateRender(snapshot, options);\n if (!immediateRender) await renderInterception;\n\n await this.renderSnapshot(renderer);\n this.delegate.viewRenderedSnapshot(snapshot, isPreview, this.renderer.renderMethod);\n this.delegate.preloadOnLoadLinksForView(this.element);\n this.finishRenderingSnapshot(renderer);\n } finally {\n delete this.renderer;\n this.#resolveRenderPromise(undefined);\n delete this.renderPromise;\n }\n } else if (shouldInvalidate) {\n this.invalidate(renderer.reloadReason);\n }\n }\n\n invalidate(reason) {\n this.delegate.viewInvalidated(reason);\n }\n\n async prepareToRenderSnapshot(renderer) {\n this.markAsPreview(renderer.isPreview);\n await renderer.prepareToRender();\n }\n\n markAsPreview(isPreview) {\n if (isPreview) {\n this.element.setAttribute(\"data-turbo-preview\", \"\");\n } else {\n this.element.removeAttribute(\"data-turbo-preview\");\n }\n }\n\n markVisitDirection(direction) {\n this.element.setAttribute(\"data-turbo-visit-direction\", direction);\n }\n\n unmarkVisitDirection() {\n this.element.removeAttribute(\"data-turbo-visit-direction\");\n }\n\n async renderSnapshot(renderer) {\n await renderer.render();\n }\n\n finishRenderingSnapshot(renderer) {\n renderer.finishRendering();\n }\n}\n\nclass FrameView extends View {\n missing() {\n this.element.innerHTML = `Content missing`;\n }\n\n get snapshot() {\n return new Snapshot(this.element)\n }\n}\n\nclass LinkInterceptor {\n constructor(delegate, element) {\n this.delegate = delegate;\n this.element = element;\n }\n\n start() {\n this.element.addEventListener(\"click\", this.clickBubbled);\n document.addEventListener(\"turbo:click\", this.linkClicked);\n document.addEventListener(\"turbo:before-visit\", this.willVisit);\n }\n\n stop() {\n this.element.removeEventListener(\"click\", this.clickBubbled);\n document.removeEventListener(\"turbo:click\", this.linkClicked);\n document.removeEventListener(\"turbo:before-visit\", this.willVisit);\n }\n\n clickBubbled = (event) => {\n if (this.clickEventIsSignificant(event)) {\n this.clickEvent = event;\n } else {\n delete this.clickEvent;\n }\n }\n\n linkClicked = (event) => {\n if (this.clickEvent && this.clickEventIsSignificant(event)) {\n if (this.delegate.shouldInterceptLinkClick(event.target, event.detail.url, event.detail.originalEvent)) {\n this.clickEvent.preventDefault();\n event.preventDefault();\n this.delegate.linkClickIntercepted(event.target, event.detail.url, event.detail.originalEvent);\n }\n }\n delete this.clickEvent;\n }\n\n willVisit = (_event) => {\n delete this.clickEvent;\n }\n\n clickEventIsSignificant(event) {\n const target = event.composed ? event.target?.parentElement : event.target;\n const element = findLinkFromClickTarget(target) || target;\n\n return element instanceof Element && element.closest(\"turbo-frame, html\") == this.element\n }\n}\n\nclass LinkClickObserver {\n started = false\n\n constructor(delegate, eventTarget) {\n this.delegate = delegate;\n this.eventTarget = eventTarget;\n }\n\n start() {\n if (!this.started) {\n this.eventTarget.addEventListener(\"click\", this.clickCaptured, true);\n this.started = true;\n }\n }\n\n stop() {\n if (this.started) {\n this.eventTarget.removeEventListener(\"click\", this.clickCaptured, true);\n this.started = false;\n }\n }\n\n clickCaptured = () => {\n this.eventTarget.removeEventListener(\"click\", this.clickBubbled, false);\n this.eventTarget.addEventListener(\"click\", this.clickBubbled, false);\n }\n\n clickBubbled = (event) => {\n if (event instanceof MouseEvent && this.clickEventIsSignificant(event)) {\n const target = (event.composedPath && event.composedPath()[0]) || event.target;\n const link = findLinkFromClickTarget(target);\n if (link && doesNotTargetIFrame(link.target)) {\n const location = getLocationForLink(link);\n if (this.delegate.willFollowLinkToLocation(link, location, event)) {\n event.preventDefault();\n this.delegate.followedLinkToLocation(link, location);\n }\n }\n }\n }\n\n clickEventIsSignificant(event) {\n return !(\n (event.target && event.target.isContentEditable) ||\n event.defaultPrevented ||\n event.which > 1 ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey ||\n event.shiftKey\n )\n }\n}\n\nclass FormLinkClickObserver {\n constructor(delegate, element) {\n this.delegate = delegate;\n this.linkInterceptor = new LinkClickObserver(this, element);\n }\n\n start() {\n this.linkInterceptor.start();\n }\n\n stop() {\n this.linkInterceptor.stop();\n }\n\n // Link hover observer delegate\n\n canPrefetchRequestToLocation(link, location) {\n return false\n }\n\n prefetchAndCacheRequestToLocation(link, location) {\n return\n }\n\n // Link click observer delegate\n\n willFollowLinkToLocation(link, location, originalEvent) {\n return (\n this.delegate.willSubmitFormLinkToLocation(link, location, originalEvent) &&\n (link.hasAttribute(\"data-turbo-method\") || link.hasAttribute(\"data-turbo-stream\"))\n )\n }\n\n followedLinkToLocation(link, location) {\n const form = document.createElement(\"form\");\n\n const type = \"hidden\";\n for (const [name, value] of location.searchParams) {\n form.append(Object.assign(document.createElement(\"input\"), { type, name, value }));\n }\n\n const action = Object.assign(location, { search: \"\" });\n form.setAttribute(\"data-turbo\", \"true\");\n form.setAttribute(\"action\", action.href);\n form.setAttribute(\"hidden\", \"\");\n\n const method = link.getAttribute(\"data-turbo-method\");\n if (method) form.setAttribute(\"method\", method);\n\n const turboFrame = link.getAttribute(\"data-turbo-frame\");\n if (turboFrame) form.setAttribute(\"data-turbo-frame\", turboFrame);\n\n const turboAction = getVisitAction(link);\n if (turboAction) form.setAttribute(\"data-turbo-action\", turboAction);\n\n const turboConfirm = link.getAttribute(\"data-turbo-confirm\");\n if (turboConfirm) form.setAttribute(\"data-turbo-confirm\", turboConfirm);\n\n const turboStream = link.hasAttribute(\"data-turbo-stream\");\n if (turboStream) form.setAttribute(\"data-turbo-stream\", \"\");\n\n this.delegate.submittedFormLinkToLocation(link, location, form);\n\n document.body.appendChild(form);\n form.addEventListener(\"turbo:submit-end\", () => form.remove(), { once: true });\n requestAnimationFrame(() => form.requestSubmit());\n }\n}\n\nclass Bardo {\n static async preservingPermanentElements(delegate, permanentElementMap, callback) {\n const bardo = new this(delegate, permanentElementMap);\n bardo.enter();\n await callback();\n bardo.leave();\n }\n\n constructor(delegate, permanentElementMap) {\n this.delegate = delegate;\n this.permanentElementMap = permanentElementMap;\n }\n\n enter() {\n for (const id in this.permanentElementMap) {\n const [currentPermanentElement, newPermanentElement] = this.permanentElementMap[id];\n this.delegate.enteringBardo(currentPermanentElement, newPermanentElement);\n this.replaceNewPermanentElementWithPlaceholder(newPermanentElement);\n }\n }\n\n leave() {\n for (const id in this.permanentElementMap) {\n const [currentPermanentElement] = this.permanentElementMap[id];\n this.replaceCurrentPermanentElementWithClone(currentPermanentElement);\n this.replacePlaceholderWithPermanentElement(currentPermanentElement);\n this.delegate.leavingBardo(currentPermanentElement);\n }\n }\n\n replaceNewPermanentElementWithPlaceholder(permanentElement) {\n const placeholder = createPlaceholderForPermanentElement(permanentElement);\n permanentElement.replaceWith(placeholder);\n }\n\n replaceCurrentPermanentElementWithClone(permanentElement) {\n const clone = permanentElement.cloneNode(true);\n permanentElement.replaceWith(clone);\n }\n\n replacePlaceholderWithPermanentElement(permanentElement) {\n const placeholder = this.getPlaceholderById(permanentElement.id);\n placeholder?.replaceWith(permanentElement);\n }\n\n getPlaceholderById(id) {\n return this.placeholders.find((element) => element.content == id)\n }\n\n get placeholders() {\n return [...document.querySelectorAll(\"meta[name=turbo-permanent-placeholder][content]\")]\n }\n}\n\nfunction createPlaceholderForPermanentElement(permanentElement) {\n const element = document.createElement(\"meta\");\n element.setAttribute(\"name\", \"turbo-permanent-placeholder\");\n element.setAttribute(\"content\", permanentElement.id);\n return element\n}\n\nclass Renderer {\n #activeElement = null\n\n static renderElement(currentElement, newElement) {\n // Abstract method\n }\n\n constructor(currentSnapshot, newSnapshot, isPreview, willRender = true) {\n this.currentSnapshot = currentSnapshot;\n this.newSnapshot = newSnapshot;\n this.isPreview = isPreview;\n this.willRender = willRender;\n this.renderElement = this.constructor.renderElement;\n this.promise = new Promise((resolve, reject) => (this.resolvingFunctions = { resolve, reject }));\n }\n\n get shouldRender() {\n return true\n }\n\n get shouldAutofocus() {\n return true\n }\n\n get reloadReason() {\n return\n }\n\n prepareToRender() {\n return\n }\n\n render() {\n // Abstract method\n }\n\n finishRendering() {\n if (this.resolvingFunctions) {\n this.resolvingFunctions.resolve();\n delete this.resolvingFunctions;\n }\n }\n\n async preservingPermanentElements(callback) {\n await Bardo.preservingPermanentElements(this, this.permanentElementMap, callback);\n }\n\n focusFirstAutofocusableElement() {\n if (this.shouldAutofocus) {\n const element = this.connectedSnapshot.firstAutofocusableElement;\n if (element) {\n element.focus();\n }\n }\n }\n\n // Bardo delegate\n\n enteringBardo(currentPermanentElement) {\n if (this.#activeElement) return\n\n if (currentPermanentElement.contains(this.currentSnapshot.activeElement)) {\n this.#activeElement = this.currentSnapshot.activeElement;\n }\n }\n\n leavingBardo(currentPermanentElement) {\n if (currentPermanentElement.contains(this.#activeElement) && this.#activeElement instanceof HTMLElement) {\n this.#activeElement.focus();\n\n this.#activeElement = null;\n }\n }\n\n get connectedSnapshot() {\n return this.newSnapshot.isConnected ? this.newSnapshot : this.currentSnapshot\n }\n\n get currentElement() {\n return this.currentSnapshot.element\n }\n\n get newElement() {\n return this.newSnapshot.element\n }\n\n get permanentElementMap() {\n return this.currentSnapshot.getPermanentElementMapForSnapshot(this.newSnapshot)\n }\n\n get renderMethod() {\n return \"replace\"\n }\n}\n\nclass FrameRenderer extends Renderer {\n static renderElement(currentElement, newElement) {\n const destinationRange = document.createRange();\n destinationRange.selectNodeContents(currentElement);\n destinationRange.deleteContents();\n\n const frameElement = newElement;\n const sourceRange = frameElement.ownerDocument?.createRange();\n if (sourceRange) {\n sourceRange.selectNodeContents(frameElement);\n currentElement.appendChild(sourceRange.extractContents());\n }\n }\n\n constructor(delegate, currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {\n super(currentSnapshot, newSnapshot, renderElement, isPreview, willRender);\n this.delegate = delegate;\n }\n\n get shouldRender() {\n return true\n }\n\n async render() {\n await nextRepaint();\n this.preservingPermanentElements(() => {\n this.loadFrameElement();\n });\n this.scrollFrameIntoView();\n await nextRepaint();\n this.focusFirstAutofocusableElement();\n await nextRepaint();\n this.activateScriptElements();\n }\n\n loadFrameElement() {\n this.delegate.willRenderFrame(this.currentElement, this.newElement);\n this.renderElement(this.currentElement, this.newElement);\n }\n\n scrollFrameIntoView() {\n if (this.currentElement.autoscroll || this.newElement.autoscroll) {\n const element = this.currentElement.firstElementChild;\n const block = readScrollLogicalPosition(this.currentElement.getAttribute(\"data-autoscroll-block\"), \"end\");\n const behavior = readScrollBehavior(this.currentElement.getAttribute(\"data-autoscroll-behavior\"), \"auto\");\n\n if (element) {\n element.scrollIntoView({ block, behavior });\n return true\n }\n }\n return false\n }\n\n activateScriptElements() {\n for (const inertScriptElement of this.newScriptElements) {\n const activatedScriptElement = activateScriptElement(inertScriptElement);\n inertScriptElement.replaceWith(activatedScriptElement);\n }\n }\n\n get newScriptElements() {\n return this.currentElement.querySelectorAll(\"script\")\n }\n}\n\nfunction readScrollLogicalPosition(value, defaultValue) {\n if (value == \"end\" || value == \"start\" || value == \"center\" || value == \"nearest\") {\n return value\n } else {\n return defaultValue\n }\n}\n\nfunction readScrollBehavior(value, defaultValue) {\n if (value == \"auto\" || value == \"smooth\") {\n return value\n } else {\n return defaultValue\n }\n}\n\n/**\n * @typedef {object} ConfigHead\n *\n * @property {'merge' | 'append' | 'morph' | 'none'} [style]\n * @property {boolean} [block]\n * @property {boolean} [ignore]\n * @property {function(Element): boolean} [shouldPreserve]\n * @property {function(Element): boolean} [shouldReAppend]\n * @property {function(Element): boolean} [shouldRemove]\n * @property {function(Element, {added: Node[], kept: Element[], removed: Element[]}): void} [afterHeadMorphed]\n */\n\n/**\n * @typedef {object} ConfigCallbacks\n *\n * @property {function(Node): boolean} [beforeNodeAdded]\n * @property {function(Node): void} [afterNodeAdded]\n * @property {function(Element, Node): boolean} [beforeNodeMorphed]\n * @property {function(Element, Node): void} [afterNodeMorphed]\n * @property {function(Element): boolean} [beforeNodeRemoved]\n * @property {function(Element): void} [afterNodeRemoved]\n * @property {function(string, Element, \"update\" | \"remove\"): boolean} [beforeAttributeUpdated]\n */\n\n/**\n * @typedef {object} Config\n *\n * @property {'outerHTML' | 'innerHTML'} [morphStyle]\n * @property {boolean} [ignoreActive]\n * @property {boolean} [ignoreActiveValue]\n * @property {boolean} [restoreFocus]\n * @property {ConfigCallbacks} [callbacks]\n * @property {ConfigHead} [head]\n */\n\n/**\n * @typedef {function} NoOp\n *\n * @returns {void}\n */\n\n/**\n * @typedef {object} ConfigHeadInternal\n *\n * @property {'merge' | 'append' | 'morph' | 'none'} style\n * @property {boolean} [block]\n * @property {boolean} [ignore]\n * @property {(function(Element): boolean) | NoOp} shouldPreserve\n * @property {(function(Element): boolean) | NoOp} shouldReAppend\n * @property {(function(Element): boolean) | NoOp} shouldRemove\n * @property {(function(Element, {added: Node[], kept: Element[], removed: Element[]}): void) | NoOp} afterHeadMorphed\n */\n\n/**\n * @typedef {object} ConfigCallbacksInternal\n *\n * @property {(function(Node): boolean) | NoOp} beforeNodeAdded\n * @property {(function(Node): void) | NoOp} afterNodeAdded\n * @property {(function(Node, Node): boolean) | NoOp} beforeNodeMorphed\n * @property {(function(Node, Node): void) | NoOp} afterNodeMorphed\n * @property {(function(Node): boolean) | NoOp} beforeNodeRemoved\n * @property {(function(Node): void) | NoOp} afterNodeRemoved\n * @property {(function(string, Element, \"update\" | \"remove\"): boolean) | NoOp} beforeAttributeUpdated\n */\n\n/**\n * @typedef {object} ConfigInternal\n *\n * @property {'outerHTML' | 'innerHTML'} morphStyle\n * @property {boolean} [ignoreActive]\n * @property {boolean} [ignoreActiveValue]\n * @property {boolean} [restoreFocus]\n * @property {ConfigCallbacksInternal} callbacks\n * @property {ConfigHeadInternal} head\n */\n\n/**\n * @typedef {Object} IdSets\n * @property {Set} persistentIds\n * @property {Map>} idMap\n */\n\n/**\n * @typedef {Function} Morph\n *\n * @param {Element | Document} oldNode\n * @param {Element | Node | HTMLCollection | Node[] | string | null} newContent\n * @param {Config} [config]\n * @returns {undefined | Node[]}\n */\n\n// base IIFE to define idiomorph\n/**\n *\n * @type {{defaults: ConfigInternal, morph: Morph}}\n */\nvar Idiomorph = (function () {\n\n /**\n * @typedef {object} MorphContext\n *\n * @property {Element} target\n * @property {Element} newContent\n * @property {ConfigInternal} config\n * @property {ConfigInternal['morphStyle']} morphStyle\n * @property {ConfigInternal['ignoreActive']} ignoreActive\n * @property {ConfigInternal['ignoreActiveValue']} ignoreActiveValue\n * @property {ConfigInternal['restoreFocus']} restoreFocus\n * @property {Map>} idMap\n * @property {Set} persistentIds\n * @property {ConfigInternal['callbacks']} callbacks\n * @property {ConfigInternal['head']} head\n * @property {HTMLDivElement} pantry\n */\n\n //=============================================================================\n // AND NOW IT BEGINS...\n //=============================================================================\n\n const noOp = () => {};\n /**\n * Default configuration values, updatable by users now\n * @type {ConfigInternal}\n */\n const defaults = {\n morphStyle: \"outerHTML\",\n callbacks: {\n beforeNodeAdded: noOp,\n afterNodeAdded: noOp,\n beforeNodeMorphed: noOp,\n afterNodeMorphed: noOp,\n beforeNodeRemoved: noOp,\n afterNodeRemoved: noOp,\n beforeAttributeUpdated: noOp,\n },\n head: {\n style: \"merge\",\n shouldPreserve: (elt) => elt.getAttribute(\"im-preserve\") === \"true\",\n shouldReAppend: (elt) => elt.getAttribute(\"im-re-append\") === \"true\",\n shouldRemove: noOp,\n afterHeadMorphed: noOp,\n },\n restoreFocus: true,\n };\n\n /**\n * Core idiomorph function for morphing one DOM tree to another\n *\n * @param {Element | Document} oldNode\n * @param {Element | Node | HTMLCollection | Node[] | string | null} newContent\n * @param {Config} [config]\n * @returns {Promise | Node[]}\n */\n function morph(oldNode, newContent, config = {}) {\n oldNode = normalizeElement(oldNode);\n const newNode = normalizeParent(newContent);\n const ctx = createMorphContext(oldNode, newNode, config);\n\n const morphedNodes = saveAndRestoreFocus(ctx, () => {\n return withHeadBlocking(\n ctx,\n oldNode,\n newNode,\n /** @param {MorphContext} ctx */ (ctx) => {\n if (ctx.morphStyle === \"innerHTML\") {\n morphChildren(ctx, oldNode, newNode);\n return Array.from(oldNode.childNodes);\n } else {\n return morphOuterHTML(ctx, oldNode, newNode);\n }\n },\n );\n });\n\n ctx.pantry.remove();\n return morphedNodes;\n }\n\n /**\n * Morph just the outerHTML of the oldNode to the newContent\n * We have to be careful because the oldNode could have siblings which need to be untouched\n * @param {MorphContext} ctx\n * @param {Element} oldNode\n * @param {Element} newNode\n * @returns {Node[]}\n */\n function morphOuterHTML(ctx, oldNode, newNode) {\n const oldParent = normalizeParent(oldNode);\n\n // basis for calulating which nodes were morphed\n // since there may be unmorphed sibling nodes\n let childNodes = Array.from(oldParent.childNodes);\n const index = childNodes.indexOf(oldNode);\n // how many elements are to the right of the oldNode\n const rightMargin = childNodes.length - (index + 1);\n\n morphChildren(\n ctx,\n oldParent,\n newNode,\n // these two optional params are the secret sauce\n oldNode, // start point for iteration\n oldNode.nextSibling, // end point for iteration\n );\n\n // return just the morphed nodes\n childNodes = Array.from(oldParent.childNodes);\n return childNodes.slice(index, childNodes.length - rightMargin);\n }\n\n /**\n * @param {MorphContext} ctx\n * @param {Function} fn\n * @returns {Promise | Node[]}\n */\n function saveAndRestoreFocus(ctx, fn) {\n if (!ctx.config.restoreFocus) return fn();\n let activeElement =\n /** @type {HTMLInputElement|HTMLTextAreaElement|null} */ (\n document.activeElement\n );\n\n // don't bother if the active element is not an input or textarea\n if (\n !(\n activeElement instanceof HTMLInputElement ||\n activeElement instanceof HTMLTextAreaElement\n )\n ) {\n return fn();\n }\n\n const { id: activeElementId, selectionStart, selectionEnd } = activeElement;\n\n const results = fn();\n\n if (activeElementId && activeElementId !== document.activeElement?.id) {\n activeElement = ctx.target.querySelector(`#${activeElementId}`);\n activeElement?.focus();\n }\n if (activeElement && !activeElement.selectionEnd && selectionEnd) {\n activeElement.setSelectionRange(selectionStart, selectionEnd);\n }\n\n return results;\n }\n\n const morphChildren = (function () {\n /**\n * This is the core algorithm for matching up children. The idea is to use id sets to try to match up\n * nodes as faithfully as possible. We greedily match, which allows us to keep the algorithm fast, but\n * by using id sets, we are able to better match up with content deeper in the DOM.\n *\n * Basic algorithm:\n * - for each node in the new content:\n * - search self and siblings for an id set match, falling back to a soft match\n * - if match found\n * - remove any nodes up to the match:\n * - pantry persistent nodes\n * - delete the rest\n * - morph the match\n * - elsif no match found, and node is persistent\n * - find its match by querying the old root (future) and pantry (past)\n * - move it and its children here\n * - morph it\n * - else\n * - create a new node from scratch as a last result\n *\n * @param {MorphContext} ctx the merge context\n * @param {Element} oldParent the old content that we are merging the new content into\n * @param {Element} newParent the parent element of the new content\n * @param {Node|null} [insertionPoint] the point in the DOM we start morphing at (defaults to first child)\n * @param {Node|null} [endPoint] the point in the DOM we stop morphing at (defaults to after last child)\n */\n function morphChildren(\n ctx,\n oldParent,\n newParent,\n insertionPoint = null,\n endPoint = null,\n ) {\n // normalize\n if (\n oldParent instanceof HTMLTemplateElement &&\n newParent instanceof HTMLTemplateElement\n ) {\n // @ts-ignore we can pretend the DocumentFragment is an Element\n oldParent = oldParent.content;\n // @ts-ignore ditto\n newParent = newParent.content;\n }\n insertionPoint ||= oldParent.firstChild;\n\n // run through all the new content\n for (const newChild of newParent.childNodes) {\n // once we reach the end of the old parent content skip to the end and insert the rest\n if (insertionPoint && insertionPoint != endPoint) {\n const bestMatch = findBestMatch(\n ctx,\n newChild,\n insertionPoint,\n endPoint,\n );\n if (bestMatch) {\n // if the node to morph is not at the insertion point then remove/move up to it\n if (bestMatch !== insertionPoint) {\n removeNodesBetween(ctx, insertionPoint, bestMatch);\n }\n morphNode(bestMatch, newChild, ctx);\n insertionPoint = bestMatch.nextSibling;\n continue;\n }\n }\n\n // if the matching node is elsewhere in the original content\n if (newChild instanceof Element && ctx.persistentIds.has(newChild.id)) {\n // move it and all its children here and morph\n const movedChild = moveBeforeById(\n oldParent,\n newChild.id,\n insertionPoint,\n ctx,\n );\n morphNode(movedChild, newChild, ctx);\n insertionPoint = movedChild.nextSibling;\n continue;\n }\n\n // last resort: insert the new node from scratch\n const insertedNode = createNode(\n oldParent,\n newChild,\n insertionPoint,\n ctx,\n );\n // could be null if beforeNodeAdded prevented insertion\n if (insertedNode) {\n insertionPoint = insertedNode.nextSibling;\n }\n }\n\n // remove any remaining old nodes that didn't match up with new content\n while (insertionPoint && insertionPoint != endPoint) {\n const tempNode = insertionPoint;\n insertionPoint = insertionPoint.nextSibling;\n removeNode(ctx, tempNode);\n }\n }\n\n /**\n * This performs the action of inserting a new node while handling situations where the node contains\n * elements with persistent ids and possible state info we can still preserve by moving in and then morphing\n *\n * @param {Element} oldParent\n * @param {Node} newChild\n * @param {Node|null} insertionPoint\n * @param {MorphContext} ctx\n * @returns {Node|null}\n */\n function createNode(oldParent, newChild, insertionPoint, ctx) {\n if (ctx.callbacks.beforeNodeAdded(newChild) === false) return null;\n if (ctx.idMap.has(newChild)) {\n // node has children with ids with possible state so create a dummy elt of same type and apply full morph algorithm\n const newEmptyChild = document.createElement(\n /** @type {Element} */ (newChild).tagName,\n );\n oldParent.insertBefore(newEmptyChild, insertionPoint);\n morphNode(newEmptyChild, newChild, ctx);\n ctx.callbacks.afterNodeAdded(newEmptyChild);\n return newEmptyChild;\n } else {\n // optimisation: no id state to preserve so we can just insert a clone of the newChild and its descendants\n const newClonedChild = document.importNode(newChild, true); // importNode to not mutate newParent\n oldParent.insertBefore(newClonedChild, insertionPoint);\n ctx.callbacks.afterNodeAdded(newClonedChild);\n return newClonedChild;\n }\n }\n\n //=============================================================================\n // Matching Functions\n //=============================================================================\n const findBestMatch = (function () {\n /**\n * Scans forward from the startPoint to the endPoint looking for a match\n * for the node. It looks for an id set match first, then a soft match.\n * We abort softmatching if we find two future soft matches, to reduce churn.\n * @param {Node} node\n * @param {MorphContext} ctx\n * @param {Node | null} startPoint\n * @param {Node | null} endPoint\n * @returns {Node | null}\n */\n function findBestMatch(ctx, node, startPoint, endPoint) {\n let softMatch = null;\n let nextSibling = node.nextSibling;\n let siblingSoftMatchCount = 0;\n\n let cursor = startPoint;\n while (cursor && cursor != endPoint) {\n // soft matching is a prerequisite for id set matching\n if (isSoftMatch(cursor, node)) {\n if (isIdSetMatch(ctx, cursor, node)) {\n return cursor; // found an id set match, we're done!\n }\n\n // we haven't yet saved a soft match fallback\n if (softMatch === null) {\n // the current soft match will hard match something else in the future, leave it\n if (!ctx.idMap.has(cursor)) {\n // save this as the fallback if we get through the loop without finding a hard match\n softMatch = cursor;\n }\n }\n }\n if (\n softMatch === null &&\n nextSibling &&\n isSoftMatch(cursor, nextSibling)\n ) {\n // The next new node has a soft match with this node, so\n // increment the count of future soft matches\n siblingSoftMatchCount++;\n nextSibling = nextSibling.nextSibling;\n\n // If there are two future soft matches, block soft matching for this node to allow\n // future siblings to soft match. This is to reduce churn in the DOM when an element\n // is prepended.\n if (siblingSoftMatchCount >= 2) {\n softMatch = undefined;\n }\n }\n\n // if the current node contains active element, stop looking for better future matches,\n // because if one is found, this node will be moved to the pantry, reparenting it and thus losing focus\n if (cursor.contains(document.activeElement)) break;\n\n cursor = cursor.nextSibling;\n }\n\n return softMatch || null;\n }\n\n /**\n *\n * @param {MorphContext} ctx\n * @param {Node} oldNode\n * @param {Node} newNode\n * @returns {boolean}\n */\n function isIdSetMatch(ctx, oldNode, newNode) {\n let oldSet = ctx.idMap.get(oldNode);\n let newSet = ctx.idMap.get(newNode);\n\n if (!newSet || !oldSet) return false;\n\n for (const id of oldSet) {\n // a potential match is an id in the new and old nodes that\n // has not already been merged into the DOM\n // But the newNode content we call this on has not been\n // merged yet and we don't allow duplicate IDs so it is simple\n if (newSet.has(id)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n *\n * @param {Node} oldNode\n * @param {Node} newNode\n * @returns {boolean}\n */\n function isSoftMatch(oldNode, newNode) {\n // ok to cast: if one is not element, `id` and `tagName` will be undefined and we'll just compare that.\n const oldElt = /** @type {Element} */ (oldNode);\n const newElt = /** @type {Element} */ (newNode);\n\n return (\n oldElt.nodeType === newElt.nodeType &&\n oldElt.tagName === newElt.tagName &&\n // If oldElt has an `id` with possible state and it doesn't match newElt.id then avoid morphing.\n // We'll still match an anonymous node with an IDed newElt, though, because if it got this far,\n // its not persistent, and new nodes can't have any hidden state.\n (!oldElt.id || oldElt.id === newElt.id)\n );\n }\n\n return findBestMatch;\n })();\n\n //=============================================================================\n // DOM Manipulation Functions\n //=============================================================================\n\n /**\n * Gets rid of an unwanted DOM node; strategy depends on nature of its reuse:\n * - Persistent nodes will be moved to the pantry for later reuse\n * - Other nodes will have their hooks called, and then are removed\n * @param {MorphContext} ctx\n * @param {Node} node\n */\n function removeNode(ctx, node) {\n // are we going to id set match this later?\n if (ctx.idMap.has(node)) {\n // skip callbacks and move to pantry\n moveBefore(ctx.pantry, node, null);\n } else {\n // remove for realsies\n if (ctx.callbacks.beforeNodeRemoved(node) === false) return;\n node.parentNode?.removeChild(node);\n ctx.callbacks.afterNodeRemoved(node);\n }\n }\n\n /**\n * Remove nodes between the start and end nodes\n * @param {MorphContext} ctx\n * @param {Node} startInclusive\n * @param {Node} endExclusive\n * @returns {Node|null}\n */\n function removeNodesBetween(ctx, startInclusive, endExclusive) {\n /** @type {Node | null} */\n let cursor = startInclusive;\n // remove nodes until the endExclusive node\n while (cursor && cursor !== endExclusive) {\n let tempNode = /** @type {Node} */ (cursor);\n cursor = cursor.nextSibling;\n removeNode(ctx, tempNode);\n }\n return cursor;\n }\n\n /**\n * Search for an element by id within the document and pantry, and move it using moveBefore.\n *\n * @param {Element} parentNode - The parent node to which the element will be moved.\n * @param {string} id - The ID of the element to be moved.\n * @param {Node | null} after - The reference node to insert the element before.\n * If `null`, the element is appended as the last child.\n * @param {MorphContext} ctx\n * @returns {Element} The found element\n */\n function moveBeforeById(parentNode, id, after, ctx) {\n const target =\n /** @type {Element} - will always be found */\n (\n ctx.target.querySelector(`#${id}`) ||\n ctx.pantry.querySelector(`#${id}`)\n );\n removeElementFromAncestorsIdMaps(target, ctx);\n moveBefore(parentNode, target, after);\n return target;\n }\n\n /**\n * Removes an element from its ancestors' id maps. This is needed when an element is moved from the\n * \"future\" via `moveBeforeId`. Otherwise, its erstwhile ancestors could be mistakenly moved to the\n * pantry rather than being deleted, preventing their removal hooks from being called.\n *\n * @param {Element} element - element to remove from its ancestors' id maps\n * @param {MorphContext} ctx\n */\n function removeElementFromAncestorsIdMaps(element, ctx) {\n const id = element.id;\n /** @ts-ignore - safe to loop in this way **/\n while ((element = element.parentNode)) {\n let idSet = ctx.idMap.get(element);\n if (idSet) {\n idSet.delete(id);\n if (!idSet.size) {\n ctx.idMap.delete(element);\n }\n }\n }\n }\n\n /**\n * Moves an element before another element within the same parent.\n * Uses the proposed `moveBefore` API if available (and working), otherwise falls back to `insertBefore`.\n * This is essentialy a forward-compat wrapper.\n *\n * @param {Element} parentNode - The parent node containing the after element.\n * @param {Node} element - The element to be moved.\n * @param {Node | null} after - The reference node to insert `element` before.\n * If `null`, `element` is appended as the last child.\n */\n function moveBefore(parentNode, element, after) {\n // @ts-ignore - use proposed moveBefore feature\n if (parentNode.moveBefore) {\n try {\n // @ts-ignore - use proposed moveBefore feature\n parentNode.moveBefore(element, after);\n } catch (e) {\n // fall back to insertBefore as some browsers may fail on moveBefore when trying to move Dom disconnected nodes to pantry\n parentNode.insertBefore(element, after);\n }\n } else {\n parentNode.insertBefore(element, after);\n }\n }\n\n return morphChildren;\n })();\n\n //=============================================================================\n // Single Node Morphing Code\n //=============================================================================\n const morphNode = (function () {\n /**\n * @param {Node} oldNode root node to merge content into\n * @param {Node} newContent new content to merge\n * @param {MorphContext} ctx the merge context\n * @returns {Node | null} the element that ended up in the DOM\n */\n function morphNode(oldNode, newContent, ctx) {\n if (ctx.ignoreActive && oldNode === document.activeElement) {\n // don't morph focused element\n return null;\n }\n\n if (ctx.callbacks.beforeNodeMorphed(oldNode, newContent) === false) {\n return oldNode;\n }\n\n if (oldNode instanceof HTMLHeadElement && ctx.head.ignore) ; else if (\n oldNode instanceof HTMLHeadElement &&\n ctx.head.style !== \"morph\"\n ) {\n // ok to cast: if newContent wasn't also a , it would've got caught in the `!isSoftMatch` branch above\n handleHeadElement(\n oldNode,\n /** @type {HTMLHeadElement} */ (newContent),\n ctx,\n );\n } else {\n morphAttributes(oldNode, newContent, ctx);\n if (!ignoreValueOfActiveElement(oldNode, ctx)) {\n // @ts-ignore newContent can be a node here because .firstChild will be null\n morphChildren(ctx, oldNode, newContent);\n }\n }\n ctx.callbacks.afterNodeMorphed(oldNode, newContent);\n return oldNode;\n }\n\n /**\n * syncs the oldNode to the newNode, copying over all attributes and\n * inner element state from the newNode to the oldNode\n *\n * @param {Node} oldNode the node to copy attributes & state to\n * @param {Node} newNode the node to copy attributes & state from\n * @param {MorphContext} ctx the merge context\n */\n function morphAttributes(oldNode, newNode, ctx) {\n let type = newNode.nodeType;\n\n // if is an element type, sync the attributes from the\n // new node into the new node\n if (type === 1 /* element type */) {\n const oldElt = /** @type {Element} */ (oldNode);\n const newElt = /** @type {Element} */ (newNode);\n\n const oldAttributes = oldElt.attributes;\n const newAttributes = newElt.attributes;\n for (const newAttribute of newAttributes) {\n if (ignoreAttribute(newAttribute.name, oldElt, \"update\", ctx)) {\n continue;\n }\n if (oldElt.getAttribute(newAttribute.name) !== newAttribute.value) {\n oldElt.setAttribute(newAttribute.name, newAttribute.value);\n }\n }\n // iterate backwards to avoid skipping over items when a delete occurs\n for (let i = oldAttributes.length - 1; 0 <= i; i--) {\n const oldAttribute = oldAttributes[i];\n\n // toAttributes is a live NamedNodeMap, so iteration+mutation is unsafe\n // e.g. custom element attribute callbacks can remove other attributes\n if (!oldAttribute) continue;\n\n if (!newElt.hasAttribute(oldAttribute.name)) {\n if (ignoreAttribute(oldAttribute.name, oldElt, \"remove\", ctx)) {\n continue;\n }\n oldElt.removeAttribute(oldAttribute.name);\n }\n }\n\n if (!ignoreValueOfActiveElement(oldElt, ctx)) {\n syncInputValue(oldElt, newElt, ctx);\n }\n }\n\n // sync text nodes\n if (type === 8 /* comment */ || type === 3 /* text */) {\n if (oldNode.nodeValue !== newNode.nodeValue) {\n oldNode.nodeValue = newNode.nodeValue;\n }\n }\n }\n\n /**\n * NB: many bothans died to bring us information:\n *\n * https://github.com/patrick-steele-idem/morphdom/blob/master/src/specialElHandlers.js\n * https://github.com/choojs/nanomorph/blob/master/lib/morph.jsL113\n *\n * @param {Element} oldElement the element to sync the input value to\n * @param {Element} newElement the element to sync the input value from\n * @param {MorphContext} ctx the merge context\n */\n function syncInputValue(oldElement, newElement, ctx) {\n if (\n oldElement instanceof HTMLInputElement &&\n newElement instanceof HTMLInputElement &&\n newElement.type !== \"file\"\n ) {\n let newValue = newElement.value;\n let oldValue = oldElement.value;\n\n // sync boolean attributes\n syncBooleanAttribute(oldElement, newElement, \"checked\", ctx);\n syncBooleanAttribute(oldElement, newElement, \"disabled\", ctx);\n\n if (!newElement.hasAttribute(\"value\")) {\n if (!ignoreAttribute(\"value\", oldElement, \"remove\", ctx)) {\n oldElement.value = \"\";\n oldElement.removeAttribute(\"value\");\n }\n } else if (oldValue !== newValue) {\n if (!ignoreAttribute(\"value\", oldElement, \"update\", ctx)) {\n oldElement.setAttribute(\"value\", newValue);\n oldElement.value = newValue;\n }\n }\n // TODO: QUESTION(1cg): this used to only check `newElement` unlike the other branches -- why?\n // did I break something?\n } else if (\n oldElement instanceof HTMLOptionElement &&\n newElement instanceof HTMLOptionElement\n ) {\n syncBooleanAttribute(oldElement, newElement, \"selected\", ctx);\n } else if (\n oldElement instanceof HTMLTextAreaElement &&\n newElement instanceof HTMLTextAreaElement\n ) {\n let newValue = newElement.value;\n let oldValue = oldElement.value;\n if (ignoreAttribute(\"value\", oldElement, \"update\", ctx)) {\n return;\n }\n if (newValue !== oldValue) {\n oldElement.value = newValue;\n }\n if (\n oldElement.firstChild &&\n oldElement.firstChild.nodeValue !== newValue\n ) {\n oldElement.firstChild.nodeValue = newValue;\n }\n }\n }\n\n /**\n * @param {Element} oldElement element to write the value to\n * @param {Element} newElement element to read the value from\n * @param {string} attributeName the attribute name\n * @param {MorphContext} ctx the merge context\n */\n function syncBooleanAttribute(oldElement, newElement, attributeName, ctx) {\n // @ts-ignore this function is only used on boolean attrs that are reflected as dom properties\n const newLiveValue = newElement[attributeName],\n // @ts-ignore ditto\n oldLiveValue = oldElement[attributeName];\n if (newLiveValue !== oldLiveValue) {\n const ignoreUpdate = ignoreAttribute(\n attributeName,\n oldElement,\n \"update\",\n ctx,\n );\n if (!ignoreUpdate) {\n // update attribute's associated DOM property\n // @ts-ignore this function is only used on boolean attrs that are reflected as dom properties\n oldElement[attributeName] = newElement[attributeName];\n }\n if (newLiveValue) {\n if (!ignoreUpdate) {\n // https://developer.mozilla.org/en-US/docs/Glossary/Boolean/HTML\n // this is the correct way to set a boolean attribute to \"true\"\n oldElement.setAttribute(attributeName, \"\");\n }\n } else {\n if (!ignoreAttribute(attributeName, oldElement, \"remove\", ctx)) {\n oldElement.removeAttribute(attributeName);\n }\n }\n }\n }\n\n /**\n * @param {string} attr the attribute to be mutated\n * @param {Element} element the element that is going to be updated\n * @param {\"update\" | \"remove\"} updateType\n * @param {MorphContext} ctx the merge context\n * @returns {boolean} true if the attribute should be ignored, false otherwise\n */\n function ignoreAttribute(attr, element, updateType, ctx) {\n if (\n attr === \"value\" &&\n ctx.ignoreActiveValue &&\n element === document.activeElement\n ) {\n return true;\n }\n return (\n ctx.callbacks.beforeAttributeUpdated(attr, element, updateType) ===\n false\n );\n }\n\n /**\n * @param {Node} possibleActiveElement\n * @param {MorphContext} ctx\n * @returns {boolean}\n */\n function ignoreValueOfActiveElement(possibleActiveElement, ctx) {\n return (\n !!ctx.ignoreActiveValue &&\n possibleActiveElement === document.activeElement &&\n possibleActiveElement !== document.body\n );\n }\n\n return morphNode;\n })();\n\n //=============================================================================\n // Head Management Functions\n //=============================================================================\n /**\n * @param {MorphContext} ctx\n * @param {Element} oldNode\n * @param {Element} newNode\n * @param {function} callback\n * @returns {Node[] | Promise}\n */\n function withHeadBlocking(ctx, oldNode, newNode, callback) {\n if (ctx.head.block) {\n const oldHead = oldNode.querySelector(\"head\");\n const newHead = newNode.querySelector(\"head\");\n if (oldHead && newHead) {\n const promises = handleHeadElement(oldHead, newHead, ctx);\n // when head promises resolve, proceed ignoring the head tag\n return Promise.all(promises).then(() => {\n const newCtx = Object.assign(ctx, {\n head: {\n block: false,\n ignore: true,\n },\n });\n return callback(newCtx);\n });\n }\n }\n // just proceed if we not head blocking\n return callback(ctx);\n }\n\n /**\n * The HEAD tag can be handled specially, either w/ a 'merge' or 'append' style\n *\n * @param {Element} oldHead\n * @param {Element} newHead\n * @param {MorphContext} ctx\n * @returns {Promise[]}\n */\n function handleHeadElement(oldHead, newHead, ctx) {\n let added = [];\n let removed = [];\n let preserved = [];\n let nodesToAppend = [];\n\n // put all new head elements into a Map, by their outerHTML\n let srcToNewHeadNodes = new Map();\n for (const newHeadChild of newHead.children) {\n srcToNewHeadNodes.set(newHeadChild.outerHTML, newHeadChild);\n }\n\n // for each elt in the current head\n for (const currentHeadElt of oldHead.children) {\n // If the current head element is in the map\n let inNewContent = srcToNewHeadNodes.has(currentHeadElt.outerHTML);\n let isReAppended = ctx.head.shouldReAppend(currentHeadElt);\n let isPreserved = ctx.head.shouldPreserve(currentHeadElt);\n if (inNewContent || isPreserved) {\n if (isReAppended) {\n // remove the current version and let the new version replace it and re-execute\n removed.push(currentHeadElt);\n } else {\n // this element already exists and should not be re-appended, so remove it from\n // the new content map, preserving it in the DOM\n srcToNewHeadNodes.delete(currentHeadElt.outerHTML);\n preserved.push(currentHeadElt);\n }\n } else {\n if (ctx.head.style === \"append\") {\n // we are appending and this existing element is not new content\n // so if and only if it is marked for re-append do we do anything\n if (isReAppended) {\n removed.push(currentHeadElt);\n nodesToAppend.push(currentHeadElt);\n }\n } else {\n // if this is a merge, we remove this content since it is not in the new head\n if (ctx.head.shouldRemove(currentHeadElt) !== false) {\n removed.push(currentHeadElt);\n }\n }\n }\n }\n\n // Push the remaining new head elements in the Map into the\n // nodes to append to the head tag\n nodesToAppend.push(...srcToNewHeadNodes.values());\n\n let promises = [];\n for (const newNode of nodesToAppend) {\n // TODO: This could theoretically be null, based on type\n let newElt = /** @type {ChildNode} */ (\n document.createRange().createContextualFragment(newNode.outerHTML)\n .firstChild\n );\n if (ctx.callbacks.beforeNodeAdded(newElt) !== false) {\n if (\n (\"href\" in newElt && newElt.href) ||\n (\"src\" in newElt && newElt.src)\n ) {\n /** @type {(result?: any) => void} */ let resolve;\n let promise = new Promise(function (_resolve) {\n resolve = _resolve;\n });\n newElt.addEventListener(\"load\", function () {\n resolve();\n });\n promises.push(promise);\n }\n oldHead.appendChild(newElt);\n ctx.callbacks.afterNodeAdded(newElt);\n added.push(newElt);\n }\n }\n\n // remove all removed elements, after we have appended the new elements to avoid\n // additional network requests for things like style sheets\n for (const removedElement of removed) {\n if (ctx.callbacks.beforeNodeRemoved(removedElement) !== false) {\n oldHead.removeChild(removedElement);\n ctx.callbacks.afterNodeRemoved(removedElement);\n }\n }\n\n ctx.head.afterHeadMorphed(oldHead, {\n added: added,\n kept: preserved,\n removed: removed,\n });\n return promises;\n }\n\n //=============================================================================\n // Create Morph Context Functions\n //=============================================================================\n const createMorphContext = (function () {\n /**\n *\n * @param {Element} oldNode\n * @param {Element} newContent\n * @param {Config} config\n * @returns {MorphContext}\n */\n function createMorphContext(oldNode, newContent, config) {\n const { persistentIds, idMap } = createIdMaps(oldNode, newContent);\n\n const mergedConfig = mergeDefaults(config);\n const morphStyle = mergedConfig.morphStyle || \"outerHTML\";\n if (![\"innerHTML\", \"outerHTML\"].includes(morphStyle)) {\n throw `Do not understand how to morph style ${morphStyle}`;\n }\n\n return {\n target: oldNode,\n newContent: newContent,\n config: mergedConfig,\n morphStyle: morphStyle,\n ignoreActive: mergedConfig.ignoreActive,\n ignoreActiveValue: mergedConfig.ignoreActiveValue,\n restoreFocus: mergedConfig.restoreFocus,\n idMap: idMap,\n persistentIds: persistentIds,\n pantry: createPantry(),\n callbacks: mergedConfig.callbacks,\n head: mergedConfig.head,\n };\n }\n\n /**\n * Deep merges the config object and the Idiomorph.defaults object to\n * produce a final configuration object\n * @param {Config} config\n * @returns {ConfigInternal}\n */\n function mergeDefaults(config) {\n let finalConfig = Object.assign({}, defaults);\n\n // copy top level stuff into final config\n Object.assign(finalConfig, config);\n\n // copy callbacks into final config (do this to deep merge the callbacks)\n finalConfig.callbacks = Object.assign(\n {},\n defaults.callbacks,\n config.callbacks,\n );\n\n // copy head config into final config (do this to deep merge the head)\n finalConfig.head = Object.assign({}, defaults.head, config.head);\n\n return finalConfig;\n }\n\n /**\n * @returns {HTMLDivElement}\n */\n function createPantry() {\n const pantry = document.createElement(\"div\");\n pantry.hidden = true;\n document.body.insertAdjacentElement(\"afterend\", pantry);\n return pantry;\n }\n\n /**\n * Returns all elements with an ID contained within the root element and its descendants\n *\n * @param {Element} root\n * @returns {Element[]}\n */\n function findIdElements(root) {\n let elements = Array.from(root.querySelectorAll(\"[id]\"));\n if (root.id) {\n elements.push(root);\n }\n return elements;\n }\n\n /**\n * A bottom-up algorithm that populates a map of Element -> IdSet.\n * The idSet for a given element is the set of all IDs contained within its subtree.\n * As an optimzation, we filter these IDs through the given list of persistent IDs,\n * because we don't need to bother considering IDed elements that won't be in the new content.\n *\n * @param {Map>} idMap\n * @param {Set} persistentIds\n * @param {Element} root\n * @param {Element[]} elements\n */\n function populateIdMapWithTree(idMap, persistentIds, root, elements) {\n for (const elt of elements) {\n if (persistentIds.has(elt.id)) {\n /** @type {Element|null} */\n let current = elt;\n // walk up the parent hierarchy of that element, adding the id\n // of element to the parent's id set\n while (current) {\n let idSet = idMap.get(current);\n // if the id set doesn't exist, create it and insert it in the map\n if (idSet == null) {\n idSet = new Set();\n idMap.set(current, idSet);\n }\n idSet.add(elt.id);\n\n if (current === root) break;\n current = current.parentElement;\n }\n }\n }\n }\n\n /**\n * This function computes a map of nodes to all ids contained within that node (inclusive of the\n * node). This map can be used to ask if two nodes have intersecting sets of ids, which allows\n * for a looser definition of \"matching\" than tradition id matching, and allows child nodes\n * to contribute to a parent nodes matching.\n *\n * @param {Element} oldContent the old content that will be morphed\n * @param {Element} newContent the new content to morph to\n * @returns {IdSets}\n */\n function createIdMaps(oldContent, newContent) {\n const oldIdElements = findIdElements(oldContent);\n const newIdElements = findIdElements(newContent);\n\n const persistentIds = createPersistentIds(oldIdElements, newIdElements);\n\n /** @type {Map>} */\n let idMap = new Map();\n populateIdMapWithTree(idMap, persistentIds, oldContent, oldIdElements);\n\n /** @ts-ignore - if newContent is a duck-typed parent, pass its single child node as the root to halt upwards iteration */\n const newRoot = newContent.__idiomorphRoot || newContent;\n populateIdMapWithTree(idMap, persistentIds, newRoot, newIdElements);\n\n return { persistentIds, idMap };\n }\n\n /**\n * This function computes the set of ids that persist between the two contents excluding duplicates\n *\n * @param {Element[]} oldIdElements\n * @param {Element[]} newIdElements\n * @returns {Set}\n */\n function createPersistentIds(oldIdElements, newIdElements) {\n let duplicateIds = new Set();\n\n /** @type {Map} */\n let oldIdTagNameMap = new Map();\n for (const { id, tagName } of oldIdElements) {\n if (oldIdTagNameMap.has(id)) {\n duplicateIds.add(id);\n } else {\n oldIdTagNameMap.set(id, tagName);\n }\n }\n\n let persistentIds = new Set();\n for (const { id, tagName } of newIdElements) {\n if (persistentIds.has(id)) {\n duplicateIds.add(id);\n } else if (oldIdTagNameMap.get(id) === tagName) {\n persistentIds.add(id);\n }\n // skip if tag types mismatch because its not possible to morph one tag into another\n }\n\n for (const id of duplicateIds) {\n persistentIds.delete(id);\n }\n return persistentIds;\n }\n\n return createMorphContext;\n })();\n\n //=============================================================================\n // HTML Normalization Functions\n //=============================================================================\n const { normalizeElement, normalizeParent } = (function () {\n /** @type {WeakSet} */\n const generatedByIdiomorph = new WeakSet();\n\n /**\n *\n * @param {Element | Document} content\n * @returns {Element}\n */\n function normalizeElement(content) {\n if (content instanceof Document) {\n return content.documentElement;\n } else {\n return content;\n }\n }\n\n /**\n *\n * @param {null | string | Node | HTMLCollection | Node[] | Document & {generatedByIdiomorph:boolean}} newContent\n * @returns {Element}\n */\n function normalizeParent(newContent) {\n if (newContent == null) {\n return document.createElement(\"div\"); // dummy parent element\n } else if (typeof newContent === \"string\") {\n return normalizeParent(parseContent(newContent));\n } else if (\n generatedByIdiomorph.has(/** @type {Element} */ (newContent))\n ) {\n // the template tag created by idiomorph parsing can serve as a dummy parent\n return /** @type {Element} */ (newContent);\n } else if (newContent instanceof Node) {\n if (newContent.parentNode) {\n // we can't use the parent directly because newContent may have siblings\n // that we don't want in the morph, and reparenting might be expensive (TODO is it?),\n // so we create a duck-typed parent node instead.\n return createDuckTypedParent(newContent);\n } else {\n // a single node is added as a child to a dummy parent\n const dummyParent = document.createElement(\"div\");\n dummyParent.append(newContent);\n return dummyParent;\n }\n } else {\n // all nodes in the array or HTMLElement collection are consolidated under\n // a single dummy parent element\n const dummyParent = document.createElement(\"div\");\n for (const elt of [...newContent]) {\n dummyParent.append(elt);\n }\n return dummyParent;\n }\n }\n\n /**\n * Creates a fake duck-typed parent element to wrap a single node, without actually reparenting it.\n * \"If it walks like a duck, and quacks like a duck, then it must be a duck!\" -- James Whitcomb Riley (1849\u20131916)\n *\n * @param {Node} newContent\n * @returns {Element}\n */\n function createDuckTypedParent(newContent) {\n return /** @type {Element} */ (\n /** @type {unknown} */ ({\n childNodes: [newContent],\n /** @ts-ignore - cover your eyes for a minute, tsc */\n querySelectorAll: (s) => {\n /** @ts-ignore */\n const elements = newContent.querySelectorAll(s);\n /** @ts-ignore */\n return newContent.matches(s) ? [newContent, ...elements] : elements;\n },\n /** @ts-ignore */\n insertBefore: (n, r) => newContent.parentNode.insertBefore(n, r),\n /** @ts-ignore */\n moveBefore: (n, r) => newContent.parentNode.moveBefore(n, r),\n // for later use with populateIdMapWithTree to halt upwards iteration\n get __idiomorphRoot() {\n return newContent;\n },\n })\n );\n }\n\n /**\n *\n * @param {string} newContent\n * @returns {Node | null | DocumentFragment}\n */\n function parseContent(newContent) {\n let parser = new DOMParser();\n\n // remove svgs to avoid false-positive matches on head, etc.\n let contentWithSvgsRemoved = newContent.replace(\n /