@forcecalendar/interface 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/force-calendar-interface.esm.js +97 -2
- package/dist/force-calendar-interface.esm.js.map +1 -1
- package/dist/force-calendar-interface.umd.js +6 -5
- package/dist/force-calendar-interface.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/components/ForceCalendar.js +1 -0
- package/src/renderers/BaseViewRenderer.js +140 -0
- package/src/renderers/DayViewRenderer.js +6 -1
- package/src/renderers/WeekViewRenderer.js +7 -1
- package/types/renderers/BaseViewRenderer.d.ts +29 -0
|
@@ -247,7 +247,7 @@
|
|
|
247
247
|
${this.formatTime(i)}${n?``:` - `+this.formatTime(a)}
|
|
248
248
|
</div>
|
|
249
249
|
</div>
|
|
250
|
-
`}getEventColor(e){return c.sanitizeColor(e?.backgroundColor,`#2563eb`)}attachCommonEventHandlers(){this.addListener(this.container,`click`,e=>{let t=e.target.closest(`.fc-event`);!t||!this.container.contains(t)||(e.stopPropagation(),this._selectEventFromElement(t))}),this.addListener(this.container,`keydown`,e=>{if(e.key!==`Enter`&&e.key!==` `)return;let t=e.target.closest(`.fc-event`);!t||!this.container.contains(t)||(e.preventDefault(),e.stopPropagation(),this._selectEventFromElement(t))}),this._enhanceEventAccessibility()}_selectEventFromElement(e){let t=e.dataset.eventId,n=this.stateManager.getEvents().find(e=>e.id===t);n&&this.stateManager.selectEvent(n)}_enhanceEventAccessibility(){for(let e of this.container.querySelectorAll(`.fc-event`))if(e.setAttribute(`role`,`button`),e.setAttribute(`tabindex`,`0`),!e.hasAttribute(`aria-label`)){let t=(e.getAttribute(`title`)||e.textContent||``).trim();t&&e.setAttribute(`aria-label`,`Event: ${t}`)}}},u=class extends l{constructor(e,t){super(e,t),this.maxEventsToShow=3}render(){if(!this.container||!this.stateManager)return;let e=this.stateManager.getViewData();if(!e||!e.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();let t=this.stateManager.getState().config,n=this._renderMonthView(e,t);this.container.innerHTML=n,this._attachEventHandlers();let r=this._applyRovingTabindex(this._pendingFocusMs??null);this._pendingFocusMs!=null&&(this._pendingFocusMs=null,r&&r.focus())}_renderMonthView(e,t){let n=t.weekStartsOn||0,r=this._getDayNames(n),i=t.locale||`en-US`;this._dayLabelFormatter=new Intl.DateTimeFormat(i,{weekday:`long`,year:`numeric`,month:`long`,day:`numeric`});let a=this.stateManager.getState().currentDate,o=new Intl.DateTimeFormat(i,{month:`long`,year:`numeric`}).format(a||new Date),s=`
|
|
250
|
+
`}getEventColor(e){return c.sanitizeColor(e?.backgroundColor,`#2563eb`)}attachCommonEventHandlers(){this.addListener(this.container,`click`,e=>{let t=e.target.closest(`.fc-event`);!t||!this.container.contains(t)||(e.stopPropagation(),this._selectEventFromElement(t))}),this.addListener(this.container,`keydown`,e=>{if(e.key!==`Enter`&&e.key!==` `)return;let t=e.target.closest(`.fc-event`);!t||!this.container.contains(t)||(e.preventDefault(),e.stopPropagation(),this._selectEventFromElement(t))}),this._enhanceEventAccessibility()}_selectEventFromElement(e){let t=e.dataset.eventId,n=this.stateManager.getEvents().find(e=>e.id===t);n&&this.stateManager.selectEvent(n)}_enhanceTimeGridAccessibility(e,t){let n=this.container.querySelector(`.fc-time-grid`);if(!n)return;n.setAttribute(`role`,`grid`),n.setAttribute(`aria-label`,t);let r=this.container.querySelector(`.fc-time-gutter`);r&&r.setAttribute(`aria-hidden`,`true`);let i=this.stateManager.getState().config.locale||`en-US`,a=new Intl.DateTimeFormat(i,{weekday:`long`,month:`long`,day:`numeric`}),o=Array.from(this.container.querySelectorAll(e));for(let e of o){e.setAttribute(`role`,`row`);let t=new Date(e.dataset.date),n=a.format(t);e.setAttribute(`aria-label`,n);for(let t of e.querySelectorAll(`.fc-hour-slot`))t.setAttribute(`role`,`gridcell`),t.setAttribute(`tabindex`,`-1`),t.setAttribute(`aria-label`,`${n}, ${this.formatHour(Number(t.dataset.hour))}`)}if(this._applySlotRovingTabindex(o),this._pendingSlotFocus){let{colIndex:e,hour:t}=this._pendingSlotFocus;this._pendingSlotFocus=null;let n=this._slotAt(o,e,t);n&&(this._applySlotRovingTabindex(o,n),n.focus())}this.addListener(this.container,`keydown`,t=>{let n=t.target.closest(`.fc-hour-slot`);if(!n||!this.container.contains(n))return;let r=n.closest(e),i=o.indexOf(r),a=Number(n.dataset.hour),s=null;switch(t.key){case`ArrowDown`:s=this._slotAt(o,i,a+1);break;case`ArrowUp`:s=this._slotAt(o,i,a-1);break;case`ArrowRight`:s=this._slotAt(o,i+1,a);break;case`ArrowLeft`:s=this._slotAt(o,i-1,a);break;case`Home`:s=this._slotAt(o,i,0);break;case`End`:s=this._slotAt(o,i,23);break;case`PageUp`:case`PageDown`:t.preventDefault(),this._pendingSlotFocus={colIndex:i,hour:a},t.key===`PageDown`?this.stateManager.next():this.stateManager.previous();return;case`Enter`:case` `:{t.preventDefault();let e=new Date(r.dataset.date);e.setHours(a,0,0,0),this._pendingSlotFocus={colIndex:i,hour:a},this.stateManager.selectDate(e);return}default:return}t.preventDefault(),s&&(this._applySlotRovingTabindex(o,s),s.scrollIntoView?.({block:`nearest`}),s.focus())})}_slotAt(e,t,n){return t<0||t>=e.length||n<0||n>23?null:e[t].querySelector(`.fc-hour-slot[data-hour="${n}"]`)}_applySlotRovingTabindex(e,t=null){let n=this.container.querySelectorAll(`.fc-hour-slot`);if(n.length!==0){if(!t){let r=e.find(e=>this.isToday(new Date(e.dataset.date)))||e[0];t=r&&r.querySelector(`.fc-hour-slot[data-hour="9"]`),t||=n[0]}for(let e of n)e.setAttribute(`tabindex`,e===t?`0`:`-1`)}}_enhanceEventAccessibility(){for(let e of this.container.querySelectorAll(`.fc-event`))if(e.setAttribute(`role`,`button`),e.setAttribute(`tabindex`,`0`),!e.hasAttribute(`aria-label`)){let t=(e.getAttribute(`title`)||e.textContent||``).trim();t&&e.setAttribute(`aria-label`,`Event: ${t}`)}}},u=class extends l{constructor(e,t){super(e,t),this.maxEventsToShow=3}render(){if(!this.container||!this.stateManager)return;let e=this.stateManager.getViewData();if(!e||!e.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();let t=this.stateManager.getState().config,n=this._renderMonthView(e,t);this.container.innerHTML=n,this._attachEventHandlers();let r=this._applyRovingTabindex(this._pendingFocusMs??null);this._pendingFocusMs!=null&&(this._pendingFocusMs=null,r&&r.focus())}_renderMonthView(e,t){let n=t.weekStartsOn||0,r=this._getDayNames(n),i=t.locale||`en-US`;this._dayLabelFormatter=new Intl.DateTimeFormat(i,{weekday:`long`,year:`numeric`,month:`long`,day:`numeric`});let a=this.stateManager.getState().currentDate,o=new Intl.DateTimeFormat(i,{month:`long`,year:`numeric`}).format(a||new Date),s=`
|
|
251
251
|
<div class="fc-month-view" role="grid" aria-label="${this.escapeHTML(o)}" style="display: flex; flex-direction: column; height: 100%; min-height: 400px; background: var(--fc-background); border: 1px solid var(--fc-border-color);">
|
|
252
252
|
<div class="fc-month-header" role="row" style="display: grid; grid-template-columns: repeat(7, 1fr); border-bottom: 1px solid var(--fc-border-color); background: var(--fc-background-alt);">
|
|
253
253
|
${r.map(e=>`<div class="fc-month-header-cell" role="columnheader" style="padding: 12px 8px; text-align: center; font-size: 11px; font-weight: 600; color: var(--fc-text-light); text-transform: uppercase;">${this.escapeHTML(e)}</div>`).join(``)}
|
|
@@ -328,7 +328,7 @@
|
|
|
328
328
|
`}_renderDayColumn(e,t){return`
|
|
329
329
|
<div class="fc-week-day-column" data-date="${e.date.toISOString()}" style="border-right: 1px solid var(--fc-border-color); position: relative; cursor: pointer;">
|
|
330
330
|
<!-- Hour grid lines -->
|
|
331
|
-
${t.map(
|
|
331
|
+
${t.map(e=>`<div class="fc-hour-slot" data-hour="${e}" style="height: ${this.hourHeight}px; border-bottom: 1px solid var(--fc-background-hover);"></div>`).join(``)}
|
|
332
332
|
|
|
333
333
|
<!-- Now indicator for today -->
|
|
334
334
|
${e.isToday?this.renderNowIndicator():``}
|
|
@@ -336,7 +336,7 @@
|
|
|
336
336
|
<!-- Timed events -->
|
|
337
337
|
${(()=>{let t=this.computeOverlapLayout(e.timedEvents);return e.timedEvents.map(e=>this.renderTimedEvent(e,{compact:!0,overlapLayout:t})).join(``)})()}
|
|
338
338
|
</div>
|
|
339
|
-
`}_attachEventHandlers(){this.addListener(this.container,`click`,e=>{let t=e.target.closest(`.fc-week-day-column`);if(!t||!this.container.contains(t)||e.target.closest(`.fc-event`))return;let n=new Date(t.dataset.date),r=this.container.querySelector(`#week-scroll-container`),i=t.offsetTop,a=e.clientY-t.getBoundingClientRect().top+(r?r.scrollTop:0)-i,o=Math.max(0,Math.min(a+i,this.totalHeight));n.setHours(Math.floor(o/this.hourHeight),Math.floor(o%this.hourHeight/(this.hourHeight/60)),0,0),this.stateManager.selectDate(n)}),this.attachCommonEventHandlers()}_scrollToCurrentTime(){if(this._scrolled)return;let e=this.container.querySelector(`#week-scroll-container`);e&&(e.scrollTop=8*this.hourHeight-50,this._scrolled=!0)}},f=class extends l{constructor(e,t){super(e,t),this.hourHeight=60,this.totalHeight=24*this.hourHeight}render(){if(!this.container||!this.stateManager)return;let e=this.stateManager.getViewData();if(!e){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;let t=this.stateManager.getState().config,n=this._renderDayView(e,t);this.container.innerHTML=n,this._attachEventHandlers(),this._scrollToCurrentTime(),this.startNowIndicatorTimer()}_renderDayView(e,t){let n=this.stateManager?.getState()?.currentDate||new Date,r=this._extractDayData(e,n);if(!r)return`<div style="padding: 20px; text-align: center; color: var(--fc-text-secondary);">No data available for day view.</div>`;let{dayDate:i,dayName:a,isToday:o,allDayEvents:s,timedEvents:c}=r,l=Array.from({length:24},(e,t)=>t);return`
|
|
339
|
+
`}_attachEventHandlers(){this.addListener(this.container,`click`,e=>{let t=e.target.closest(`.fc-week-day-column`);if(!t||!this.container.contains(t)||e.target.closest(`.fc-event`))return;let n=new Date(t.dataset.date),r=this.container.querySelector(`#week-scroll-container`),i=t.offsetTop,a=e.clientY-t.getBoundingClientRect().top+(r?r.scrollTop:0)-i,o=Math.max(0,Math.min(a+i,this.totalHeight));n.setHours(Math.floor(o/this.hourHeight),Math.floor(o%this.hourHeight/(this.hourHeight/60)),0,0),this.stateManager.selectDate(n)}),this.attachCommonEventHandlers();let e=this.stateManager.getViewData()?.days||[],t=this.stateManager.getState().config.locale||`en-US`,n=e[0]?new Date(e[0].date):new Date,r=`Week of ${new Intl.DateTimeFormat(t,{month:`long`,day:`numeric`,year:`numeric`}).format(n)}`;this._enhanceTimeGridAccessibility(`.fc-week-day-column`,r)}_scrollToCurrentTime(){if(this._scrolled)return;let e=this.container.querySelector(`#week-scroll-container`);e&&(e.scrollTop=8*this.hourHeight-50,this._scrolled=!0)}},f=class extends l{constructor(e,t){super(e,t),this.hourHeight=60,this.totalHeight=24*this.hourHeight}render(){if(!this.container||!this.stateManager)return;let e=this.stateManager.getViewData();if(!e){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;let t=this.stateManager.getState().config,n=this._renderDayView(e,t);this.container.innerHTML=n,this._attachEventHandlers(),this._scrollToCurrentTime(),this.startNowIndicatorTimer()}_renderDayView(e,t){let n=this.stateManager?.getState()?.currentDate||new Date,r=this._extractDayData(e,n);if(!r)return`<div style="padding: 20px; text-align: center; color: var(--fc-text-secondary);">No data available for day view.</div>`;let{dayDate:i,dayName:a,isToday:o,allDayEvents:s,timedEvents:c}=r,l=Array.from({length:24},(e,t)=>t);return`
|
|
340
340
|
<div class="fc-day-view" style="display: flex; flex-direction: column; height: 100%; background: var(--fc-background); overflow: hidden;">
|
|
341
341
|
${this._renderHeader(i,a,o)}
|
|
342
342
|
${this._renderAllDayRow(s,i)}
|
|
@@ -386,7 +386,7 @@
|
|
|
386
386
|
`}_renderDayColumn(e,t,n,r){return`
|
|
387
387
|
<div class="fc-day-column" data-date="${n.toISOString()}" style="position: relative; cursor: pointer;">
|
|
388
388
|
<!-- Hour grid lines -->
|
|
389
|
-
${r.map(
|
|
389
|
+
${r.map(e=>`<div class="fc-hour-slot" data-hour="${e}" style="height: ${this.hourHeight}px; border-bottom: 1px solid var(--fc-background-hover);"></div>`).join(``)}
|
|
390
390
|
|
|
391
391
|
<!-- Now indicator for today -->
|
|
392
392
|
${t?this.renderNowIndicator():``}
|
|
@@ -394,7 +394,7 @@
|
|
|
394
394
|
<!-- Timed events -->
|
|
395
395
|
${(()=>{let t=this.computeOverlapLayout(e);return e.map(e=>this.renderTimedEvent(e,{compact:!1,overlapLayout:t})).join(``)})()}
|
|
396
396
|
</div>
|
|
397
|
-
`}_attachEventHandlers(){this.addListener(this.container,`click`,e=>{let t=e.target.closest(`.fc-day-column`);if(!t||!this.container.contains(t)||e.target.closest(`.fc-event`))return;let n=new Date(t.dataset.date),r=this.container.querySelector(`#day-scroll-container`),i=t.offsetTop,a=e.clientY-t.getBoundingClientRect().top+(r?r.scrollTop:0)-i,o=Math.max(0,Math.min(a+i,this.totalHeight));n.setHours(Math.floor(o/this.hourHeight),Math.floor(o%this.hourHeight/(this.hourHeight/60)),0,0),this.stateManager.selectDate(n)}),this.attachCommonEventHandlers()}_scrollToCurrentTime(){if(this._scrolled)return;let e=this.container.querySelector(`#day-scroll-container`);e&&(e.scrollTop=8*this.hourHeight-50,this._scrolled=!0)}},p=class extends n{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(e,t,n){e===`open`&&(n===null?this.close():this.open())}getStyles(){return`
|
|
397
|
+
`}_attachEventHandlers(){this.addListener(this.container,`click`,e=>{let t=e.target.closest(`.fc-day-column`);if(!t||!this.container.contains(t)||e.target.closest(`.fc-event`))return;let n=new Date(t.dataset.date),r=this.container.querySelector(`#day-scroll-container`),i=t.offsetTop,a=e.clientY-t.getBoundingClientRect().top+(r?r.scrollTop:0)-i,o=Math.max(0,Math.min(a+i,this.totalHeight));n.setHours(Math.floor(o/this.hourHeight),Math.floor(o%this.hourHeight/(this.hourHeight/60)),0,0),this.stateManager.selectDate(n)}),this.attachCommonEventHandlers();let e=this.stateManager.getState().config.locale||`en-US`,t=this.stateManager.getState().currentDate||new Date,n=new Intl.DateTimeFormat(e,{weekday:`long`,month:`long`,day:`numeric`,year:`numeric`}).format(t);this._enhanceTimeGridAccessibility(`.fc-day-column`,n)}_scrollToCurrentTime(){if(this._scrolled)return;let e=this.container.querySelector(`#day-scroll-container`);e&&(e.scrollTop=8*this.hourHeight-50,this._scrolled=!0)}},p=class extends n{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(e,t,n){e===`open`&&(n===null?this.close():this.open())}getStyles(){return`
|
|
398
398
|
${c.getBaseStyles()}
|
|
399
399
|
${c.getButtonStyles()}
|
|
400
400
|
|
|
@@ -722,6 +722,7 @@
|
|
|
722
722
|
}
|
|
723
723
|
|
|
724
724
|
.fc-month-day:focus-visible,
|
|
725
|
+
.fc-hour-slot:focus-visible,
|
|
725
726
|
.fc-event:focus-visible {
|
|
726
727
|
outline: 2px solid var(--fc-primary-color);
|
|
727
728
|
outline-offset: -2px;
|