@forcecalendar/interface 1.0.46 → 1.0.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/force-calendar-interface.esm.js +275 -283
- package/dist/force-calendar-interface.esm.js.map +1 -1
- package/dist/force-calendar-interface.umd.js +97 -97
- package/dist/force-calendar-interface.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/renderers/BaseViewRenderer.js +6 -30
- package/src/renderers/DayViewRenderer.js +12 -12
- package/src/renderers/MonthViewRenderer.js +9 -9
- package/src/renderers/WeekViewRenderer.js +14 -14
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(function(l,u){typeof exports=="object"&&typeof module<"u"?u(exports,require("@forcecalendar/core")):typeof define=="function"&&define.amd?define(["exports","@forcecalendar/core"],u):(l=typeof globalThis<"u"?globalThis:l||self,u(l.ForceCalendarInterface={},l.ForceCalendarCore))})(this,function(l,u){"use strict";var B=Object.defineProperty;var A=(l,u,v)=>u in l?B(l,u,{enumerable:!0,configurable:!0,writable:!0,value:v}):l[u]=v;var y=(l,u,v)=>A(l,typeof u!="symbol"?u+"":u,v);class v extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._listeners=[],this._state=null,this._props=new Map,this._initialized=!1}connectedCallback(){this._initialized||(this.initialize(),this._initialized=!0),this.mount()}disconnectedCallback(){this.unmount(),this.cleanup()}initialize(){}mount(){this.render()}unmount(){}cleanup(){this._listeners.forEach(({element:
|
|
1
|
+
(function(l,u){typeof exports=="object"&&typeof module<"u"?u(exports,require("@forcecalendar/core")):typeof define=="function"&&define.amd?define(["exports","@forcecalendar/core"],u):(l=typeof globalThis<"u"?globalThis:l||self,u(l.ForceCalendarInterface={},l.ForceCalendarCore))})(this,function(l,u){"use strict";var B=Object.defineProperty;var A=(l,u,v)=>u in l?B(l,u,{enumerable:!0,configurable:!0,writable:!0,value:v}):l[u]=v;var y=(l,u,v)=>A(l,typeof u!="symbol"?u+"":u,v);class v extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._listeners=[],this._state=null,this._props=new Map,this._initialized=!1}connectedCallback(){this._initialized||(this.initialize(),this._initialized=!0),this.mount()}disconnectedCallback(){this.unmount(),this.cleanup()}initialize(){}mount(){this.render()}unmount(){}cleanup(){this._listeners.forEach(({element:t,event:e,handler:r})=>{t.removeEventListener(e,r)}),this._listeners=[]}setState(t){const e=this._state;this._state={...this._state,...t},this.stateChanged(e,this._state),this.render()}getState(){return this._state}stateChanged(t,e){}setProp(t,e){const r=this._props.get(t);this._props.set(t,e),this.propChanged(t,r,e)}getProp(t){return this._props.get(t)}propChanged(t,e,r){}addListener(t,e,r){if(!t||!e||!r){console.warn("addListener called with invalid parameters",{element:t,event:e,handler:r});return}const i=r.bind(this);t.addEventListener(e,i),this._listeners.push({element:t,event:e,handler:i})}emit(t,e={}){this.dispatchEvent(new CustomEvent(t,{detail:e,bubbles:!0,composed:!0}))}getStyles(){return""}getBaseStyles(){return`
|
|
2
2
|
:host {
|
|
3
3
|
display: block;
|
|
4
4
|
box-sizing: border-box;
|
|
@@ -7,15 +7,15 @@
|
|
|
7
7
|
*, *::before, *::after {
|
|
8
8
|
box-sizing: inherit;
|
|
9
9
|
}
|
|
10
|
-
`}render(){this.cleanup();const
|
|
10
|
+
`}render(){this.cleanup();const t=`
|
|
11
11
|
<style>
|
|
12
12
|
${this.getBaseStyles()}
|
|
13
13
|
${this.getStyles()}
|
|
14
14
|
</style>
|
|
15
|
-
`,t=this.template();this.shadowRoot.innerHTML=e+t,this.afterRender()}template(){return""}afterRender(){}$(e){return this.shadowRoot.querySelector(e)}$$(e){return this.shadowRoot.querySelectorAll(e)}static get observedAttributes(){return[]}attributeChangedCallback(e,t,r){this.setProp(e,r),this._initialized&&this.render()}}class k{constructor(){this.events=new Map,this.wildcardHandlers=new Set}on(e,t,r={}){const{once:i=!1,priority:s=0}=r;if(e.includes("*")){const a={pattern:e,handler:t,once:i,priority:s};return this.wildcardHandlers.add(a),()=>this.wildcardHandlers.delete(a)}this.events.has(e)||this.events.set(e,[]);const n={handler:t,once:i,priority:s},o=this.events.get(e);return o.push(n),o.sort((a,c)=>c.priority-a.priority),()=>{const a=o.indexOf(n);a>-1&&o.splice(a,1)}}once(e,t,r={}){return this.on(e,t,{...r,once:!0})}off(e,t){if(e.includes("*")){for(const s of this.wildcardHandlers)if(s.pattern===e&&s.handler===t){this.wildcardHandlers.delete(s);return}return}if(!this.events.has(e))return;const r=this.events.get(e),i=r.findIndex(s=>s.handler===t);i>-1&&r.splice(i,1),r.length===0&&this.events.delete(e)}offWildcard(e){for(const t of[...this.wildcardHandlers])t.pattern===e&&this.wildcardHandlers.delete(t)}offAll(e){for(const[t,r]of this.events){const i=r.findIndex(s=>s.handler===e);i>-1&&r.splice(i,1),r.length===0&&this.events.delete(t)}for(const t of[...this.wildcardHandlers])t.handler===e&&this.wildcardHandlers.delete(t)}emit(e,t){if(this.events.has(e)){const i=[...this.events.get(e)];for(const s of i){const{handler:n,once:o}=s;o&&this.off(e,n);try{n(t,e)}catch(a){console.error(`Error in event handler for ${e}:`,a)}}}const r=[];for(const i of[...this.wildcardHandlers])if(this.matchesPattern(e,i.pattern)){const{handler:s,once:n}=i;n&&r.push(i);try{s(t,e)}catch(o){console.error(`Error in wildcard handler for ${e}:`,o)}}r.forEach(i=>this.wildcardHandlers.delete(i))}matchesPattern(e,t){return new RegExp("^"+t.replace(/\*/g,".*")+"$").test(e)}clear(){this.events.clear(),this.wildcardHandlers.clear()}getEventNames(){return Array.from(this.events.keys())}getHandlerCount(e){return this.events.has(e)?this.events.get(e).length:0}getWildcardHandlerCount(){return this.wildcardHandlers.size}getTotalHandlerCount(){let e=this.wildcardHandlers.size;for(const t of this.events.values())e+=t.length;return e}}const V=new k;class S{constructor(e={}){this.eventBus=new k,this.calendar=new u.Calendar({view:e.view||"month",date:e.date||new Date,weekStartsOn:e.weekStartsOn??0,locale:e.locale||"en-US",timeZone:e.timeZone||Intl.DateTimeFormat().resolvedOptions().timeZone,...e}),this.state={view:this.calendar.getView(),currentDate:this.calendar.getCurrentDate(),events:[],selectedEvent:null,selectedDate:null,loading:!1,error:null,config:{...e}},this.subscribers=new Set,this.subscribe=this.subscribe.bind(this),this.unsubscribe=this.unsubscribe.bind(this),this.setState=this.setState.bind(this),this._syncEventsFromCore({silent:!0})}_syncEventsFromCore(e={}){const{force:t=!1}=e,r=this.calendar.getEvents()||[];return(t||this.state.events.length!==r.length||!this._eventsMatch(this.state.events,r))&&this.setState({events:[...r]},e),r}_eventsMatch(e,t){if(e.length!==t.length)return!1;const r=new Set(e.map(i=>i.id));return t.every(i=>r.has(i.id))}getState(){return{...this.state,config:{...this.state.config},events:[...this.state.events]}}setState(e,t={}){const{silent:r=!1}=t,i={...this.state};return this.state={...this.state,...e},r||(this.notifySubscribers(i,this.state),this.emitStateChange(i,this.state)),this.state}subscribe(e,t=null){return this.subscribers.add(e),t&&(this._subscriberIds||(this._subscriberIds=new Map),this._subscriberIds.set(t,e)),()=>this.unsubscribe(e,t)}unsubscribe(e,t=null){this.subscribers.delete(e),t&&this._subscriberIds&&this._subscriberIds.delete(t)}unsubscribeById(e){if(!this._subscriberIds)return!1;const t=this._subscriberIds.get(e);return t?(this.subscribers.delete(t),this._subscriberIds.delete(e),!0):!1}getSubscriberCount(){return this.subscribers.size}notifySubscribers(e,t){this.subscribers.forEach(r=>{try{r(t,e)}catch(i){console.error("Error in state subscriber:",i)}})}emitStateChange(e,t){const r=Object.keys(t).filter(i=>e[i]!==t[i]);r.forEach(i=>{this.eventBus.emit(`state:${i}:changed`,{oldValue:e[i],newValue:t[i],state:t})}),r.length>0&&this.eventBus.emit("state:changed",{oldState:e,newState:t,changedKeys:r})}setView(e){this.calendar.setView(e),this.setState({view:e}),this.eventBus.emit("view:changed",{view:e})}getView(){return this.state.view}setDate(e){this.calendar.goToDate(e),this.setState({currentDate:this.calendar.getCurrentDate()}),this.eventBus.emit("date:changed",{date:this.state.currentDate})}getCurrentDate(){return this.state.currentDate}next(){this.calendar.next(),this.setState({currentDate:this.calendar.getCurrentDate()}),this.eventBus.emit("navigation:next",{date:this.state.currentDate})}previous(){this.calendar.previous(),this.setState({currentDate:this.calendar.getCurrentDate()}),this.eventBus.emit("navigation:previous",{date:this.state.currentDate})}today(){this.calendar.today(),this.setState({currentDate:this.calendar.getCurrentDate()}),this.eventBus.emit("navigation:today",{date:this.state.currentDate})}goToDate(e){this.calendar.goToDate(e),this.setState({currentDate:this.calendar.getCurrentDate()}),this.eventBus.emit("navigation:goto",{date:this.state.currentDate})}addEvent(e){const t=this.calendar.addEvent(e);return t?(this._syncEventsFromCore(),this.eventBus.emit("event:add",{event:t}),this.eventBus.emit("event:added",{event:t}),t):(console.error("Failed to add event to calendar"),this.eventBus.emit("event:error",{action:"add",event:e,error:"Failed to add event"}),null)}updateEvent(e,t){this._syncEventsFromCore({silent:!0});const r=this.calendar.updateEvent(e,t);return r?(this._syncEventsFromCore({force:!0}),this.eventBus.emit("event:update",{event:r}),this.eventBus.emit("event:updated",{event:r}),r):(console.error(`Failed to update event: ${e}`),this.eventBus.emit("event:error",{action:"update",eventId:e,updates:t,error:"Event not found in calendar"}),null)}deleteEvent(e){return this._syncEventsFromCore({silent:!0}),this.calendar.removeEvent(e)?(this._syncEventsFromCore(),this.eventBus.emit("event:remove",{eventId:e}),this.eventBus.emit("event:deleted",{eventId:e}),!0):(console.error(`Failed to delete event: ${e}`),this.eventBus.emit("event:error",{action:"delete",eventId:e,error:"Event not found"}),!1)}getEvents(){return this.calendar.getEvents()||[]}syncEvents(){return this._syncEventsFromCore()}getEventsForDate(e){return this.calendar.getEventsForDate(e)}getEventsInRange(e,t){return this.calendar.getEventsInRange(e,t)}getViewData(){const e=this.calendar.getViewData();return this.enrichViewData(e)}enrichViewData(e){var i;const t={...e},r=(i=this.state.selectedDate)==null?void 0:i.toDateString();if(t.weeks&&(t.weeks=t.weeks.map(s=>({...s,days:s.days.map(n=>{const o=new Date(n.date);return{...n,isSelected:o.toDateString()===r,events:n.events||this.getEventsForDate(o)}})}))),t.days&&(t.days=t.days.map(s=>{const n=new Date(s.date);return{...s,isSelected:n.toDateString()===r,events:s.events||this.getEventsForDate(n)}})),t.date&&!t.days&&!t.weeks){const s=new Date(t.date);t.isSelected=s.toDateString()===r,t.events=t.events||this.getEventsForDate(s)}return t}selectEvent(e){this.setState({selectedEvent:e}),this.eventBus.emit("event:selected",{event:e})}selectEventById(e){const t=this.state.events.find(r=>r.id===e);t&&this.selectEvent(t)}deselectEvent(){this.setState({selectedEvent:null}),this.eventBus.emit("event:deselected",{})}selectDate(e){this.setState({selectedDate:e}),this.eventBus.emit("date:selected",{date:e})}deselectDate(){this.setState({selectedDate:null}),this.eventBus.emit("date:deselected",{})}isToday(e){const t=new Date;return e.toDateString()===t.toDateString()}isSelectedDate(e){return this.state.selectedDate&&e.toDateString()===this.state.selectedDate.toDateString()}isWeekend(e){const t=e.getDay();return t===0||t===6}setLoading(e){this.setState({loading:e})}setError(e){this.setState({error:e}),e&&this.eventBus.emit("error",{error:e})}clearError(){this.setState({error:null})}updateConfig(e){this.setState({config:{...this.state.config,...e}}),e.weekStartsOn!==void 0&&this.calendar.setWeekStartsOn(e.weekStartsOn),e.locale!==void 0&&this.calendar.setLocale(e.locale),e.timeZone!==void 0&&this.calendar.setTimezone(e.timeZone)}destroy(){this.subscribers.clear(),this._subscriberIds&&(this._subscriberIds.clear(),this._subscriberIds=null),this.eventBus&&(this.eventBus.clear(),this.eventBus=null),this.state=null,this.calendar=null}}class m extends u.DateUtils{static formatDate(e,t="default",r="en-US"){if(!e)return"";const i={default:{year:"numeric",month:"long",day:"numeric"},short:{year:"numeric",month:"short",day:"numeric"},long:{weekday:"long",year:"numeric",month:"long",day:"numeric"},month:{year:"numeric",month:"long"},monthShort:{year:"numeric",month:"short"},day:{weekday:"long",day:"numeric"},dayShort:{weekday:"short",day:"numeric"},time:{hour:"numeric",minute:"2-digit"},timeShort:{hour:"numeric"},datetime:{year:"numeric",month:"short",day:"numeric",hour:"numeric",minute:"2-digit"}},s=i[t]||i.default;return new Intl.DateTimeFormat(r,s).format(e)}static formatTime(e,t=!0,r=!1,i="en-US"){if(!e)return"";const s={hour:"numeric",minute:t?"2-digit":void 0,hour12:!r};return new Intl.DateTimeFormat(i,s).format(e)}static formatDateRange(e,t,r="en-US"){if(!e)return"";if(!t||this.isSameDay(e,t))return this.formatDate(e,"default",r);const i=this.isSameYear(e,t)?"short":"default";return`${this.formatDate(e,i,r)} - ${this.formatDate(t,"default",r)}`}static formatTimeRange(e,t,r="en-US"){if(!e)return"";const i=this.formatTime(e,!0,!1,r);if(!t)return i;const s=this.formatTime(t,!0,!1,r);return`${i} - ${s}`}static getRelativeTime(e,t=new Date,r="en-US"){const i=new Intl.RelativeTimeFormat(r,{numeric:"auto"}),s=e-t,n=Math.floor(s/1e3),o=Math.floor(n/60),a=Math.floor(o/60),c=Math.floor(a/24),d=Math.floor(c/7),h=Math.floor(c/30),p=Math.floor(c/365);return Math.abs(n)<60?i.format(n,"second"):Math.abs(o)<60?i.format(o,"minute"):Math.abs(a)<24?i.format(a,"hour"):Math.abs(c)<7?i.format(c,"day"):Math.abs(d)<4?i.format(d,"week"):Math.abs(h)<12?i.format(h,"month"):i.format(p,"year")}static isToday(e){const t=new Date;return this.isSameDay(e,t)}static isPast(e){return e<new Date}static isFuture(e){return e>new Date}static getWeekNumber(e){const t=new Date(e.getFullYear(),0,1),r=(e-t)/864e5;return Math.ceil((r+t.getDay()+1)/7)}static getDayAbbreviation(e,t="en-US"){const r=new Date(2024,0,7+e);return new Intl.DateTimeFormat(t,{weekday:"short"}).format(r)}static getMonthName(e,t="long",r="en-US"){const i=new Date(2024,e,1);return new Intl.DateTimeFormat(r,{month:t}).format(i)}static parseTimeString(e,t=new Date){const r=new Date(t),[i,s]=e.split(/\s+/),[n,o]=i.split(":").map(Number);let a=n;return s&&(s.toLowerCase()==="pm"&&n<12?a=n+12:s.toLowerCase()==="am"&&n===12&&(a=0)),r.setHours(a,o||0,0,0),r}}class w{static createElement(e,t={},r=[]){const i=document.createElement(e);return Object.entries(t).forEach(([s,n])=>{if(s==="className")i.className=n;else if(s==="style"&&typeof n=="object")Object.assign(i.style,n);else if(s.startsWith("data-"))i.setAttribute(s,n);else if(s.startsWith("on")&&typeof n=="function"){const o=s.slice(2).toLowerCase();i.addEventListener(o,n)}else i[s]=n}),r.forEach(s=>{typeof s=="string"?i.appendChild(document.createTextNode(s)):s instanceof Node&&i.appendChild(s)}),i}static addEventListeners(e,t){return Object.entries(t).forEach(([r,i])=>{e.addEventListener(r,i)}),()=>{Object.entries(t).forEach(([r,i])=>{e.removeEventListener(r,i)})}}static delegate(e,t,r,i){const s=n=>{const o=n.target.closest(t);o&&e.contains(o)&&i.call(o,n)};return e.addEventListener(r,s),()=>e.removeEventListener(r,s)}static getPosition(e){const t=e.getBoundingClientRect();return{top:t.top+window.scrollY,left:t.left+window.scrollX,bottom:t.bottom+window.scrollY,right:t.right+window.scrollX,width:t.width,height:t.height}}static isInViewport(e,t=0){const r=e.getBoundingClientRect();return r.top>=-t&&r.left>=-t&&r.bottom<=(window.innerHeight||document.documentElement.clientHeight)+t&&r.right<=(window.innerWidth||document.documentElement.clientWidth)+t}static scrollToElement(e,t={}){const{behavior:r="smooth",block:i="start",inline:s="nearest"}=t;e.scrollIntoView({behavior:r,block:i,inline:s})}static getStyle(e,t){return window.getComputedStyle(e).getPropertyValue(t)}static setStyles(e,t){Object.assign(e.style,t)}static async animateClass(e,t,r=300){e.classList.add(t),await this.wait(r),e.classList.remove(t)}static waitForAnimation(e,t="animationend"){return new Promise(r=>{const i=()=>{e.removeEventListener(t,i),r()};e.addEventListener(t,i)})}static wait(e){return new Promise(t=>setTimeout(t,e))}static parseHTML(e){const t=document.createElement("template");return t.innerHTML=e.trim(),t.content.firstChild}static escapeHTML(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}static debounce(e,t=250){let r;return function(...s){const n=()=>{clearTimeout(r),e(...s)};clearTimeout(r),r=setTimeout(n,t)}}static throttle(e,t=250){let r;return function(...i){r||(e.apply(this,i),r=!0,setTimeout(()=>r=!1,t))}}static closest(e,t){return e.closest(t)}static parents(e,t){const r=[];let i=e.parentElement;for(;i;)i.matches(t)&&r.push(i),i=i.parentElement;return r}static getOuterDimensions(e){const t=window.getComputedStyle(e),r={top:parseInt(t.marginTop),right:parseInt(t.marginRight),bottom:parseInt(t.marginBottom),left:parseInt(t.marginLeft)};return{width:e.offsetWidth+r.left+r.right,height:e.offsetHeight+r.top+r.bottom,margin:r}}static cloneWithEvents(e,t=!0){return e.cloneNode(t)}static trapFocus(e){const t=e.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');if(t.length===0)return e.setAttribute("tabindex","-1"),e.focus(),()=>e.removeAttribute("tabindex");const r=t[0],i=t[t.length-1],s=n=>{n.key==="Tab"&&(n.shiftKey?document.activeElement===r&&(i==null||i.focus(),n.preventDefault()):document.activeElement===i&&(r==null||r.focus(),n.preventDefault()))};return e.addEventListener("keydown",s),r==null||r.focus(),()=>e.removeEventListener("keydown",s)}}class f{static getCSSVariable(e,t=document.documentElement){return getComputedStyle(t).getPropertyValue(e).trim()}static setCSSVariables(e,t=document.documentElement){Object.entries(e).forEach(([r,i])=>{t.style.setProperty(r,i)})}static getBaseStyles(){return`
|
|
15
|
+
`,e=this.template();this.shadowRoot.innerHTML=t+e,this.afterRender()}template(){return""}afterRender(){}$(t){return this.shadowRoot.querySelector(t)}$$(t){return this.shadowRoot.querySelectorAll(t)}static get observedAttributes(){return[]}attributeChangedCallback(t,e,r){this.setProp(t,r),this._initialized&&this.render()}}class E{constructor(){this.events=new Map,this.wildcardHandlers=new Set}on(t,e,r={}){const{once:i=!1,priority:s=0}=r;if(t.includes("*")){const o={pattern:t,handler:e,once:i,priority:s};return this.wildcardHandlers.add(o),()=>this.wildcardHandlers.delete(o)}this.events.has(t)||this.events.set(t,[]);const n={handler:e,once:i,priority:s},a=this.events.get(t);return a.push(n),a.sort((o,c)=>c.priority-o.priority),()=>{const o=a.indexOf(n);o>-1&&a.splice(o,1)}}once(t,e,r={}){return this.on(t,e,{...r,once:!0})}off(t,e){if(t.includes("*")){for(const s of this.wildcardHandlers)if(s.pattern===t&&s.handler===e){this.wildcardHandlers.delete(s);return}return}if(!this.events.has(t))return;const r=this.events.get(t),i=r.findIndex(s=>s.handler===e);i>-1&&r.splice(i,1),r.length===0&&this.events.delete(t)}offWildcard(t){for(const e of[...this.wildcardHandlers])e.pattern===t&&this.wildcardHandlers.delete(e)}offAll(t){for(const[e,r]of this.events){const i=r.findIndex(s=>s.handler===t);i>-1&&r.splice(i,1),r.length===0&&this.events.delete(e)}for(const e of[...this.wildcardHandlers])e.handler===t&&this.wildcardHandlers.delete(e)}emit(t,e){if(this.events.has(t)){const i=[...this.events.get(t)];for(const s of i){const{handler:n,once:a}=s;a&&this.off(t,n);try{n(e,t)}catch(o){console.error(`Error in event handler for ${t}:`,o)}}}const r=[];for(const i of[...this.wildcardHandlers])if(this.matchesPattern(t,i.pattern)){const{handler:s,once:n}=i;n&&r.push(i);try{s(e,t)}catch(a){console.error(`Error in wildcard handler for ${t}:`,a)}}r.forEach(i=>this.wildcardHandlers.delete(i))}matchesPattern(t,e){return new RegExp("^"+e.replace(/\*/g,".*")+"$").test(t)}clear(){this.events.clear(),this.wildcardHandlers.clear()}getEventNames(){return Array.from(this.events.keys())}getHandlerCount(t){return this.events.has(t)?this.events.get(t).length:0}getWildcardHandlerCount(){return this.wildcardHandlers.size}getTotalHandlerCount(){let t=this.wildcardHandlers.size;for(const e of this.events.values())t+=e.length;return t}}const V=new E;class S{constructor(t={}){this.eventBus=new E,this.calendar=new u.Calendar({view:t.view||"month",date:t.date||new Date,weekStartsOn:t.weekStartsOn??0,locale:t.locale||"en-US",timeZone:t.timeZone||Intl.DateTimeFormat().resolvedOptions().timeZone,...t}),this.state={view:this.calendar.getView(),currentDate:this.calendar.getCurrentDate(),events:[],selectedEvent:null,selectedDate:null,loading:!1,error:null,config:{...t}},this.subscribers=new Set,this.subscribe=this.subscribe.bind(this),this.unsubscribe=this.unsubscribe.bind(this),this.setState=this.setState.bind(this),this._syncEventsFromCore({silent:!0})}_syncEventsFromCore(t={}){const{force:e=!1}=t,r=this.calendar.getEvents()||[];return(e||this.state.events.length!==r.length||!this._eventsMatch(this.state.events,r))&&this.setState({events:[...r]},t),r}_eventsMatch(t,e){if(t.length!==e.length)return!1;const r=new Set(t.map(i=>i.id));return e.every(i=>r.has(i.id))}getState(){return{...this.state,config:{...this.state.config},events:[...this.state.events]}}setState(t,e={}){const{silent:r=!1}=e,i={...this.state};return this.state={...this.state,...t},r||(this.notifySubscribers(i,this.state),this.emitStateChange(i,this.state)),this.state}subscribe(t,e=null){return this.subscribers.add(t),e&&(this._subscriberIds||(this._subscriberIds=new Map),this._subscriberIds.set(e,t)),()=>this.unsubscribe(t,e)}unsubscribe(t,e=null){this.subscribers.delete(t),e&&this._subscriberIds&&this._subscriberIds.delete(e)}unsubscribeById(t){if(!this._subscriberIds)return!1;const e=this._subscriberIds.get(t);return e?(this.subscribers.delete(e),this._subscriberIds.delete(t),!0):!1}getSubscriberCount(){return this.subscribers.size}notifySubscribers(t,e){this.subscribers.forEach(r=>{try{r(e,t)}catch(i){console.error("Error in state subscriber:",i)}})}emitStateChange(t,e){const r=Object.keys(e).filter(i=>t[i]!==e[i]);r.forEach(i=>{this.eventBus.emit(`state:${i}:changed`,{oldValue:t[i],newValue:e[i],state:e})}),r.length>0&&this.eventBus.emit("state:changed",{oldState:t,newState:e,changedKeys:r})}setView(t){this.calendar.setView(t),this.setState({view:t}),this.eventBus.emit("view:changed",{view:t})}getView(){return this.state.view}setDate(t){this.calendar.goToDate(t),this.setState({currentDate:this.calendar.getCurrentDate()}),this.eventBus.emit("date:changed",{date:this.state.currentDate})}getCurrentDate(){return this.state.currentDate}next(){this.calendar.next(),this.setState({currentDate:this.calendar.getCurrentDate()}),this.eventBus.emit("navigation:next",{date:this.state.currentDate})}previous(){this.calendar.previous(),this.setState({currentDate:this.calendar.getCurrentDate()}),this.eventBus.emit("navigation:previous",{date:this.state.currentDate})}today(){this.calendar.today(),this.setState({currentDate:this.calendar.getCurrentDate()}),this.eventBus.emit("navigation:today",{date:this.state.currentDate})}goToDate(t){this.calendar.goToDate(t),this.setState({currentDate:this.calendar.getCurrentDate()}),this.eventBus.emit("navigation:goto",{date:this.state.currentDate})}addEvent(t){const e=this.calendar.addEvent(t);return e?(this._syncEventsFromCore(),this.eventBus.emit("event:add",{event:e}),this.eventBus.emit("event:added",{event:e}),e):(console.error("Failed to add event to calendar"),this.eventBus.emit("event:error",{action:"add",event:t,error:"Failed to add event"}),null)}updateEvent(t,e){this._syncEventsFromCore({silent:!0});const r=this.calendar.updateEvent(t,e);return r?(this._syncEventsFromCore({force:!0}),this.eventBus.emit("event:update",{event:r}),this.eventBus.emit("event:updated",{event:r}),r):(console.error(`Failed to update event: ${t}`),this.eventBus.emit("event:error",{action:"update",eventId:t,updates:e,error:"Event not found in calendar"}),null)}deleteEvent(t){return this._syncEventsFromCore({silent:!0}),this.calendar.removeEvent(t)?(this._syncEventsFromCore(),this.eventBus.emit("event:remove",{eventId:t}),this.eventBus.emit("event:deleted",{eventId:t}),!0):(console.error(`Failed to delete event: ${t}`),this.eventBus.emit("event:error",{action:"delete",eventId:t,error:"Event not found"}),!1)}getEvents(){return this.calendar.getEvents()||[]}syncEvents(){return this._syncEventsFromCore()}getEventsForDate(t){return this.calendar.getEventsForDate(t)}getEventsInRange(t,e){return this.calendar.getEventsInRange(t,e)}getViewData(){const t=this.calendar.getViewData();return this.enrichViewData(t)}enrichViewData(t){var i;const e={...t},r=(i=this.state.selectedDate)==null?void 0:i.toDateString();if(e.weeks&&(e.weeks=e.weeks.map(s=>({...s,days:s.days.map(n=>{const a=new Date(n.date);return{...n,isSelected:a.toDateString()===r,events:n.events||this.getEventsForDate(a)}})}))),e.days&&(e.days=e.days.map(s=>{const n=new Date(s.date);return{...s,isSelected:n.toDateString()===r,events:s.events||this.getEventsForDate(n)}})),e.date&&!e.days&&!e.weeks){const s=new Date(e.date);e.isSelected=s.toDateString()===r,e.events=e.events||this.getEventsForDate(s)}return e}selectEvent(t){this.setState({selectedEvent:t}),this.eventBus.emit("event:selected",{event:t})}selectEventById(t){const e=this.state.events.find(r=>r.id===t);e&&this.selectEvent(e)}deselectEvent(){this.setState({selectedEvent:null}),this.eventBus.emit("event:deselected",{})}selectDate(t){this.setState({selectedDate:t}),this.eventBus.emit("date:selected",{date:t})}deselectDate(){this.setState({selectedDate:null}),this.eventBus.emit("date:deselected",{})}isToday(t){const e=new Date;return t.toDateString()===e.toDateString()}isSelectedDate(t){return this.state.selectedDate&&t.toDateString()===this.state.selectedDate.toDateString()}isWeekend(t){const e=t.getDay();return e===0||e===6}setLoading(t){this.setState({loading:t})}setError(t){this.setState({error:t}),t&&this.eventBus.emit("error",{error:t})}clearError(){this.setState({error:null})}updateConfig(t){this.setState({config:{...this.state.config,...t}}),t.weekStartsOn!==void 0&&this.calendar.setWeekStartsOn(t.weekStartsOn),t.locale!==void 0&&this.calendar.setLocale(t.locale),t.timeZone!==void 0&&this.calendar.setTimezone(t.timeZone)}destroy(){this.subscribers.clear(),this._subscriberIds&&(this._subscriberIds.clear(),this._subscriberIds=null),this.eventBus&&(this.eventBus.clear(),this.eventBus=null),this.state=null,this.calendar=null}}class m extends u.DateUtils{static formatDate(t,e="default",r="en-US"){if(!t)return"";const i={default:{year:"numeric",month:"long",day:"numeric"},short:{year:"numeric",month:"short",day:"numeric"},long:{weekday:"long",year:"numeric",month:"long",day:"numeric"},month:{year:"numeric",month:"long"},monthShort:{year:"numeric",month:"short"},day:{weekday:"long",day:"numeric"},dayShort:{weekday:"short",day:"numeric"},time:{hour:"numeric",minute:"2-digit"},timeShort:{hour:"numeric"},datetime:{year:"numeric",month:"short",day:"numeric",hour:"numeric",minute:"2-digit"}},s=i[e]||i.default;return new Intl.DateTimeFormat(r,s).format(t)}static formatTime(t,e=!0,r=!1,i="en-US"){if(!t)return"";const s={hour:"numeric",minute:e?"2-digit":void 0,hour12:!r};return new Intl.DateTimeFormat(i,s).format(t)}static formatDateRange(t,e,r="en-US"){if(!t)return"";if(!e||this.isSameDay(t,e))return this.formatDate(t,"default",r);const i=this.isSameYear(t,e)?"short":"default";return`${this.formatDate(t,i,r)} - ${this.formatDate(e,"default",r)}`}static formatTimeRange(t,e,r="en-US"){if(!t)return"";const i=this.formatTime(t,!0,!1,r);if(!e)return i;const s=this.formatTime(e,!0,!1,r);return`${i} - ${s}`}static getRelativeTime(t,e=new Date,r="en-US"){const i=new Intl.RelativeTimeFormat(r,{numeric:"auto"}),s=t-e,n=Math.floor(s/1e3),a=Math.floor(n/60),o=Math.floor(a/60),c=Math.floor(o/24),d=Math.floor(c/7),h=Math.floor(c/30),p=Math.floor(c/365);return Math.abs(n)<60?i.format(n,"second"):Math.abs(a)<60?i.format(a,"minute"):Math.abs(o)<24?i.format(o,"hour"):Math.abs(c)<7?i.format(c,"day"):Math.abs(d)<4?i.format(d,"week"):Math.abs(h)<12?i.format(h,"month"):i.format(p,"year")}static isToday(t){const e=new Date;return this.isSameDay(t,e)}static isPast(t){return t<new Date}static isFuture(t){return t>new Date}static getWeekNumber(t){const e=new Date(t.getFullYear(),0,1),r=(t-e)/864e5;return Math.ceil((r+e.getDay()+1)/7)}static getDayAbbreviation(t,e="en-US"){const r=new Date(2024,0,7+t);return new Intl.DateTimeFormat(e,{weekday:"short"}).format(r)}static getMonthName(t,e="long",r="en-US"){const i=new Date(2024,t,1);return new Intl.DateTimeFormat(r,{month:e}).format(i)}static parseTimeString(t,e=new Date){const r=new Date(e),[i,s]=t.split(/\s+/),[n,a]=i.split(":").map(Number);let o=n;return s&&(s.toLowerCase()==="pm"&&n<12?o=n+12:s.toLowerCase()==="am"&&n===12&&(o=0)),r.setHours(o,a||0,0,0),r}}class x{static createElement(t,e={},r=[]){const i=document.createElement(t);return Object.entries(e).forEach(([s,n])=>{if(s==="className")i.className=n;else if(s==="style"&&typeof n=="object")Object.assign(i.style,n);else if(s.startsWith("data-"))i.setAttribute(s,n);else if(s.startsWith("on")&&typeof n=="function"){const a=s.slice(2).toLowerCase();i.addEventListener(a,n)}else i[s]=n}),r.forEach(s=>{typeof s=="string"?i.appendChild(document.createTextNode(s)):s instanceof Node&&i.appendChild(s)}),i}static addEventListeners(t,e){return Object.entries(e).forEach(([r,i])=>{t.addEventListener(r,i)}),()=>{Object.entries(e).forEach(([r,i])=>{t.removeEventListener(r,i)})}}static delegate(t,e,r,i){const s=n=>{const a=n.target.closest(e);a&&t.contains(a)&&i.call(a,n)};return t.addEventListener(r,s),()=>t.removeEventListener(r,s)}static getPosition(t){const e=t.getBoundingClientRect();return{top:e.top+window.scrollY,left:e.left+window.scrollX,bottom:e.bottom+window.scrollY,right:e.right+window.scrollX,width:e.width,height:e.height}}static isInViewport(t,e=0){const r=t.getBoundingClientRect();return r.top>=-e&&r.left>=-e&&r.bottom<=(window.innerHeight||document.documentElement.clientHeight)+e&&r.right<=(window.innerWidth||document.documentElement.clientWidth)+e}static scrollToElement(t,e={}){const{behavior:r="smooth",block:i="start",inline:s="nearest"}=e;t.scrollIntoView({behavior:r,block:i,inline:s})}static getStyle(t,e){return window.getComputedStyle(t).getPropertyValue(e)}static setStyles(t,e){Object.assign(t.style,e)}static async animateClass(t,e,r=300){t.classList.add(e),await this.wait(r),t.classList.remove(e)}static waitForAnimation(t,e="animationend"){return new Promise(r=>{const i=()=>{t.removeEventListener(e,i),r()};t.addEventListener(e,i)})}static wait(t){return new Promise(e=>setTimeout(e,t))}static parseHTML(t){const e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}static escapeHTML(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}static debounce(t,e=250){let r;return function(...s){const n=()=>{clearTimeout(r),t(...s)};clearTimeout(r),r=setTimeout(n,e)}}static throttle(t,e=250){let r;return function(...i){r||(t.apply(this,i),r=!0,setTimeout(()=>r=!1,e))}}static closest(t,e){return t.closest(e)}static parents(t,e){const r=[];let i=t.parentElement;for(;i;)i.matches(e)&&r.push(i),i=i.parentElement;return r}static getOuterDimensions(t){const e=window.getComputedStyle(t),r={top:parseInt(e.marginTop),right:parseInt(e.marginRight),bottom:parseInt(e.marginBottom),left:parseInt(e.marginLeft)};return{width:t.offsetWidth+r.left+r.right,height:t.offsetHeight+r.top+r.bottom,margin:r}}static cloneWithEvents(t,e=!0){return t.cloneNode(e)}static trapFocus(t){const e=t.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');if(e.length===0)return t.setAttribute("tabindex","-1"),t.focus(),()=>t.removeAttribute("tabindex");const r=e[0],i=e[e.length-1],s=n=>{n.key==="Tab"&&(n.shiftKey?document.activeElement===r&&(i==null||i.focus(),n.preventDefault()):document.activeElement===i&&(r==null||r.focus(),n.preventDefault()))};return t.addEventListener("keydown",s),r==null||r.focus(),()=>t.removeEventListener("keydown",s)}}class f{static getCSSVariable(t,e=document.documentElement){return getComputedStyle(e).getPropertyValue(t).trim()}static setCSSVariables(t,e=document.documentElement){Object.entries(t).forEach(([r,i])=>{e.style.setProperty(r,i)})}static getBaseStyles(){return`
|
|
16
16
|
:host {
|
|
17
17
|
/* Apply CSS variables */
|
|
18
|
-
${Object.entries(this.cssVariables).map(([e
|
|
18
|
+
${Object.entries(this.cssVariables).map(([t,e])=>`${t}: ${e};`).join(`
|
|
19
19
|
`)}
|
|
20
20
|
|
|
21
21
|
/* Base styles */
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
padding: 0;
|
|
150
150
|
border-radius: var(--fc-border-radius-full);
|
|
151
151
|
}
|
|
152
|
-
`}static darken(e
|
|
152
|
+
`}static darken(t,e){const r=parseInt(t.replace("#",""),16),i=Math.round(2.55*e),s=(r>>16)-i,n=(r>>8&255)-i,a=(r&255)-i;return"#"+(16777216+(s<255?s<1?0:s:255)*65536+(n<255?n<1?0:n:255)*256+(a<255?a<1?0:a:255)).toString(16).slice(1)}static lighten(t,e){const r=parseInt(t.replace("#",""),16),i=Math.round(2.55*e),s=(r>>16)+i,n=(r>>8&255)+i,a=(r&255)+i;return"#"+(16777216+(s<255?s<1?0:s:255)*65536+(n<255?n<1?0:n:255)*256+(a<255?a<1?0:a:255)).toString(16).slice(1)}static getContrastColor(t){const e=t.replace("#",""),r=parseInt(e.substr(0,2),16),i=parseInt(e.substr(2,2),16),s=parseInt(e.substr(4,2),16);return(r*299+i*587+s*114)/1e3>=128?"#000000":"#FFFFFF"}static sanitizeColor(t,e="var(--fc-primary-color)"){if(!t||typeof t!="string")return e;const r=t.trim();return/[;{}()<>\"\'\\]/.test(r)?e:/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(r)||/^var\(--[a-zA-Z0-9-]+\)$/.test(r)||/^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*(0|1|0?\.\d+))?\s*\)$/.test(r)||["transparent","currentColor","inherit","black","white","red","green","blue","yellow","orange","purple","pink","brown","gray","grey","cyan","magenta","lime","navy","teal","aqua","maroon","olive","silver","fuchsia"].includes(r.toLowerCase())?r:e}static hexToRgba(t,e=1){const r=t.replace("#",""),i=parseInt(r.substr(0,2),16),s=parseInt(r.substr(2,2),16),n=parseInt(r.substr(4,2),16);return`rgba(${i}, ${s}, ${n}, ${e})`}static getGridStyles(){return`
|
|
153
153
|
.fc-grid {
|
|
154
154
|
display: grid;
|
|
155
155
|
gap: 1px;
|
|
@@ -180,7 +180,7 @@
|
|
|
180
180
|
text-transform: uppercase;
|
|
181
181
|
letter-spacing: 0.5px;
|
|
182
182
|
}
|
|
183
|
-
`}static mediaQuery(e
|
|
183
|
+
`}static mediaQuery(t,e){const r=this.breakpoints[t];return r?`@media (min-width: ${r}) { ${e} }`:""}static getAnimations(){return`
|
|
184
184
|
@keyframes fc-fade-in {
|
|
185
185
|
from { opacity: 0; }
|
|
186
186
|
to { opacity: 1; }
|
|
@@ -235,9 +235,9 @@
|
|
|
235
235
|
.fc-scale-in {
|
|
236
236
|
animation: fc-scale-in var(--fc-transition);
|
|
237
237
|
}
|
|
238
|
-
`}}y(f,"colors",{primary:"#3B82F6",secondary:"#64748B",accent:"#F59E0B",danger:"#EF4444",warning:"#F97316",info:"#06B6D4",success:"#22C55E",light:"#F8FAFC",dark:"#0F172A",white:"#FFFFFF",gray:{50:"#F8FAFC",100:"#F1F5F9",200:"#E2E8F0",300:"#CBD5E1",400:"#94A3B8",500:"#64748B",600:"#475569",700:"#334155",800:"#1E293B",900:"#0F172A"}}),y(f,"cssVariables",{"--fc-primary-color":"#2563EB","--fc-primary-hover":"#1D4ED8","--fc-primary-light":"#EFF6FF","--fc-text-color":"#111827","--fc-text-secondary":"#6B7280","--fc-text-light":"#9CA3AF","--fc-border-color":"#E5E7EB","--fc-border-color-hover":"#D1D5DB","--fc-background":"#FFFFFF","--fc-background-alt":"#FAFAFA","--fc-background-hover":"#F3F4F6","--fc-background-active":"#E5E7EB","--fc-accent-color":"#F59E0B","--fc-danger-color":"#EF4444","--fc-success-color":"#10B981","--fc-font-family":'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',"--fc-font-size-xs":"11px","--fc-font-size-sm":"12px","--fc-font-size-base":"13px","--fc-font-size-lg":"15px","--fc-font-size-xl":"18px","--fc-font-size-2xl":"24px","--fc-line-height":"1.4","--fc-font-weight-normal":"400","--fc-font-weight-medium":"500","--fc-font-weight-semibold":"600","--fc-font-weight-bold":"700","--fc-spacing-xs":"2px","--fc-spacing-sm":"6px","--fc-spacing-md":"10px","--fc-spacing-lg":"14px","--fc-spacing-xl":"20px","--fc-spacing-2xl":"28px","--fc-border-width":"1px","--fc-border-radius-sm":"3px","--fc-border-radius":"5px","--fc-border-radius-lg":"8px","--fc-border-radius-full":"9999px","--fc-shadow-sm":"0 1px 1px rgba(0,0,0,0.05)","--fc-shadow":"0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06)","--fc-shadow-md":"0 4px 6px -1px rgba(0, 0, 0, 0.1)","--fc-shadow-lg":"0 10px 15px -3px rgba(0, 0, 0, 0.1)","--fc-transition-fast":"100ms ease-out","--fc-transition":"150ms ease-out","--fc-transition-slow":"250ms ease-out","--fc-z-dropdown":"1000","--fc-z-modal":"2000","--fc-z-tooltip":"3000"}),y(f,"breakpoints",{xs:"320px",sm:"576px",md:"768px",lg:"992px",xl:"1200px","2xl":"1400px"});class
|
|
239
|
-
<div class="fc-event fc-timed-event" data-event-id="${this.escapeHTML(
|
|
240
|
-
style="position: absolute; top: ${
|
|
238
|
+
`}}y(f,"colors",{primary:"#3B82F6",secondary:"#64748B",accent:"#F59E0B",danger:"#EF4444",warning:"#F97316",info:"#06B6D4",success:"#22C55E",light:"#F8FAFC",dark:"#0F172A",white:"#FFFFFF",gray:{50:"#F8FAFC",100:"#F1F5F9",200:"#E2E8F0",300:"#CBD5E1",400:"#94A3B8",500:"#64748B",600:"#475569",700:"#334155",800:"#1E293B",900:"#0F172A"}}),y(f,"cssVariables",{"--fc-primary-color":"#2563EB","--fc-primary-hover":"#1D4ED8","--fc-primary-light":"#EFF6FF","--fc-text-color":"#111827","--fc-text-secondary":"#6B7280","--fc-text-light":"#9CA3AF","--fc-border-color":"#E5E7EB","--fc-border-color-hover":"#D1D5DB","--fc-background":"#FFFFFF","--fc-background-alt":"#FAFAFA","--fc-background-hover":"#F3F4F6","--fc-background-active":"#E5E7EB","--fc-accent-color":"#F59E0B","--fc-danger-color":"#EF4444","--fc-success-color":"#10B981","--fc-font-family":'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',"--fc-font-size-xs":"11px","--fc-font-size-sm":"12px","--fc-font-size-base":"13px","--fc-font-size-lg":"15px","--fc-font-size-xl":"18px","--fc-font-size-2xl":"24px","--fc-line-height":"1.4","--fc-font-weight-normal":"400","--fc-font-weight-medium":"500","--fc-font-weight-semibold":"600","--fc-font-weight-bold":"700","--fc-spacing-xs":"2px","--fc-spacing-sm":"6px","--fc-spacing-md":"10px","--fc-spacing-lg":"14px","--fc-spacing-xl":"20px","--fc-spacing-2xl":"28px","--fc-border-width":"1px","--fc-border-radius-sm":"3px","--fc-border-radius":"5px","--fc-border-radius-lg":"8px","--fc-border-radius-full":"9999px","--fc-shadow-sm":"0 1px 1px rgba(0,0,0,0.05)","--fc-shadow":"0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06)","--fc-shadow-md":"0 4px 6px -1px rgba(0, 0, 0, 0.1)","--fc-shadow-lg":"0 10px 15px -3px rgba(0, 0, 0, 0.1)","--fc-transition-fast":"100ms ease-out","--fc-transition":"150ms ease-out","--fc-transition-slow":"250ms ease-out","--fc-z-dropdown":"1000","--fc-z-modal":"2000","--fc-z-tooltip":"3000"}),y(f,"breakpoints",{xs:"320px",sm:"576px",md:"768px",lg:"992px",xl:"1200px","2xl":"1400px"});class w{constructor(t,e){this.container=t,this.stateManager=e,this._listeners=[],this._scrolled=!1}render(){throw new Error("render() must be implemented by subclass")}cleanup(){this._listeners.forEach(({element:t,event:e,handler:r})=>{t.removeEventListener(e,r)}),this._listeners=[]}addListener(t,e,r){const i=r.bind(this);t.addEventListener(e,i),this._listeners.push({element:t,event:e,handler:i})}escapeHTML(t){return t==null?"":x.escapeHTML(String(t))}isToday(t){const e=new Date;return t.getDate()===e.getDate()&&t.getMonth()===e.getMonth()&&t.getFullYear()===e.getFullYear()}isSameDay(t,e){return t.getDate()===e.getDate()&&t.getMonth()===e.getMonth()&&t.getFullYear()===e.getFullYear()}formatHour(t){const e=t>=12?"PM":"AM";return`${t%12||12} ${e}`}formatTime(t){const e=t.getHours(),r=t.getMinutes(),i=e>=12?"PM":"AM",s=e%12||12;return r===0?`${s} ${i}`:`${s}:${r.toString().padStart(2,"0")} ${i}`}getContrastingTextColor(t){return!t||typeof t!="string"||t.charAt(0)!=="#"?"white":f.getContrastColor(t)}renderNowIndicator(){const t=new Date;return`<div class="fc-now-indicator" style="position: absolute; left: 0; right: 0; top: ${t.getHours()*60+t.getMinutes()}px; height: 2px; background: var(--fc-danger-color); z-index: 15; pointer-events: none;"></div>`}computeOverlapLayout(t){if(!t||t.length===0)return new Map;const e=t.map(o=>{const c=new Date(o.start),d=new Date(o.end),h=c.getHours()*60+c.getMinutes(),p=Math.max(h+1,d.getHours()*60+d.getMinutes());return{id:o.id,startMin:h,endMin:p}});e.sort((o,c)=>o.startMin-c.startMin||c.endMin-c.startMin-(o.endMin-o.startMin));const r=[],i=new Map;for(const o of e){let c=!1;for(let d=0;d<r.length;d++)if(r[d]<=o.startMin){r[d]=o.endMin,i.set(o.id,{column:d,totalColumns:0}),c=!0;break}c||(i.set(o.id,{column:r.length,totalColumns:0}),r.push(o.endMin))}const s=[];let n=[],a=0;for(const o of e)n.length===0||o.startMin<a?(n.push(o),a=Math.max(a,o.endMin)):(s.push(n),n=[o],a=o.endMin);n.length>0&&s.push(n);for(const o of s){const c=Math.max(...o.map(d=>i.get(d.id).column))+1;for(const d of o)i.get(d.id).totalColumns=c}return i}renderTimedEvent(t,e={}){const{compact:r=!0,overlapLayout:i=null}=e,s=new Date(t.start),n=new Date(t.end),a=s.getHours()*60+s.getMinutes(),o=Math.max((n-s)/(1e3*60),r?20:30),c=this.getEventColor(t),d=r?"4px 8px":"8px 12px",h=r?"11px":"13px",p=r?2:12,_=r?2:24,$=r?"4px":"6px";let M,T;if(i&&i.has(t.id)){const{column:z,totalColumns:H}=i.get(t.id),L=`(100% - ${p+_}px)`;M=`calc(${p}px + ${z} * ${L} / ${H})`,T=`calc(${L} / ${H})`}else M=`${p}px`,T=`calc(100% - ${p+_}px)`;return`
|
|
239
|
+
<div class="fc-event fc-timed-event" data-event-id="${this.escapeHTML(t.id)}"
|
|
240
|
+
style="position: absolute; top: ${a}px; height: ${o}px;
|
|
241
241
|
left: ${M}; width: ${T};
|
|
242
242
|
background-color: ${c}; border-radius: ${$};
|
|
243
243
|
padding: ${d}; font-size: ${h};
|
|
@@ -245,62 +245,62 @@
|
|
|
245
245
|
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
|
|
246
246
|
cursor: pointer; z-index: 5;">
|
|
247
247
|
<div style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
|
|
248
|
-
${this.escapeHTML(
|
|
248
|
+
${this.escapeHTML(t.title)}
|
|
249
249
|
</div>
|
|
250
250
|
<div style="font-size: ${r?"10px":"11px"}; opacity: 0.9;">
|
|
251
251
|
${this.formatTime(s)}${r?"":" - "+this.formatTime(n)}
|
|
252
252
|
</div>
|
|
253
253
|
</div>
|
|
254
|
-
`}getEventColor(
|
|
255
|
-
<div class="fc-month-view" style="display: flex; flex-direction: column; height: 100%; min-height: 400px; background:
|
|
256
|
-
<div class="fc-month-header" style="display: grid; grid-template-columns: repeat(7, 1fr); border-bottom: 1px solid
|
|
257
|
-
${this._getDayNames(r).map(n=>`<div class="fc-month-header-cell" style="padding: 12px 8px; text-align: center; font-size: 11px; font-weight: 600; color:
|
|
254
|
+
`}getEventColor(t){return f.sanitizeColor(t==null?void 0:t.backgroundColor,"#2563eb")}attachCommonEventHandlers(){this.addListener(this.container,"click",t=>{const e=t.target.closest(".fc-event");if(!e||!this.container.contains(e))return;t.stopPropagation();const r=e.dataset.eventId,i=this.stateManager.getEvents().find(s=>s.id===r);i&&this.stateManager.selectEvent(i)})}}class k extends w{constructor(t,e){super(t,e),this.maxEventsToShow=3}render(){if(!this.container||!this.stateManager)return;const t=this.stateManager.getViewData();if(!t||!t.weeks){this.container.innerHTML='<div style="padding: 20px; text-align: center; color: var(--fc-text-secondary);">No data available for month view.</div>';return}this.cleanup();const e=this.stateManager.getState().config,r=this._renderMonthView(t,e);this.container.innerHTML=r,this._attachEventHandlers()}_renderMonthView(t,e){const r=e.weekStartsOn||0;let s=`
|
|
255
|
+
<div class="fc-month-view" style="display: flex; flex-direction: column; height: 100%; min-height: 400px; background: var(--fc-background); border: 1px solid var(--fc-border-color);">
|
|
256
|
+
<div class="fc-month-header" style="display: grid; grid-template-columns: repeat(7, 1fr); border-bottom: 1px solid var(--fc-border-color); background: var(--fc-background-alt);">
|
|
257
|
+
${this._getDayNames(r).map(n=>`<div class="fc-month-header-cell" style="padding: 12px 8px; text-align: center; font-size: 11px; font-weight: 600; color: var(--fc-text-light); text-transform: uppercase;">${n}</div>`).join("")}
|
|
258
258
|
</div>
|
|
259
259
|
<div class="fc-month-body" style="display: flex; flex-direction: column; flex: 1;">
|
|
260
|
-
`;return
|
|
261
|
-
<div class="fc-month-day" data-date="${
|
|
262
|
-
style="background: ${i}; border-right: 1px solid
|
|
260
|
+
`;return t.weeks.forEach(n=>{s+=this._renderWeek(n)}),s+="</div></div>",s}_getDayNames(t){const e=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],r=[];for(let i=0;i<7;i++){const s=(t+i)%7;r.push(e[s])}return r}_renderWeek(t){let e='<div class="fc-month-week" style="display: grid; grid-template-columns: repeat(7, 1fr); flex: 1; min-height: 80px;">';return t.days.forEach(r=>{e+=this._renderDay(r)}),e+="</div>",e}_renderDay(t){const e=!t.isCurrentMonth,r=t.isToday,i=e?"var(--fc-background-hover)":"var(--fc-background)",s=e?"var(--fc-text-light)":"var(--fc-text-color)",n=r?"background: var(--fc-primary-color); color: white; border-radius: 50%; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;":"",a=t.events||[],o=a.slice(0,this.maxEventsToShow),c=a.length-this.maxEventsToShow;return`
|
|
261
|
+
<div class="fc-month-day" data-date="${t.date}"
|
|
262
|
+
style="background: ${i}; border-right: 1px solid var(--fc-border-color); border-bottom: 1px solid var(--fc-border-color); padding: 4px; min-height: 80px; cursor: pointer; display: flex; flex-direction: column;">
|
|
263
263
|
<div class="fc-day-number" style="font-size: 13px; font-weight: 500; color: ${s}; padding: 2px 4px; margin-bottom: 4px; ${n}">
|
|
264
|
-
${
|
|
264
|
+
${t.dayOfMonth}
|
|
265
265
|
</div>
|
|
266
266
|
<div class="fc-day-events" style="display: flex; flex-direction: column; gap: 2px; flex: 1; overflow: hidden;">
|
|
267
|
-
${
|
|
268
|
-
${c>0?`<div class="fc-more-events" style="font-size: 10px; color:
|
|
267
|
+
${o.map(d=>this._renderEvent(d)).join("")}
|
|
268
|
+
${c>0?`<div class="fc-more-events" style="font-size: 10px; color: var(--fc-text-light); padding: 2px 4px; font-weight: 500;">+${c} more</div>`:""}
|
|
269
269
|
</div>
|
|
270
270
|
</div>
|
|
271
|
-
`}_renderEvent(
|
|
272
|
-
<div class="fc-event" data-event-id="${this.escapeHTML(
|
|
273
|
-
style="background-color: ${
|
|
274
|
-
${this.escapeHTML(
|
|
271
|
+
`}_renderEvent(t){const e=this.getEventColor(t);return`
|
|
272
|
+
<div class="fc-event" data-event-id="${this.escapeHTML(t.id)}"
|
|
273
|
+
style="background-color: ${e}; font-size: 11px; padding: 2px 6px; border-radius: 3px; color: white; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer;">
|
|
274
|
+
${this.escapeHTML(t.title)}
|
|
275
275
|
</div>
|
|
276
|
-
`}_attachEventHandlers(){this.addListener(this.container,"click",
|
|
277
|
-
<div class="fc-week-view" style="display: flex; flex-direction: column; height: 100%; background:
|
|
276
|
+
`}_attachEventHandlers(){this.addListener(this.container,"click",t=>{const e=t.target.closest(".fc-month-day");if(!e||!this.container.contains(e)||t.target.closest(".fc-event"))return;const r=new Date(e.dataset.date);this.stateManager.selectDate(r)}),this.attachCommonEventHandlers()}}class C extends w{constructor(t,e){super(t,e),this.hourHeight=60,this.totalHeight=24*this.hourHeight}render(){if(!this.container||!this.stateManager)return;const t=this.stateManager.getViewData();if(!t||!t.days||t.days.length===0){this.container.innerHTML='<div style="padding: 20px; text-align: center; color: var(--fc-text-secondary);">No data available for week view.</div>';return}this.cleanup(),this._scrolled=!1;const e=this.stateManager.getState().config,r=this._renderWeekView(t,e);this.container.innerHTML=r,this._attachEventHandlers(),this._scrollToCurrentTime()}_renderWeekView(t,e){const r=t.days,i=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],s=Array.from({length:24},(a,o)=>o),n=r.map(a=>{const o=new Date(a.date),c=a.events||[];return{...a,date:o,dayName:i[o.getDay()],dayOfMonth:o.getDate(),isToday:this.isToday(o),timedEvents:c.filter(d=>!d.allDay),allDayEvents:c.filter(d=>d.allDay)}});return`
|
|
277
|
+
<div class="fc-week-view" style="display: flex; flex-direction: column; height: 100%; background: var(--fc-background); overflow: hidden;">
|
|
278
278
|
${this._renderHeader(n)}
|
|
279
279
|
${this._renderAllDayRow(n)}
|
|
280
280
|
${this._renderTimeGrid(n,s)}
|
|
281
281
|
</div>
|
|
282
|
-
`}_renderHeader(
|
|
283
|
-
<div class="fc-week-header" style="display: grid; grid-template-columns: 60px repeat(7, 1fr); border-bottom: 1px solid
|
|
284
|
-
<div style="border-right: 1px solid
|
|
285
|
-
${
|
|
286
|
-
<div style="padding: 12px 8px; text-align: center; border-right: 1px solid
|
|
287
|
-
<div style="font-size: 10px; font-weight: 700; color:
|
|
288
|
-
${
|
|
282
|
+
`}_renderHeader(t){return`
|
|
283
|
+
<div class="fc-week-header" style="display: grid; grid-template-columns: 60px repeat(7, 1fr); border-bottom: 1px solid var(--fc-border-color); background: var(--fc-background-alt); flex-shrink: 0;">
|
|
284
|
+
<div style="border-right: 1px solid var(--fc-border-color);"></div>
|
|
285
|
+
${t.map(e=>`
|
|
286
|
+
<div style="padding: 12px 8px; text-align: center; border-right: 1px solid var(--fc-border-color);">
|
|
287
|
+
<div style="font-size: 10px; font-weight: 700; color: var(--fc-text-light); text-transform: uppercase; letter-spacing: 0.1em;">
|
|
288
|
+
${e.dayName}
|
|
289
289
|
</div>
|
|
290
|
-
<div style="font-size: 16px; font-weight: 500; margin-top: 4px; ${
|
|
291
|
-
${
|
|
290
|
+
<div style="font-size: 16px; font-weight: 500; margin-top: 4px; ${e.isToday?"background: var(--fc-danger-color); color: white; border-radius: 50%; width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;":"color: var(--fc-text-color);"}">
|
|
291
|
+
${e.dayOfMonth}
|
|
292
292
|
</div>
|
|
293
293
|
</div>
|
|
294
294
|
`).join("")}
|
|
295
295
|
</div>
|
|
296
|
-
`}_renderAllDayRow(
|
|
297
|
-
<div class="fc-all-day-row" style="display: grid; grid-template-columns: 60px repeat(7, 1fr); border-bottom: 1px solid
|
|
298
|
-
<div style="font-size: 9px; color:
|
|
296
|
+
`}_renderAllDayRow(t){return`
|
|
297
|
+
<div class="fc-all-day-row" style="display: grid; grid-template-columns: 60px repeat(7, 1fr); border-bottom: 1px solid var(--fc-border-color); background: var(--fc-background-alt); min-height: 32px; flex-shrink: 0;">
|
|
298
|
+
<div style="font-size: 9px; color: var(--fc-text-light); display: flex; align-items: center; justify-content: center; border-right: 1px solid var(--fc-border-color); text-transform: uppercase; font-weight: 700;">
|
|
299
299
|
All day
|
|
300
300
|
</div>
|
|
301
|
-
${
|
|
302
|
-
<div class="fc-all-day-cell" data-date="${
|
|
303
|
-
${
|
|
301
|
+
${t.map(e=>`
|
|
302
|
+
<div class="fc-all-day-cell" data-date="${e.date.toISOString()}" style="border-right: 1px solid var(--fc-border-color); padding: 4px; display: flex; flex-direction: column; gap: 2px;">
|
|
303
|
+
${e.allDayEvents.map(r=>`
|
|
304
304
|
<div class="fc-event fc-all-day-event" data-event-id="${this.escapeHTML(r.id)}"
|
|
305
305
|
style="background-color: ${this.getEventColor(r)}; font-size: 10px; padding: 2px 4px; border-radius: 2px; color: white; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
|
|
306
306
|
${this.escapeHTML(r.title)}
|
|
@@ -309,57 +309,57 @@
|
|
|
309
309
|
</div>
|
|
310
310
|
`).join("")}
|
|
311
311
|
</div>
|
|
312
|
-
`}_renderTimeGrid(e
|
|
312
|
+
`}_renderTimeGrid(t,e){return`
|
|
313
313
|
<div id="week-scroll-container" class="fc-time-grid-container" style="flex: 1; overflow-y: auto; overflow-x: hidden; position: relative;">
|
|
314
314
|
<div class="fc-time-grid" style="display: grid; grid-template-columns: 60px repeat(7, 1fr); position: relative; height: ${this.totalHeight}px;">
|
|
315
|
-
${this._renderTimeGutter(
|
|
316
|
-
${
|
|
315
|
+
${this._renderTimeGutter(e)}
|
|
316
|
+
${t.map(r=>this._renderDayColumn(r,e)).join("")}
|
|
317
317
|
</div>
|
|
318
318
|
</div>
|
|
319
|
-
`}_renderTimeGutter(
|
|
320
|
-
<div class="fc-time-gutter" style="border-right: 1px solid
|
|
321
|
-
${
|
|
322
|
-
<div style="height: ${this.hourHeight}px; font-size: 10px; color:
|
|
323
|
-
${
|
|
319
|
+
`}_renderTimeGutter(t){return`
|
|
320
|
+
<div class="fc-time-gutter" style="border-right: 1px solid var(--fc-border-color); background: var(--fc-background-alt);">
|
|
321
|
+
${t.map(e=>`
|
|
322
|
+
<div style="height: ${this.hourHeight}px; font-size: 10px; color: var(--fc-text-light); text-align: right; padding-right: 8px; font-weight: 500;">
|
|
323
|
+
${e===0?"":this.formatHour(e)}
|
|
324
324
|
</div>
|
|
325
325
|
`).join("")}
|
|
326
326
|
</div>
|
|
327
|
-
`}_renderDayColumn(e
|
|
328
|
-
<div class="fc-week-day-column" data-date="${
|
|
327
|
+
`}_renderDayColumn(t,e){return`
|
|
328
|
+
<div class="fc-week-day-column" data-date="${t.date.toISOString()}" style="border-right: 1px solid var(--fc-border-color); position: relative; cursor: pointer;">
|
|
329
329
|
<!-- Hour grid lines -->
|
|
330
|
-
${
|
|
330
|
+
${e.map(()=>`<div style="height: ${this.hourHeight}px; border-bottom: 1px solid var(--fc-background-hover);"></div>`).join("")}
|
|
331
331
|
|
|
332
332
|
<!-- Now indicator for today -->
|
|
333
|
-
${
|
|
333
|
+
${t.isToday?this.renderNowIndicator():""}
|
|
334
334
|
|
|
335
335
|
<!-- Timed events -->
|
|
336
|
-
${(()=>{const r=this.computeOverlapLayout(
|
|
336
|
+
${(()=>{const r=this.computeOverlapLayout(t.timedEvents);return t.timedEvents.map(i=>this.renderTimedEvent(i,{compact:!0,overlapLayout:r})).join("")})()}
|
|
337
337
|
</div>
|
|
338
|
-
`}_attachEventHandlers(){this.addListener(this.container,"click",
|
|
339
|
-
<div class="fc-day-view" style="display: flex; flex-direction: column; height: 100%; background:
|
|
340
|
-
${this._renderHeader(s,n,
|
|
341
|
-
${this._renderAllDayRow(
|
|
342
|
-
${this._renderTimeGrid(c,
|
|
338
|
+
`}_attachEventHandlers(){this.addListener(this.container,"click",t=>{const e=t.target.closest(".fc-week-day-column");if(!e||!this.container.contains(e)||t.target.closest(".fc-event"))return;const r=new Date(e.dataset.date),i=this.container.querySelector("#week-scroll-container"),s=e.offsetTop,n=t.clientY-e.getBoundingClientRect().top+(i?i.scrollTop:0)-s,a=Math.max(0,Math.min(n+s,this.totalHeight));r.setHours(Math.floor(a/this.hourHeight),Math.floor(a%this.hourHeight/(this.hourHeight/60)),0,0),this.stateManager.selectDate(r)}),this.attachCommonEventHandlers()}_scrollToCurrentTime(){if(this._scrolled)return;const t=this.container.querySelector("#week-scroll-container");t&&(t.scrollTop=8*this.hourHeight-50,this._scrolled=!0)}}class F extends w{constructor(t,e){super(t,e),this.hourHeight=60,this.totalHeight=24*this.hourHeight}render(){if(!this.container||!this.stateManager)return;const t=this.stateManager.getViewData();if(!t){this.container.innerHTML='<div style="padding: 20px; text-align: center; color: var(--fc-text-secondary);">No data available for day view.</div>';return}this.cleanup(),this._scrolled=!1;const e=this.stateManager.getState().config,r=this._renderDayView(t,e);this.container.innerHTML=r,this._attachEventHandlers(),this._scrollToCurrentTime()}_renderDayView(t,e){var h,p;const r=((p=(h=this.stateManager)==null?void 0:h.getState())==null?void 0:p.currentDate)||new Date,i=this._extractDayData(t,r);if(!i)return'<div style="padding: 20px; text-align: center; color: var(--fc-text-secondary);">No data available for day view.</div>';const{dayDate:s,dayName:n,isToday:a,allDayEvents:o,timedEvents:c}=i,d=Array.from({length:24},(_,$)=>$);return`
|
|
339
|
+
<div class="fc-day-view" style="display: flex; flex-direction: column; height: 100%; background: var(--fc-background); overflow: hidden;">
|
|
340
|
+
${this._renderHeader(s,n,a)}
|
|
341
|
+
${this._renderAllDayRow(o,s)}
|
|
342
|
+
${this._renderTimeGrid(c,a,s,d)}
|
|
343
343
|
</div>
|
|
344
|
-
`}_extractDayData(e
|
|
345
|
-
<div class="fc-day-header" style="display: grid; grid-template-columns: 60px 1fr; border-bottom: 1px solid
|
|
346
|
-
<div style="border-right: 1px solid
|
|
344
|
+
`}_extractDayData(t,e){let r,i,s,n,a;const o=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];if(t.type==="day"&&t.date)if(r=new Date(t.date),i=t.dayName||o[r.getDay()],s=t.isToday!==void 0?t.isToday:this.isToday(r),n=t.allDayEvents||[],t.hours&&Array.isArray(t.hours)){const c=new Map;t.hours.forEach(d=>{(d.events||[]).forEach(h=>{c.has(h.id)||c.set(h.id,h)})}),a=Array.from(c.values())}else a=[];else if(t.days&&t.days.length>0){const c=t.days.find(h=>this.isSameDay(new Date(h.date),e))||t.days[0];r=new Date(c.date),i=o[r.getDay()],s=this.isToday(r);const d=c.events||[];n=d.filter(h=>h.allDay),a=d.filter(h=>!h.allDay)}else return null;return{dayDate:r,dayName:i,isToday:s,allDayEvents:n,timedEvents:a}}_renderHeader(t,e,r){return`
|
|
345
|
+
<div class="fc-day-header" style="display: grid; grid-template-columns: 60px 1fr; border-bottom: 1px solid var(--fc-border-color); background: var(--fc-background-alt); flex-shrink: 0;">
|
|
346
|
+
<div style="border-right: 1px solid var(--fc-border-color);"></div>
|
|
347
347
|
<div style="padding: 16px 24px;">
|
|
348
|
-
<div style="font-size: 12px; font-weight: 700; color:
|
|
349
|
-
${
|
|
348
|
+
<div style="font-size: 12px; font-weight: 700; color: var(--fc-text-light); text-transform: uppercase; letter-spacing: 0.1em;">
|
|
349
|
+
${e}
|
|
350
350
|
</div>
|
|
351
|
-
<div style="font-size: 24px; font-weight: 600; margin-top: 4px; ${r?"color:
|
|
352
|
-
${
|
|
351
|
+
<div style="font-size: 24px; font-weight: 600; margin-top: 4px; ${r?"color: var(--fc-danger-color);":"color: var(--fc-text-color);"}">
|
|
352
|
+
${t.getDate()}
|
|
353
353
|
</div>
|
|
354
354
|
</div>
|
|
355
355
|
</div>
|
|
356
|
-
`}_renderAllDayRow(e
|
|
357
|
-
<div class="fc-all-day-row" style="display: grid; grid-template-columns: 60px 1fr; border-bottom: 1px solid
|
|
358
|
-
<div style="font-size: 9px; color:
|
|
356
|
+
`}_renderAllDayRow(t,e){return`
|
|
357
|
+
<div class="fc-all-day-row" style="display: grid; grid-template-columns: 60px 1fr; border-bottom: 1px solid var(--fc-border-color); background: var(--fc-background-alt); min-height: 36px; flex-shrink: 0;">
|
|
358
|
+
<div style="font-size: 9px; color: var(--fc-text-light); display: flex; align-items: center; justify-content: center; border-right: 1px solid var(--fc-border-color); text-transform: uppercase; font-weight: 700;">
|
|
359
359
|
All day
|
|
360
360
|
</div>
|
|
361
|
-
<div class="fc-all-day-cell" data-date="${
|
|
362
|
-
${
|
|
361
|
+
<div class="fc-all-day-cell" data-date="${e.toISOString()}" style="padding: 6px 12px; display: flex; flex-wrap: wrap; gap: 4px;">
|
|
362
|
+
${t.map(r=>`
|
|
363
363
|
<div class="fc-event fc-all-day-event" data-event-id="${this.escapeHTML(r.id)}"
|
|
364
364
|
style="background-color: ${this.getEventColor(r)}; font-size: 12px; padding: 4px 8px; border-radius: 4px; color: white; cursor: pointer; font-weight: 500;">
|
|
365
365
|
${this.escapeHTML(r.title)}
|
|
@@ -367,33 +367,33 @@
|
|
|
367
367
|
`).join("")}
|
|
368
368
|
</div>
|
|
369
369
|
</div>
|
|
370
|
-
`}_renderTimeGrid(e,
|
|
370
|
+
`}_renderTimeGrid(t,e,r,i){return`
|
|
371
371
|
<div id="day-scroll-container" class="fc-time-grid-container" style="flex: 1; overflow-y: auto; overflow-x: hidden; position: relative;">
|
|
372
372
|
<div class="fc-time-grid" style="display: grid; grid-template-columns: 60px 1fr; position: relative; height: ${this.totalHeight}px;">
|
|
373
373
|
${this._renderTimeGutter(i)}
|
|
374
|
-
${this._renderDayColumn(e,
|
|
374
|
+
${this._renderDayColumn(t,e,r,i)}
|
|
375
375
|
</div>
|
|
376
376
|
</div>
|
|
377
|
-
`}_renderTimeGutter(
|
|
378
|
-
<div class="fc-time-gutter" style="border-right: 1px solid
|
|
379
|
-
${
|
|
380
|
-
<div style="height: ${this.hourHeight}px; font-size: 11px; color:
|
|
381
|
-
${
|
|
377
|
+
`}_renderTimeGutter(t){return`
|
|
378
|
+
<div class="fc-time-gutter" style="border-right: 1px solid var(--fc-border-color); background: var(--fc-background-alt);">
|
|
379
|
+
${t.map(e=>`
|
|
380
|
+
<div style="height: ${this.hourHeight}px; font-size: 11px; color: var(--fc-text-light); text-align: right; padding-right: 12px; font-weight: 500;">
|
|
381
|
+
${e===0?"":this.formatHour(e)}
|
|
382
382
|
</div>
|
|
383
383
|
`).join("")}
|
|
384
384
|
</div>
|
|
385
|
-
`}_renderDayColumn(e,
|
|
385
|
+
`}_renderDayColumn(t,e,r,i){return`
|
|
386
386
|
<div class="fc-day-column" data-date="${r.toISOString()}" style="position: relative; cursor: pointer;">
|
|
387
387
|
<!-- Hour grid lines -->
|
|
388
|
-
${i.map(()=>`<div style="height: ${this.hourHeight}px; border-bottom: 1px solid
|
|
388
|
+
${i.map(()=>`<div style="height: ${this.hourHeight}px; border-bottom: 1px solid var(--fc-background-hover);"></div>`).join("")}
|
|
389
389
|
|
|
390
390
|
<!-- Now indicator for today -->
|
|
391
|
-
${
|
|
391
|
+
${e?this.renderNowIndicator():""}
|
|
392
392
|
|
|
393
393
|
<!-- Timed events -->
|
|
394
|
-
${(()=>{const s=this.computeOverlapLayout(
|
|
394
|
+
${(()=>{const s=this.computeOverlapLayout(t);return t.map(n=>this.renderTimedEvent(n,{compact:!1,overlapLayout:s})).join("")})()}
|
|
395
395
|
</div>
|
|
396
|
-
`}_attachEventHandlers(){this.addListener(this.container,"click",
|
|
396
|
+
`}_attachEventHandlers(){this.addListener(this.container,"click",t=>{const e=t.target.closest(".fc-day-column");if(!e||!this.container.contains(e)||t.target.closest(".fc-event"))return;const r=new Date(e.dataset.date),i=this.container.querySelector("#day-scroll-container"),s=e.offsetTop,n=t.clientY-e.getBoundingClientRect().top+(i?i.scrollTop:0)-s,a=Math.max(0,Math.min(n+s,this.totalHeight));r.setHours(Math.floor(a/this.hourHeight),Math.floor(a%this.hourHeight/(this.hourHeight/60)),0,0),this.stateManager.selectDate(r)}),this.attachCommonEventHandlers()}_scrollToCurrentTime(){if(this._scrolled)return;const t=this.container.querySelector("#day-scroll-container");t&&(t.scrollTop=8*this.hourHeight-50,this._scrolled=!0)}}class I extends v{constructor(){super(),this._isVisible=!1,this._cleanupFocusTrap=null,this.config={title:"New Event",defaultDuration:60,colors:[{color:"#2563EB",label:"Blue"},{color:"#10B981",label:"Green"},{color:"#F59E0B",label:"Amber"},{color:"#EF4444",label:"Red"},{color:"#8B5CF6",label:"Purple"},{color:"#6B7280",label:"Gray"}]},this._formData={title:"",start:new Date,end:new Date,allDay:!1,color:this.config.colors[0].color}}static get observedAttributes(){return["open"]}attributeChangedCallback(t,e,r){t==="open"&&(r!==null?this.open():this.close())}getStyles(){return`
|
|
397
397
|
${f.getBaseStyles()}
|
|
398
398
|
${f.getButtonStyles()}
|
|
399
399
|
|
|
@@ -596,14 +596,14 @@
|
|
|
596
596
|
<div class="form-group">
|
|
597
597
|
<label id="color-label">Color</label>
|
|
598
598
|
<div class="color-options" id="color-picker" role="radiogroup" aria-labelledby="color-label">
|
|
599
|
-
${this.config.colors.map(
|
|
599
|
+
${this.config.colors.map(t=>`
|
|
600
600
|
<button type="button"
|
|
601
|
-
class="color-btn ${
|
|
602
|
-
style="background-color: ${
|
|
603
|
-
data-color="${
|
|
604
|
-
title="${
|
|
605
|
-
aria-label="${
|
|
606
|
-
aria-checked="${
|
|
601
|
+
class="color-btn ${t.color===this._formData.color?"selected":""}"
|
|
602
|
+
style="background-color: ${t.color}"
|
|
603
|
+
data-color="${t.color}"
|
|
604
|
+
title="${t.label}"
|
|
605
|
+
aria-label="${t.label}"
|
|
606
|
+
aria-checked="${t.color===this._formData.color?"true":"false"}"
|
|
607
607
|
role="radio"></button>
|
|
608
608
|
`).join("")}
|
|
609
609
|
</div>
|
|
@@ -615,14 +615,14 @@
|
|
|
615
615
|
<button class="fc-btn fc-btn-primary" id="save-btn">Save Event</button>
|
|
616
616
|
</footer>
|
|
617
617
|
</div>
|
|
618
|
-
`}afterRender(){this.modalContent=this.$(".modal-content"),this.titleInput=this.$("#event-title"),this.startInput=this.$("#event-start"),this.endInput=this.$("#event-end"),this.colorContainer=this.$("#color-picker"),this.titleGroup=this.$("#title-group"),this.endGroup=this.$("#end-group"),this.addListener(this.$("#close-x"),"click",()=>this.close()),this.addListener(this.$("#cancel-btn"),"click",()=>this.close()),this.addListener(this.$("#save-btn"),"click",()=>this.save()),this.colorContainer.querySelectorAll(".color-btn").forEach(
|
|
618
|
+
`}afterRender(){this.modalContent=this.$(".modal-content"),this.titleInput=this.$("#event-title"),this.startInput=this.$("#event-start"),this.endInput=this.$("#event-end"),this.colorContainer=this.$("#color-picker"),this.titleGroup=this.$("#title-group"),this.endGroup=this.$("#end-group"),this.addListener(this.$("#close-x"),"click",()=>this.close()),this.addListener(this.$("#cancel-btn"),"click",()=>this.close()),this.addListener(this.$("#save-btn"),"click",()=>this.save()),this.colorContainer.querySelectorAll(".color-btn").forEach(t=>{this.addListener(t,"click",e=>{this._formData.color=e.currentTarget.dataset.color,this.updateColorSelection()})}),this.addListener(this,"click",t=>{t.target===this&&this.close()}),this._keydownListenerAdded||(this._handleKeyDown=t=>{t.key==="Escape"&&this.hasAttribute("open")&&this.close()},window.addEventListener("keydown",this._handleKeyDown),this._keydownListenerAdded=!0)}updateColorSelection(){this.colorContainer.querySelectorAll(".color-btn").forEach(e=>{const r=e.dataset.color===this._formData.color;e.classList.toggle("selected",r),e.setAttribute("aria-checked",r?"true":"false")})}open(t=new Date){this.hasAttribute("open")||this.setAttribute("open",""),this.titleGroup.classList.remove("has-error"),this.endGroup.classList.remove("has-error"),this._formData.start=t,this._formData.end=new Date(t.getTime()+this.config.defaultDuration*60*1e3),this._formData.title="",this._formData.color=this.config.colors[0].color,this.startInput&&(this.titleInput.value="",this.startInput.value=this.formatDateForInput(this._formData.start),this.endInput.value=this.formatDateForInput(this._formData.end),this.updateColorSelection(),this._cleanupFocusTrap&&this._cleanupFocusTrap(),this._cleanupFocusTrap=x.trapFocus(this.modalContent))}close(){this.removeAttribute("open"),this._cleanupFocusTrap&&(this._cleanupFocusTrap(),this._cleanupFocusTrap=null)}validate(){let t=!0;this.titleGroup.classList.remove("has-error"),this.endGroup.classList.remove("has-error"),this.titleInput.value.trim()||(this.titleGroup.classList.add("has-error"),t=!1);const e=new Date(this.startInput.value);return new Date(this.endInput.value)<=e&&(this.endGroup.classList.add("has-error"),t=!1),t}save(){if(!this.validate())return;const t={title:this.titleInput.value.trim(),start:new Date(this.startInput.value),end:new Date(this.endInput.value),backgroundColor:this._formData.color};this.emit("save",t),this.close()}formatDateForInput(t){const e=o=>String(o).padStart(2,"0"),r=t.getFullYear(),i=e(t.getMonth()+1),s=e(t.getDate()),n=e(t.getHours()),a=e(t.getMinutes());return`${r}-${i}-${s}T${n}:${a}`}unmount(){this._cleanupFocusTrap&&this._cleanupFocusTrap(),this._handleKeyDown&&(window.removeEventListener("keydown",this._handleKeyDown),this._handleKeyDown=null,this._keydownListenerAdded=!1)}}customElements.get("forcecal-event-form")||customElements.define("forcecal-event-form",I);const b=class b extends v{static get observedAttributes(){return["view","date","locale","timezone","week-starts-on","height"]}constructor(){super(),this.stateManager=null,this.currentView=null,this._hasRendered=!1,this._cachedStyles=null,this._busUnsubscribers=[]}initialize(){const t={view:this.getAttribute("view")||"month",date:this.getAttribute("date")?new Date(this.getAttribute("date")):new Date,locale:this.getAttribute("locale")||"en-US",timeZone:this.getAttribute("timezone")||Intl.DateTimeFormat().resolvedOptions().timeZone,weekStartsOn:parseInt(this.getAttribute("week-starts-on")||"0")};this.stateManager=new S(t),this._stateUnsubscribe=this.stateManager.subscribe(this.handleStateChange.bind(this)),this.setupEventListeners()}setupEventListeners(){this._busUnsubscribers.forEach(r=>r()),this._busUnsubscribers=[];const t=this.stateManager.eventBus;this._busUnsubscribers.push(t.on("navigation:*",(r,i)=>{this.emit("calendar-navigate",{action:i.split(":")[1],...r})})),this._busUnsubscribers.push(t.on("view:changed",r=>{this.emit("calendar-view-change",r)}));const e=(r,i)=>{this.emit(`calendar-event-${r}`,i)};this._busUnsubscribers.push(t.on("event:add",r=>{e("add",r)})),this._busUnsubscribers.push(t.on("event:update",r=>{e("update",r)})),this._busUnsubscribers.push(t.on("event:remove",r=>{e("remove",r)})),this._busUnsubscribers.push(t.on("event:added",r=>{this.emit("calendar-event-added",r)})),this._busUnsubscribers.push(t.on("event:updated",r=>{this.emit("calendar-event-updated",r)})),this._busUnsubscribers.push(t.on("event:deleted",r=>{this.emit("calendar-event-deleted",r)})),this._busUnsubscribers.push(t.on("date:selected",r=>{this.emit("calendar-date-select",r)}))}handleStateChange(t,e){var o,c;if(!this._hasRendered)return;const r=t.view!==(e==null?void 0:e.view),i=((o=t.currentDate)==null?void 0:o.getTime())!==((c=e==null?void 0:e.currentDate)==null?void 0:c.getTime()),s=t.events!==(e==null?void 0:e.events),n=t.loading!==(e==null?void 0:e.loading);if(t.error!==(e==null?void 0:e.error)){this.render();return}if(n){this._updateLoadingState(t.loading);return}r&&(this.currentView=t.view),r?(this._updateTitle(),this._updateViewButtons(),this._switchView()):i?(this._updateTitle(),this._updateViewContent()):s&&this._updateViewContent()}_updateTitle(){const t=this.$(".fc-title");if(t){const e=this.stateManager.getState();t.textContent=this.getTitle(e.currentDate,e.view)}}_updateViewButtons(){const t=this.stateManager.getState();this.$$("[data-view]").forEach(e=>{const r=e.dataset.view===t.view;e.classList.toggle("active",r)})}_switchView(){const t=this.$("#calendar-view-container");if(t){this._currentViewInstance&&this._currentViewInstance.cleanup&&this._currentViewInstance.cleanup();try{const e=b.RENDERERS[this.currentView]||k,r=new e(t,this.stateManager);r._viewType=this.currentView,this._currentViewInstance=r,r.render()}catch(e){console.error("[ForceCalendar] Error switching view:",e)}}}_updateViewContent(){this._currentViewInstance&&this._currentViewInstance.render&&this._currentViewInstance.render()}_updateLoadingState(t){const e=this.$(".fc-loading"),r=this.$(".fc-view-container");e&&(e.style.display=t?"flex":"none"),r&&(r.style.display=t?"none":"flex")}mount(){this.currentView=this.stateManager.getView(),super.mount()}loadView(t){!t||this.currentView===t||(this.currentView=t,this._switchView(),this._updateViewButtons(),this._updateTitle())}getStyles(){const t=this.getAttribute("height")||"800px";return`
|
|
619
619
|
${f.getBaseStyles()}
|
|
620
620
|
${f.getButtonStyles()}
|
|
621
621
|
${f.getGridStyles()}
|
|
622
622
|
${f.getAnimations()}
|
|
623
623
|
|
|
624
624
|
:host {
|
|
625
|
-
--calendar-height: ${
|
|
625
|
+
--calendar-height: ${t};
|
|
626
626
|
display: block;
|
|
627
627
|
font-family: var(--fc-font-family);
|
|
628
628
|
}
|
|
@@ -1000,13 +1000,13 @@
|
|
|
1000
1000
|
height: 100%;
|
|
1001
1001
|
background: var(--fc-background);
|
|
1002
1002
|
}
|
|
1003
|
-
`}template(){const
|
|
1003
|
+
`}template(){const t=this.stateManager.getState(),{currentDate:e,view:r,loading:i,error:s}=t;if(s)return`
|
|
1004
1004
|
<div class="force-calendar">
|
|
1005
1005
|
<div class="fc-error">
|
|
1006
|
-
<p><strong>Error:</strong> ${
|
|
1006
|
+
<p><strong>Error:</strong> ${x.escapeHTML(s.message||"An error occurred")}</p>
|
|
1007
1007
|
</div>
|
|
1008
1008
|
</div>
|
|
1009
|
-
`;const n=this.getTitle(
|
|
1009
|
+
`;const n=this.getTitle(e,r);return`
|
|
1010
1010
|
<div class="force-calendar">
|
|
1011
1011
|
<header class="fc-header">
|
|
1012
1012
|
<div class="fc-header-left">
|
|
@@ -1052,7 +1052,7 @@
|
|
|
1052
1052
|
|
|
1053
1053
|
<forcecal-event-form id="event-modal"></forcecal-event-form>
|
|
1054
1054
|
</div>
|
|
1055
|
-
`}renderView(){return'<div id="calendar-view-container"></div>'}afterRender(){const
|
|
1055
|
+
`}renderView(){return'<div id="calendar-view-container"></div>'}afterRender(){const t=this.$("#calendar-view-container");if(t&&this.stateManager&&this.currentView){if(this._currentViewInstance&&this._currentViewInstance._viewType===this.currentView&&t.children.length>0)return;this._currentViewInstance&&(this._currentViewInstance.cleanup&&this._currentViewInstance.cleanup(),this._viewUnsubscribe&&(this._viewUnsubscribe(),this._viewUnsubscribe=null));try{const i=b.RENDERERS[this.currentView]||k,s=new i(t,this.stateManager);s._viewType=this.currentView,this._currentViewInstance=s,s.render()}catch(i){console.error("[ForceCalendar] Error creating/rendering view:",i)}}this.$$("[data-action]").forEach(i=>{this.addListener(i,"click",this.handleNavigation)}),this.$$("[data-view]").forEach(i=>{this.addListener(i,"click",this.handleViewChange)});const e=this.$("#event-modal"),r=this.$("#create-event-btn");r&&e&&this.addListener(r,"click",()=>{e.open(new Date)}),this.addListener(this.shadowRoot,"day-click",i=>{e&&e.open(i.detail.date)}),e&&this.addListener(e,"save",i=>{const s=i.detail,n=window.crypto&&typeof window.crypto.randomUUID=="function"?window.crypto.randomUUID():Math.random().toString(36).substring(2,15);this.stateManager.addEvent({id:n,...s})}),this._hasRendered=!0}handleNavigation(t){switch(t.currentTarget.dataset.action){case"today":this.stateManager.today();break;case"previous":this.stateManager.previous();break;case"next":this.stateManager.next();break}}handleViewChange(t){const e=t.currentTarget.dataset.view;this.stateManager.setView(e)}getTitle(t,e){const r=this.stateManager.getState().config.locale;switch(e){case"month":return m.formatDate(t,"month",r);case"week":{const i=m.startOfWeek(t),s=m.endOfWeek(t);return m.formatDateRange(i,s,r)}case"day":return m.formatDate(t,"long",r);default:return m.formatDate(t,"month",r)}}getIcon(t){return{"chevron-left":`
|
|
1056
1056
|
<svg class="fc-icon" viewBox="0 0 24 24">
|
|
1057
1057
|
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>
|
|
1058
1058
|
</svg>
|
|
@@ -1064,5 +1064,5 @@
|
|
|
1064
1064
|
<svg class="fc-icon" viewBox="0 0 24 24">
|
|
1065
1065
|
<path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z"/>
|
|
1066
1066
|
</svg>
|
|
1067
|
-
`}[
|
|
1067
|
+
`}[t]||""}addEvent(t){return this.stateManager.addEvent(t)}updateEvent(t,e){return this.stateManager.updateEvent(t,e)}deleteEvent(t){return this.stateManager.deleteEvent(t)}getEvents(){return this.stateManager.getEvents()}setView(t){this.stateManager.setView(t)}setDate(t){this.stateManager.setDate(t)}next(){this.stateManager.next()}previous(){this.stateManager.previous()}today(){this.stateManager.today()}unmount(){this.destroy()}destroy(){this._busUnsubscribers.forEach(t=>t()),this._busUnsubscribers=[],this._stateUnsubscribe&&(this._stateUnsubscribe(),this._stateUnsubscribe=null),this._currentViewInstance&&this._currentViewInstance.cleanup&&(this._currentViewInstance.cleanup(),this._currentViewInstance=null),this.stateManager&&this.stateManager.destroy(),super.cleanup()}};y(b,"RENDERERS",{month:k,week:C,day:F});let D=b;customElements.get("forcecal-main")||customElements.define("forcecal-main",D),l.BaseComponent=v,l.BaseViewRenderer=w,l.DOMUtils=x,l.DateUtils=m,l.DayViewRenderer=F,l.EventBus=E,l.ForceCalendar=D,l.MonthViewRenderer=k,l.StateManager=S,l.StyleUtils=f,l.WeekViewRenderer=C,l.eventBus=V,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})});
|
|
1068
1068
|
//# sourceMappingURL=force-calendar-interface.umd.js.map
|