@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.
@@ -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(()=>`<div style="height: ${this.hourHeight}px; border-bottom: 1px solid var(--fc-background-hover);"></div>`).join(``)}
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(()=>`<div style="height: ${this.hourHeight}px; border-bottom: 1px solid var(--fc-background-hover);"></div>`).join(``)}
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;