@fullcalendar/list 7.0.0-beta.3 → 7.0.0-beta.4

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/index.global.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- FullCalendar List View Plugin v7.0.0-beta.3
2
+ FullCalendar List View Plugin v7.0.0-beta.4
3
3
  Docs & License: https://fullcalendar.io/docs/list-view
4
4
  (c) 2024 Adam Shaw
5
5
  */
@@ -16,19 +16,23 @@ FullCalendar.List = (function (exports, core, internal$1, preact) {
16
16
  let text = options.listDayFormat ? dateEnv.format(dayDate, options.listDayFormat) : '';
17
17
  // will ever be falsy? also, BAD NAME "alt"
18
18
  let sideText = options.listDaySideFormat ? dateEnv.format(dayDate, options.listDaySideFormat) : '';
19
+ let isNavLink = options.navLinks;
19
20
  let renderProps = Object.assign({ date: dateEnv.toDate(dayDate), view: viewApi, text,
20
- sideText, navLinkAttrs: internal$1.buildNavLinkAttrs(this.context, dayDate), sideNavLinkAttrs: internal$1.buildNavLinkAttrs(this.context, dayDate, 'day', false) }, dayMeta);
21
+ sideText, navLinkAttrs: isNavLink
22
+ ? internal$1.buildNavLinkAttrs(this.context, dayDate, undefined, text)
23
+ : {}, sideNavLinkAttrs: isNavLink
24
+ // duplicate navLink, so does not need to be tabbable
25
+ ? internal$1.buildNavLinkAttrs(this.context, dayDate, undefined, sideText, /* isTabbable = */ false)
26
+ : {} }, dayMeta);
21
27
  // TODO: make a reusable HOC for dayHeader (used in daygrid/timegrid too)
22
28
  return (preact.createElement("div", { className: internal$1.joinClassNames('fc-list-day-outer', stickyHeaderDates && 'fc-list-day-outer-sticky') },
23
- preact.createElement(internal$1.ContentContainer, { tag: "div", className: internal$1.joinClassNames('fc-list-day', internal$1.getDayClassName(dayMeta)), attrs: {
24
- 'data-date': internal$1.formatDayString(dayDate),
25
- }, renderProps: renderProps, generatorName: "dayHeaderContent", customGenerator: options.dayHeaderContent, defaultGenerator: renderInnerContent, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount })));
29
+ preact.createElement(internal$1.ContentContainer, { tag: "div", className: internal$1.joinClassNames('fc-list-day', internal$1.getDayClassName(dayMeta)), attrs: Object.assign({ 'data-date': internal$1.formatDayString(dayDate) }, (dayMeta.isToday ? { 'aria-current': 'date' } : {})), renderProps: renderProps, generatorName: "dayHeaderContent", customGenerator: options.dayHeaderContent, defaultGenerator: renderInnerContent, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount })));
26
30
  }
27
31
  }
28
32
  function renderInnerContent(props) {
29
33
  return (preact.createElement(preact.Fragment, null,
30
- props.text && (preact.createElement("a", Object.assign({ id: props.textId, className: "fc-list-day-text" }, props.navLinkAttrs), props.text)),
31
- props.sideText && ( /* not keyboard tabbable */preact.createElement("a", Object.assign({ className: "fc-list-day-side-text" }, props.sideNavLinkAttrs), props.sideText))));
34
+ props.text && (preact.createElement("div", Object.assign({ className: "fc-list-day-text" }, props.navLinkAttrs), props.text)),
35
+ props.sideText && (preact.createElement("div", Object.assign({ className: "fc-list-day-side-text" }, props.sideNavLinkAttrs), props.sideText))));
32
36
  }
33
37
 
34
38
  const DEFAULT_TIME_FORMAT = internal$1.createFormatter({
@@ -55,8 +59,8 @@ FullCalendar.List = (function (exports, core, internal$1, preact) {
55
59
  let { eventRange } = props;
56
60
  let { options } = context;
57
61
  let timeFormat = options.eventTimeFormat || DEFAULT_TIME_FORMAT;
58
- let anchorAttrs = internal$1.getEventRangeAnchorAttrs(eventRange, context);
59
- return (preact.createElement(internal$1.EventContainer, Object.assign({}, props, { tag: anchorAttrs ? 'a' : 'div', attrs: anchorAttrs, className: 'fc-list-event', defaultGenerator: renderEventTitleOnly, eventRange: eventRange, timeText: "", disableDragging: true, disableResizing: true }), (InnerContent, eventContentArg) => (preact.createElement(preact.Fragment, null,
62
+ let [tag, attrs] = internal$1.getEventTagAndAttrs(eventRange, context);
63
+ return (preact.createElement(internal$1.EventContainer, Object.assign({}, props, { tag: tag, attrs: Object.assign({ role: 'listitem' }, attrs), className: 'fc-list-event', defaultGenerator: renderEventTitleOnly, eventRange: eventRange, timeText: "", disableDragging: true, disableResizing: true }), (InnerContent, eventContentArg) => (preact.createElement(preact.Fragment, null,
60
64
  preact.createElement("div", { className: 'fc-list-event-time-outer', style: { width: props.timeOuterWidth } }, this.buildTimeContent(eventRange, props.slicedStart, props.slicedEnd, props.isStart, props.isEnd, timeFormat, context)),
61
65
  preact.createElement("div", { className: "fc-list-event-dot-outer" },
62
66
  preact.createElement("span", { className: "fc-list-event-dot", style: {
@@ -117,12 +121,13 @@ FullCalendar.List = (function (exports, core, internal$1, preact) {
117
121
  const { nowDate, todayRange } = props;
118
122
  const { options } = context;
119
123
  const segs = this.sortEventSegs(props.segs, options.eventOrder);
120
- return (preact.createElement("div", { className: 'fc-list-day-and-events' },
124
+ const fullDateStr = internal$1.buildDateStr(this.context, props.dayDate);
125
+ return (preact.createElement("div", { role: 'listitem', "aria-label": fullDateStr, className: 'fc-list-day-and-events' },
121
126
  preact.createElement(ListDayHeader, { dayDate: props.dayDate, todayRange: todayRange, forPrint: props.forPrint }),
122
- segs.map((seg) => {
127
+ preact.createElement("div", { role: 'list', "aria-label": options.eventsHint }, segs.map((seg) => {
123
128
  const key = internal$1.getEventKey(seg);
124
129
  return (preact.createElement(ListEvent, Object.assign({ key: key, eventRange: seg.eventRange, slicedStart: seg.slicedStart, slicedEnd: seg.slicedEnd, isStart: seg.isStart, isEnd: seg.isEnd, timeWidthRef: timeWidthRefMap.createRef(key), timeOuterWidth: props.timeOuterWidth, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: false }, internal$1.getEventRangeMeta(seg.eventRange, todayRange, nowDate))));
125
- })));
130
+ }))));
126
131
  }
127
132
  componentWillUnmount() {
128
133
  internal$1.setRef(this.props.timeWidthRef, null);
@@ -168,11 +173,11 @@ FullCalendar.List = (function (exports, core, internal$1, preact) {
168
173
  let { dayDates, dayRanges } = this.computeDateVars(props.dateProfile);
169
174
  let eventSegs = this.eventStoreToSegs(props.eventStore, props.eventUiBases, dayRanges);
170
175
  let verticalScrolling = !props.forPrint && !internal$1.getIsHeightAuto(options);
171
- return (preact.createElement(internal$1.ViewContainer, { elRef: this.setRootEl, className: 'fc-list fc-flex-col fc-border', viewSpec: context.viewSpec },
176
+ return (preact.createElement(internal$1.ViewContainer, { viewSpec: context.viewSpec, className: 'fc-list fc-flex-col fc-border', elRef: this.setRootEl },
172
177
  preact.createElement(internal$1.Scroller // TODO: don't need heavyweight component
173
- , { vertical: verticalScrolling, className: verticalScrolling ? 'fc-liquid' : '' }, eventSegs.length > 0 ?
174
- this.renderSegList(eventSegs, dayDates) :
175
- this.renderEmptyMessage())));
178
+ , { vertical: verticalScrolling, className: verticalScrolling ? 'fc-liquid' : '' },
179
+ this.renderSegList(eventSegs, dayDates),
180
+ !eventSegs.length && this.renderEmptyMessage())));
176
181
  }
177
182
  renderEmptyMessage() {
178
183
  let { options, viewApi } = this.context;
@@ -180,22 +185,25 @@ FullCalendar.List = (function (exports, core, internal$1, preact) {
180
185
  text: options.noEventsText,
181
186
  view: viewApi,
182
187
  };
183
- return (preact.createElement(internal$1.ContentContainer, { tag: "div", className: 'fc-list-empty', renderProps: renderProps, generatorName: "noEventsContent", customGenerator: options.noEventsContent, defaultGenerator: renderNoEventsInner, classNameGenerator: options.noEventsClassNames, didMount: options.noEventsDidMount, willUnmount: options.noEventsWillUnmount }, (InnerContent) => (preact.createElement(InnerContent, { tag: "div", className: 'fc-list-empty-inner' }))));
188
+ return (preact.createElement(internal$1.ContentContainer, { tag: "div", attrs: {
189
+ role: 'status', // does a polite announcement
190
+ }, className: 'fc-list-empty', renderProps: renderProps, generatorName: "noEventsContent", customGenerator: options.noEventsContent, defaultGenerator: renderNoEventsInner, classNameGenerator: options.noEventsClassNames, didMount: options.noEventsDidMount, willUnmount: options.noEventsWillUnmount }, (InnerContent) => (preact.createElement(InnerContent, { tag: "div", className: 'fc-list-empty-inner' }))));
184
191
  }
185
192
  renderSegList(allSegs, dayDates) {
186
193
  let segsByDay = groupSegsByDay(allSegs); // sparse array
187
- return (preact.createElement(internal$1.NowTimer, { unit: "day" }, (nowDate, todayRange) => {
188
- const dayNodes = [];
189
- for (let dayIndex = 0; dayIndex < segsByDay.length; dayIndex += 1) {
190
- let daySegs = segsByDay[dayIndex];
191
- if (daySegs) { // sparse array, so might be undefined
192
- const dayDate = dayDates[dayIndex];
193
- const key = internal$1.formatDayString(dayDate);
194
- dayNodes.push(preact.createElement(ListDay, { key: key, dayDate: dayDate, nowDate: nowDate, todayRange: todayRange, segs: daySegs, forPrint: this.props.forPrint, timeWidthRef: this.timeWidthRefMap.createRef(key), timeOuterWidth: this.state.timeOuterWidth }));
194
+ return (preact.createElement("div", { role: 'list', "aria-labelledby": this.props.labelId, "aria-label": this.props.labelStr },
195
+ preact.createElement(internal$1.NowTimer, { unit: "day" }, (nowDate, todayRange) => {
196
+ const dayNodes = [];
197
+ for (let dayIndex = 0; dayIndex < segsByDay.length; dayIndex += 1) {
198
+ let daySegs = segsByDay[dayIndex];
199
+ if (daySegs) { // sparse array, so might be undefined
200
+ const dayDate = dayDates[dayIndex];
201
+ const key = internal$1.formatDayString(dayDate);
202
+ dayNodes.push(preact.createElement(ListDay, { key: key, dayDate: dayDate, nowDate: nowDate, todayRange: todayRange, segs: daySegs, forPrint: this.props.forPrint, timeWidthRef: this.timeWidthRefMap.createRef(key), timeOuterWidth: this.state.timeOuterWidth }));
203
+ }
195
204
  }
196
- }
197
- return (preact.createElement(preact.Fragment, null, dayNodes));
198
- }));
205
+ return (preact.createElement(preact.Fragment, null, dayNodes));
206
+ })));
199
207
  }
200
208
  _eventStoreToSegs(eventStore, eventUiBases, dayRanges) {
201
209
  return this.eventRangesToSegs(internal$1.sliceEventStore(eventStore, eventUiBases,
@@ -1,6 +1,6 @@
1
1
  /*!
2
- FullCalendar List View Plugin v7.0.0-beta.3
2
+ FullCalendar List View Plugin v7.0.0-beta.4
3
3
  Docs & License: https://fullcalendar.io/docs/list-view
4
4
  (c) 2024 Adam Shaw
5
5
  */
6
- FullCalendar.List=function(e,t,n,i){"use strict";class a extends n.BaseComponent{render(){let{dateEnv:e,options:t,viewApi:a}=this.context,{dayDate:r,todayRange:o}=this.props,l=!this.props.forPrint&&n.getStickyHeaderDates(t),d=n.getDateMeta(r,o),c=t.listDayFormat?e.format(r,t.listDayFormat):"",m=t.listDaySideFormat?e.format(r,t.listDaySideFormat):"",u=Object.assign({date:e.toDate(r),view:a,text:c,sideText:m,navLinkAttrs:n.buildNavLinkAttrs(this.context,r),sideNavLinkAttrs:n.buildNavLinkAttrs(this.context,r,"day",!1)},d);return i.createElement("div",{className:n.joinClassNames("fc-list-day-outer",l&&"fc-list-day-outer-sticky")},i.createElement(n.ContentContainer,{tag:"div",className:n.joinClassNames("fc-list-day",n.getDayClassName(d)),attrs:{"data-date":n.formatDayString(r)},renderProps:u,generatorName:"dayHeaderContent",customGenerator:t.dayHeaderContent,defaultGenerator:s,classNameGenerator:t.dayHeaderClassNames,didMount:t.dayHeaderDidMount,willUnmount:t.dayHeaderWillUnmount}))}}function s(e){return i.createElement(i.Fragment,null,e.text&&i.createElement("a",Object.assign({id:e.textId,className:"fc-list-day-text"},e.navLinkAttrs),e.text),e.sideText&&i.createElement("a",Object.assign({className:"fc-list-day-side-text"},e.sideNavLinkAttrs),e.sideText))}const r=n.createFormatter({hour:"numeric",minute:"2-digit",meridiem:"short"});class o extends n.BaseComponent{constructor(){super(...arguments),this.handleTitleEl=e=>{this.disconnectTitleWidth&&this.disconnectTitleWidth(),e&&(this.disconnectTitleWidth=n.watchWidth(e,e=>{n.setRef(this.props.timeWidthRef,e)}))}}render(){let{props:e,context:t}=this,{eventRange:a}=e,{options:s}=t,o=s.eventTimeFormat||r,d=n.getEventRangeAnchorAttrs(a,t);return i.createElement(n.EventContainer,Object.assign({},e,{tag:d?"a":"div",attrs:d,className:"fc-list-event",defaultGenerator:l,eventRange:a,timeText:"",disableDragging:!0,disableResizing:!0}),(n,s)=>i.createElement(i.Fragment,null,i.createElement("div",{className:"fc-list-event-time-outer",style:{width:e.timeOuterWidth}},this.buildTimeContent(a,e.slicedStart,e.slicedEnd,e.isStart,e.isEnd,o,t)),i.createElement("div",{className:"fc-list-event-dot-outer"},i.createElement("span",{className:"fc-list-event-dot",style:{borderColor:s.borderColor||s.backgroundColor}})),i.createElement(n,{tag:"div",className:"fc-list-event-title"})))}buildTimeContent(e,t,a,s,r,o,l){let{options:c}=l;if(!1!==c.displayEventTime){if(e.def.allDay||!s&&!r){let e={text:l.options.allDayText,view:l.viewApi};return i.createElement(n.ContentContainer,{tag:"div",className:"fc-list-event-time",renderProps:e,elRef:this.handleTitleEl,generatorName:"allDayContent",customGenerator:c.allDayContent,defaultGenerator:d,classNameGenerator:c.allDayClassNames,didMount:c.allDayDidMount,willUnmount:c.allDayWillUnmount})}return i.createElement("div",{className:"fc-list-event-time",ref:this.handleTitleEl},n.buildEventRangeTimeText(o,e,t,a,s,r,l))}return null}componentWillUnmount(){n.setRef(this.props.timeWidthRef,null)}}function l(e){return e.event.title}function d(e){return e.text}class c extends n.BaseComponent{constructor(){super(...arguments),this.sortEventSegs=n.memoize(n.sortEventSegs),this.timeWidthRefMap=new n.RefMap(()=>{n.afterSize(this.handleTimeWidths)}),this.handleTimeWidths=()=>{const e=this.timeWidthRefMap.current;let t=0;for(const n of e.values())t=Math.max(t,n);n.setRef(this.props.timeWidthRef,t)}}render(){const{props:e,context:t,timeWidthRefMap:s}=this,{nowDate:r,todayRange:l}=e,{options:d}=t,c=this.sortEventSegs(e.segs,d.eventOrder);return i.createElement("div",{className:"fc-list-day-and-events"},i.createElement(a,{dayDate:e.dayDate,todayRange:l,forPrint:e.forPrint}),c.map(t=>{const a=n.getEventKey(t);return i.createElement(o,Object.assign({key:a,eventRange:t.eventRange,slicedStart:t.slicedStart,slicedEnd:t.slicedEnd,isStart:t.isStart,isEnd:t.isEnd,timeWidthRef:s.createRef(a),timeOuterWidth:e.timeOuterWidth,isDragging:!1,isResizing:!1,isDateSelecting:!1,isSelected:!1},n.getEventRangeMeta(t.eventRange,l,r)))}))}componentWillUnmount(){n.setRef(this.props.timeWidthRef,null)}}class m extends n.DateComponent{constructor(){super(...arguments),this.computeDateVars=n.memoize(f),this.eventStoreToSegs=n.memoize(this._eventStoreToSegs),this.timeWidthRefMap=new n.RefMap(()=>{n.afterSize(this.handleTimeWidths)}),this.setRootEl=e=>{e?this.context.registerInteractiveComponent(this,{el:e,disableHits:!0}):this.context.unregisterInteractiveComponent(this)},this.handleTimeWidths=()=>{const e=this.timeWidthRefMap.current;let t=0;for(const n of e.values())t=Math.max(t,n);this.setState({timeOuterWidth:t})}}render(){let{props:e,context:t}=this,{options:a}=t,{dayDates:s,dayRanges:r}=this.computeDateVars(e.dateProfile),o=this.eventStoreToSegs(e.eventStore,e.eventUiBases,r),l=!e.forPrint&&!n.getIsHeightAuto(a);return i.createElement(n.ViewContainer,{elRef:this.setRootEl,className:"fc-list fc-flex-col fc-border",viewSpec:t.viewSpec},i.createElement(n.Scroller,{vertical:l,className:l?"fc-liquid":""},o.length>0?this.renderSegList(o,s):this.renderEmptyMessage()))}renderEmptyMessage(){let{options:e,viewApi:t}=this.context,a={text:e.noEventsText,view:t};return i.createElement(n.ContentContainer,{tag:"div",className:"fc-list-empty",renderProps:a,generatorName:"noEventsContent",customGenerator:e.noEventsContent,defaultGenerator:u,classNameGenerator:e.noEventsClassNames,didMount:e.noEventsDidMount,willUnmount:e.noEventsWillUnmount},e=>i.createElement(e,{tag:"div",className:"fc-list-empty-inner"}))}renderSegList(e,t){let a=function(e){let t,n,i=[];for(t=0;t<e.length;t+=1)n=e[t],(i[n.dayIndex]||(i[n.dayIndex]=[])).push(n);return i}(e);return i.createElement(n.NowTimer,{unit:"day"},(e,s)=>{const r=[];for(let o=0;o<a.length;o+=1){let l=a[o];if(l){const a=t[o],d=n.formatDayString(a);r.push(i.createElement(c,{key:d,dayDate:a,nowDate:e,todayRange:s,segs:l,forPrint:this.props.forPrint,timeWidthRef:this.timeWidthRefMap.createRef(d),timeOuterWidth:this.state.timeOuterWidth}))}}return i.createElement(i.Fragment,null,r)})}_eventStoreToSegs(e,t,i){return this.eventRangesToSegs(n.sliceEventStore(e,t,this.props.dateProfile.activeRange,this.context.options.nextDayThreshold).fg,i)}eventRangesToSegs(e,t){let n=[];for(let i of e)n.push(...this.eventRangeToSegs(i,t));return n}eventRangeToSegs(e,t){let i,a=e.range,s=[];for(i=0;i<t.length;i+=1){const r=n.intersectRanges(a,t[i]);r&&s.push({eventRange:e,slicedStart:r.start,slicedEnd:r.end,isStart:e.isStart&&a.start.valueOf()===r.start.valueOf(),isEnd:e.isEnd&&a.end.valueOf()===r.end.valueOf(),dayIndex:i})}return s}}function u(e){return e.text}function f(e){let t=n.startOfDay(e.renderRange.start),i=e.renderRange.end,a=[],s=[];for(;t<i;)a.push(t),s.push({start:t,end:n.addDays(t,1)}),t=n.addDays(t,1);return{dayDates:a,dayRanges:s}}const h={listDayFormat:v,listDaySideFormat:v,noEventsClassNames:n.identity,noEventsContent:n.identity,noEventsDidMount:n.identity,noEventsWillUnmount:n.identity};function v(e){return!1===e?null:n.createFormatter(e)}n.injectStyles(":root{--fc-list-event-dot-width:10px;--fc-list-event-hover-bg-color:#f5f5f5}.fc-list-day,.fc-list-event-dot-outer,.fc-list-event-time,.fc-list-event-title{padding:8px 14px}.fc-direction-ltr .fc-list-event-dot-outer{padding-right:0}.fc-direction-rtl .fc-list-event-dot-outer{padding-left:0}.fc-list-empty{align-items:center;background-color:var(--fc-neutral-bg-color);display:flex;height:100%;justify-content:center}.fc-list-empty-inner{margin:5em 0}.fc-list-day,.fc-list-event:not(.fc-list-day-and-events:last-child .fc-list-event:last-child){border-bottom:1px solid var(--fc-border-color)}.fc-list-day-outer-sticky{background:var(--fc-page-bg-color);position:sticky;top:0}.fc-list-day{background:var(--fc-neutral-bg-color);display:flex;font-weight:700;justify-content:space-between}.fc-list-event{display:flex;flex-direction:row}a.fc-list-event{color:inherit;text-decoration:none}.fc-list-event:hover{background-color:var(--fc-list-event-hover-bg-color)}.fc-list-event-time-outer{display:flex;flex-direction:row}.fc-list-event-dot-outer,.fc-list-event-time{white-space:nowrap}.fc-list-event-dot{border:calc(var(--fc-list-event-dot-width)/2) solid var(--fc-event-border-color);border-radius:calc(var(--fc-list-event-dot-width)/2);box-sizing:content-box;display:inline-block;height:0;width:0}a.fc-list-event:hover .fc-list-event-title{text-decoration:underline}");var g=t.createPlugin({name:"@fullcalendar/list",optionRefiners:h,views:{list:{component:m,buttonTextKey:"list",listDayFormat:{month:"long",day:"numeric",year:"numeric"}},listDay:{type:"list",duration:{days:1},listDayFormat:{weekday:"long"}},listWeek:{type:"list",duration:{weeks:1},listDayFormat:{weekday:"long"},listDaySideFormat:{month:"long",day:"numeric",year:"numeric"}},listMonth:{type:"list",duration:{month:1},listDaySideFormat:{weekday:"long"}},listYear:{type:"list",duration:{year:1},listDaySideFormat:{weekday:"long"}}}}),y={__proto__:null,ListView:m};return t.globalPlugins.push(g),e.Internal=y,e.default=g,Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,FullCalendar.Internal,FullCalendar.Preact);
6
+ FullCalendar.List=function(e,t,n,i){"use strict";class a extends n.BaseComponent{render(){let{dateEnv:e,options:t,viewApi:a}=this.context,{dayDate:r,todayRange:l}=this.props,o=!this.props.forPrint&&n.getStickyHeaderDates(t),d=n.getDateMeta(r,l),c=t.listDayFormat?e.format(r,t.listDayFormat):"",m=t.listDaySideFormat?e.format(r,t.listDaySideFormat):"",u=t.navLinks,f=Object.assign({date:e.toDate(r),view:a,text:c,sideText:m,navLinkAttrs:u?n.buildNavLinkAttrs(this.context,r,void 0,c):{},sideNavLinkAttrs:u?n.buildNavLinkAttrs(this.context,r,void 0,m,!1):{}},d);return i.createElement("div",{className:n.joinClassNames("fc-list-day-outer",o&&"fc-list-day-outer-sticky")},i.createElement(n.ContentContainer,{tag:"div",className:n.joinClassNames("fc-list-day",n.getDayClassName(d)),attrs:Object.assign({"data-date":n.formatDayString(r)},d.isToday?{"aria-current":"date"}:{}),renderProps:f,generatorName:"dayHeaderContent",customGenerator:t.dayHeaderContent,defaultGenerator:s,classNameGenerator:t.dayHeaderClassNames,didMount:t.dayHeaderDidMount,willUnmount:t.dayHeaderWillUnmount}))}}function s(e){return i.createElement(i.Fragment,null,e.text&&i.createElement("div",Object.assign({className:"fc-list-day-text"},e.navLinkAttrs),e.text),e.sideText&&i.createElement("div",Object.assign({className:"fc-list-day-side-text"},e.sideNavLinkAttrs),e.sideText))}const r=n.createFormatter({hour:"numeric",minute:"2-digit",meridiem:"short"});class l extends n.BaseComponent{constructor(){super(...arguments),this.handleTitleEl=e=>{this.disconnectTitleWidth&&this.disconnectTitleWidth(),e&&(this.disconnectTitleWidth=n.watchWidth(e,e=>{n.setRef(this.props.timeWidthRef,e)}))}}render(){let{props:e,context:t}=this,{eventRange:a}=e,{options:s}=t,l=s.eventTimeFormat||r,[d,c]=n.getEventTagAndAttrs(a,t);return i.createElement(n.EventContainer,Object.assign({},e,{tag:d,attrs:Object.assign({role:"listitem"},c),className:"fc-list-event",defaultGenerator:o,eventRange:a,timeText:"",disableDragging:!0,disableResizing:!0}),(n,s)=>i.createElement(i.Fragment,null,i.createElement("div",{className:"fc-list-event-time-outer",style:{width:e.timeOuterWidth}},this.buildTimeContent(a,e.slicedStart,e.slicedEnd,e.isStart,e.isEnd,l,t)),i.createElement("div",{className:"fc-list-event-dot-outer"},i.createElement("span",{className:"fc-list-event-dot",style:{borderColor:s.borderColor||s.backgroundColor}})),i.createElement(n,{tag:"div",className:"fc-list-event-title"})))}buildTimeContent(e,t,a,s,r,l,o){let{options:c}=o;if(!1!==c.displayEventTime){if(e.def.allDay||!s&&!r){let e={text:o.options.allDayText,view:o.viewApi};return i.createElement(n.ContentContainer,{tag:"div",className:"fc-list-event-time",renderProps:e,elRef:this.handleTitleEl,generatorName:"allDayContent",customGenerator:c.allDayContent,defaultGenerator:d,classNameGenerator:c.allDayClassNames,didMount:c.allDayDidMount,willUnmount:c.allDayWillUnmount})}return i.createElement("div",{className:"fc-list-event-time",ref:this.handleTitleEl},n.buildEventRangeTimeText(l,e,t,a,s,r,o))}return null}componentWillUnmount(){n.setRef(this.props.timeWidthRef,null)}}function o(e){return e.event.title}function d(e){return e.text}class c extends n.BaseComponent{constructor(){super(...arguments),this.sortEventSegs=n.memoize(n.sortEventSegs),this.timeWidthRefMap=new n.RefMap(()=>{n.afterSize(this.handleTimeWidths)}),this.handleTimeWidths=()=>{const e=this.timeWidthRefMap.current;let t=0;for(const n of e.values())t=Math.max(t,n);n.setRef(this.props.timeWidthRef,t)}}render(){const{props:e,context:t,timeWidthRefMap:s}=this,{nowDate:r,todayRange:o}=e,{options:d}=t,c=this.sortEventSegs(e.segs,d.eventOrder),m=n.buildDateStr(this.context,e.dayDate);return i.createElement("div",{role:"listitem","aria-label":m,className:"fc-list-day-and-events"},i.createElement(a,{dayDate:e.dayDate,todayRange:o,forPrint:e.forPrint}),i.createElement("div",{role:"list","aria-label":d.eventsHint},c.map(t=>{const a=n.getEventKey(t);return i.createElement(l,Object.assign({key:a,eventRange:t.eventRange,slicedStart:t.slicedStart,slicedEnd:t.slicedEnd,isStart:t.isStart,isEnd:t.isEnd,timeWidthRef:s.createRef(a),timeOuterWidth:e.timeOuterWidth,isDragging:!1,isResizing:!1,isDateSelecting:!1,isSelected:!1},n.getEventRangeMeta(t.eventRange,o,r)))})))}componentWillUnmount(){n.setRef(this.props.timeWidthRef,null)}}class m extends n.DateComponent{constructor(){super(...arguments),this.computeDateVars=n.memoize(f),this.eventStoreToSegs=n.memoize(this._eventStoreToSegs),this.timeWidthRefMap=new n.RefMap(()=>{n.afterSize(this.handleTimeWidths)}),this.setRootEl=e=>{e?this.context.registerInteractiveComponent(this,{el:e,disableHits:!0}):this.context.unregisterInteractiveComponent(this)},this.handleTimeWidths=()=>{const e=this.timeWidthRefMap.current;let t=0;for(const n of e.values())t=Math.max(t,n);this.setState({timeOuterWidth:t})}}render(){let{props:e,context:t}=this,{options:a}=t,{dayDates:s,dayRanges:r}=this.computeDateVars(e.dateProfile),l=this.eventStoreToSegs(e.eventStore,e.eventUiBases,r),o=!e.forPrint&&!n.getIsHeightAuto(a);return i.createElement(n.ViewContainer,{viewSpec:t.viewSpec,className:"fc-list fc-flex-col fc-border",elRef:this.setRootEl},i.createElement(n.Scroller,{vertical:o,className:o?"fc-liquid":""},this.renderSegList(l,s),!l.length&&this.renderEmptyMessage()))}renderEmptyMessage(){let{options:e,viewApi:t}=this.context,a={text:e.noEventsText,view:t};return i.createElement(n.ContentContainer,{tag:"div",attrs:{role:"status"},className:"fc-list-empty",renderProps:a,generatorName:"noEventsContent",customGenerator:e.noEventsContent,defaultGenerator:u,classNameGenerator:e.noEventsClassNames,didMount:e.noEventsDidMount,willUnmount:e.noEventsWillUnmount},e=>i.createElement(e,{tag:"div",className:"fc-list-empty-inner"}))}renderSegList(e,t){let a=function(e){let t,n,i=[];for(t=0;t<e.length;t+=1)n=e[t],(i[n.dayIndex]||(i[n.dayIndex]=[])).push(n);return i}(e);return i.createElement("div",{role:"list","aria-labelledby":this.props.labelId,"aria-label":this.props.labelStr},i.createElement(n.NowTimer,{unit:"day"},(e,s)=>{const r=[];for(let l=0;l<a.length;l+=1){let o=a[l];if(o){const a=t[l],d=n.formatDayString(a);r.push(i.createElement(c,{key:d,dayDate:a,nowDate:e,todayRange:s,segs:o,forPrint:this.props.forPrint,timeWidthRef:this.timeWidthRefMap.createRef(d),timeOuterWidth:this.state.timeOuterWidth}))}}return i.createElement(i.Fragment,null,r)}))}_eventStoreToSegs(e,t,i){return this.eventRangesToSegs(n.sliceEventStore(e,t,this.props.dateProfile.activeRange,this.context.options.nextDayThreshold).fg,i)}eventRangesToSegs(e,t){let n=[];for(let i of e)n.push(...this.eventRangeToSegs(i,t));return n}eventRangeToSegs(e,t){let i,a=e.range,s=[];for(i=0;i<t.length;i+=1){const r=n.intersectRanges(a,t[i]);r&&s.push({eventRange:e,slicedStart:r.start,slicedEnd:r.end,isStart:e.isStart&&a.start.valueOf()===r.start.valueOf(),isEnd:e.isEnd&&a.end.valueOf()===r.end.valueOf(),dayIndex:i})}return s}}function u(e){return e.text}function f(e){let t=n.startOfDay(e.renderRange.start),i=e.renderRange.end,a=[],s=[];for(;t<i;)a.push(t),s.push({start:t,end:n.addDays(t,1)}),t=n.addDays(t,1);return{dayDates:a,dayRanges:s}}const h={listDayFormat:v,listDaySideFormat:v,noEventsClassNames:n.identity,noEventsContent:n.identity,noEventsDidMount:n.identity,noEventsWillUnmount:n.identity};function v(e){return!1===e?null:n.createFormatter(e)}n.injectStyles(":root{--fc-list-event-dot-width:10px;--fc-list-event-hover-bg-color:#f5f5f5}.fc-list-day,.fc-list-event-dot-outer,.fc-list-event-time,.fc-list-event-title{padding:8px 14px}.fc-direction-ltr .fc-list-event-dot-outer{padding-right:0}.fc-direction-rtl .fc-list-event-dot-outer{padding-left:0}.fc-list-empty{align-items:center;background-color:var(--fc-neutral-bg-color);display:flex;height:100%;justify-content:center}.fc-list-empty-inner{margin:5em 0}.fc-list-day,.fc-list-event:not(.fc-list-day-and-events:last-child .fc-list-event:last-child){border-bottom:1px solid var(--fc-border-color)}.fc-list-day-outer-sticky{background:var(--fc-page-bg-color);position:sticky;top:0}.fc-list-day{background:var(--fc-neutral-bg-color);display:flex;font-weight:700;justify-content:space-between}.fc-list-event{display:flex;flex-direction:row}a.fc-list-event{color:inherit;text-decoration:none}.fc-list-event:hover{background-color:var(--fc-list-event-hover-bg-color)}.fc-list-event-time-outer{display:flex;flex-direction:row}.fc-list-event-dot-outer,.fc-list-event-time{white-space:nowrap}.fc-list-event-dot{border:calc(var(--fc-list-event-dot-width)/2) solid var(--fc-event-border-color);border-radius:calc(var(--fc-list-event-dot-width)/2);box-sizing:content-box;display:inline-block;height:0;width:0}a.fc-list-event:hover .fc-list-event-title{text-decoration:underline}");var g=t.createPlugin({name:"@fullcalendar/list",optionRefiners:h,views:{list:{component:m,buttonTextKey:"list",listDayFormat:{month:"long",day:"numeric",year:"numeric"}},listDay:{type:"list",duration:{days:1},listDayFormat:{weekday:"long"}},listWeek:{type:"list",duration:{weeks:1},listDayFormat:{weekday:"long"},listDaySideFormat:{month:"long",day:"numeric",year:"numeric"}},listMonth:{type:"list",duration:{month:1},listDaySideFormat:{weekday:"long"}},listYear:{type:"list",duration:{year:1},listDaySideFormat:{weekday:"long"}}}}),y={__proto__:null,ListView:m};return t.globalPlugins.push(g),e.Internal=y,e.default=g,Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,FullCalendar.Internal,FullCalendar.Preact);
package/internal.cjs CHANGED
@@ -15,19 +15,23 @@ class ListDayHeader extends internal_cjs.BaseComponent {
15
15
  let text = options.listDayFormat ? dateEnv.format(dayDate, options.listDayFormat) : '';
16
16
  // will ever be falsy? also, BAD NAME "alt"
17
17
  let sideText = options.listDaySideFormat ? dateEnv.format(dayDate, options.listDaySideFormat) : '';
18
+ let isNavLink = options.navLinks;
18
19
  let renderProps = Object.assign({ date: dateEnv.toDate(dayDate), view: viewApi, text,
19
- sideText, navLinkAttrs: internal_cjs.buildNavLinkAttrs(this.context, dayDate), sideNavLinkAttrs: internal_cjs.buildNavLinkAttrs(this.context, dayDate, 'day', false) }, dayMeta);
20
+ sideText, navLinkAttrs: isNavLink
21
+ ? internal_cjs.buildNavLinkAttrs(this.context, dayDate, undefined, text)
22
+ : {}, sideNavLinkAttrs: isNavLink
23
+ // duplicate navLink, so does not need to be tabbable
24
+ ? internal_cjs.buildNavLinkAttrs(this.context, dayDate, undefined, sideText, /* isTabbable = */ false)
25
+ : {} }, dayMeta);
20
26
  // TODO: make a reusable HOC for dayHeader (used in daygrid/timegrid too)
21
27
  return (preact_cjs.createElement("div", { className: internal_cjs.joinClassNames('fc-list-day-outer', stickyHeaderDates && 'fc-list-day-outer-sticky') },
22
- preact_cjs.createElement(internal_cjs.ContentContainer, { tag: "div", className: internal_cjs.joinClassNames('fc-list-day', internal_cjs.getDayClassName(dayMeta)), attrs: {
23
- 'data-date': internal_cjs.formatDayString(dayDate),
24
- }, renderProps: renderProps, generatorName: "dayHeaderContent", customGenerator: options.dayHeaderContent, defaultGenerator: renderInnerContent, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount })));
28
+ preact_cjs.createElement(internal_cjs.ContentContainer, { tag: "div", className: internal_cjs.joinClassNames('fc-list-day', internal_cjs.getDayClassName(dayMeta)), attrs: Object.assign({ 'data-date': internal_cjs.formatDayString(dayDate) }, (dayMeta.isToday ? { 'aria-current': 'date' } : {})), renderProps: renderProps, generatorName: "dayHeaderContent", customGenerator: options.dayHeaderContent, defaultGenerator: renderInnerContent, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount })));
25
29
  }
26
30
  }
27
31
  function renderInnerContent(props) {
28
32
  return (preact_cjs.createElement(preact_cjs.Fragment, null,
29
- props.text && (preact_cjs.createElement("a", Object.assign({ id: props.textId, className: "fc-list-day-text" }, props.navLinkAttrs), props.text)),
30
- props.sideText && ( /* not keyboard tabbable */preact_cjs.createElement("a", Object.assign({ className: "fc-list-day-side-text" }, props.sideNavLinkAttrs), props.sideText))));
33
+ props.text && (preact_cjs.createElement("div", Object.assign({ className: "fc-list-day-text" }, props.navLinkAttrs), props.text)),
34
+ props.sideText && (preact_cjs.createElement("div", Object.assign({ className: "fc-list-day-side-text" }, props.sideNavLinkAttrs), props.sideText))));
31
35
  }
32
36
 
33
37
  const DEFAULT_TIME_FORMAT = internal_cjs.createFormatter({
@@ -54,8 +58,8 @@ class ListEvent extends internal_cjs.BaseComponent {
54
58
  let { eventRange } = props;
55
59
  let { options } = context;
56
60
  let timeFormat = options.eventTimeFormat || DEFAULT_TIME_FORMAT;
57
- let anchorAttrs = internal_cjs.getEventRangeAnchorAttrs(eventRange, context);
58
- return (preact_cjs.createElement(internal_cjs.EventContainer, Object.assign({}, props, { tag: anchorAttrs ? 'a' : 'div', attrs: anchorAttrs, className: 'fc-list-event', defaultGenerator: renderEventTitleOnly, eventRange: eventRange, timeText: "", disableDragging: true, disableResizing: true }), (InnerContent, eventContentArg) => (preact_cjs.createElement(preact_cjs.Fragment, null,
61
+ let [tag, attrs] = internal_cjs.getEventTagAndAttrs(eventRange, context);
62
+ return (preact_cjs.createElement(internal_cjs.EventContainer, Object.assign({}, props, { tag: tag, attrs: Object.assign({ role: 'listitem' }, attrs), className: 'fc-list-event', defaultGenerator: renderEventTitleOnly, eventRange: eventRange, timeText: "", disableDragging: true, disableResizing: true }), (InnerContent, eventContentArg) => (preact_cjs.createElement(preact_cjs.Fragment, null,
59
63
  preact_cjs.createElement("div", { className: 'fc-list-event-time-outer', style: { width: props.timeOuterWidth } }, this.buildTimeContent(eventRange, props.slicedStart, props.slicedEnd, props.isStart, props.isEnd, timeFormat, context)),
60
64
  preact_cjs.createElement("div", { className: "fc-list-event-dot-outer" },
61
65
  preact_cjs.createElement("span", { className: "fc-list-event-dot", style: {
@@ -116,12 +120,13 @@ class ListDay extends internal_cjs.BaseComponent {
116
120
  const { nowDate, todayRange } = props;
117
121
  const { options } = context;
118
122
  const segs = this.sortEventSegs(props.segs, options.eventOrder);
119
- return (preact_cjs.createElement("div", { className: 'fc-list-day-and-events' },
123
+ const fullDateStr = internal_cjs.buildDateStr(this.context, props.dayDate);
124
+ return (preact_cjs.createElement("div", { role: 'listitem', "aria-label": fullDateStr, className: 'fc-list-day-and-events' },
120
125
  preact_cjs.createElement(ListDayHeader, { dayDate: props.dayDate, todayRange: todayRange, forPrint: props.forPrint }),
121
- segs.map((seg) => {
126
+ preact_cjs.createElement("div", { role: 'list', "aria-label": options.eventsHint }, segs.map((seg) => {
122
127
  const key = internal_cjs.getEventKey(seg);
123
128
  return (preact_cjs.createElement(ListEvent, Object.assign({ key: key, eventRange: seg.eventRange, slicedStart: seg.slicedStart, slicedEnd: seg.slicedEnd, isStart: seg.isStart, isEnd: seg.isEnd, timeWidthRef: timeWidthRefMap.createRef(key), timeOuterWidth: props.timeOuterWidth, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: false }, internal_cjs.getEventRangeMeta(seg.eventRange, todayRange, nowDate))));
124
- })));
129
+ }))));
125
130
  }
126
131
  componentWillUnmount() {
127
132
  internal_cjs.setRef(this.props.timeWidthRef, null);
@@ -167,11 +172,11 @@ class ListView extends internal_cjs.DateComponent {
167
172
  let { dayDates, dayRanges } = this.computeDateVars(props.dateProfile);
168
173
  let eventSegs = this.eventStoreToSegs(props.eventStore, props.eventUiBases, dayRanges);
169
174
  let verticalScrolling = !props.forPrint && !internal_cjs.getIsHeightAuto(options);
170
- return (preact_cjs.createElement(internal_cjs.ViewContainer, { elRef: this.setRootEl, className: 'fc-list fc-flex-col fc-border', viewSpec: context.viewSpec },
175
+ return (preact_cjs.createElement(internal_cjs.ViewContainer, { viewSpec: context.viewSpec, className: 'fc-list fc-flex-col fc-border', elRef: this.setRootEl },
171
176
  preact_cjs.createElement(internal_cjs.Scroller // TODO: don't need heavyweight component
172
- , { vertical: verticalScrolling, className: verticalScrolling ? 'fc-liquid' : '' }, eventSegs.length > 0 ?
173
- this.renderSegList(eventSegs, dayDates) :
174
- this.renderEmptyMessage())));
177
+ , { vertical: verticalScrolling, className: verticalScrolling ? 'fc-liquid' : '' },
178
+ this.renderSegList(eventSegs, dayDates),
179
+ !eventSegs.length && this.renderEmptyMessage())));
175
180
  }
176
181
  renderEmptyMessage() {
177
182
  let { options, viewApi } = this.context;
@@ -179,22 +184,25 @@ class ListView extends internal_cjs.DateComponent {
179
184
  text: options.noEventsText,
180
185
  view: viewApi,
181
186
  };
182
- return (preact_cjs.createElement(internal_cjs.ContentContainer, { tag: "div", className: 'fc-list-empty', renderProps: renderProps, generatorName: "noEventsContent", customGenerator: options.noEventsContent, defaultGenerator: renderNoEventsInner, classNameGenerator: options.noEventsClassNames, didMount: options.noEventsDidMount, willUnmount: options.noEventsWillUnmount }, (InnerContent) => (preact_cjs.createElement(InnerContent, { tag: "div", className: 'fc-list-empty-inner' }))));
187
+ return (preact_cjs.createElement(internal_cjs.ContentContainer, { tag: "div", attrs: {
188
+ role: 'status', // does a polite announcement
189
+ }, className: 'fc-list-empty', renderProps: renderProps, generatorName: "noEventsContent", customGenerator: options.noEventsContent, defaultGenerator: renderNoEventsInner, classNameGenerator: options.noEventsClassNames, didMount: options.noEventsDidMount, willUnmount: options.noEventsWillUnmount }, (InnerContent) => (preact_cjs.createElement(InnerContent, { tag: "div", className: 'fc-list-empty-inner' }))));
183
190
  }
184
191
  renderSegList(allSegs, dayDates) {
185
192
  let segsByDay = groupSegsByDay(allSegs); // sparse array
186
- return (preact_cjs.createElement(internal_cjs.NowTimer, { unit: "day" }, (nowDate, todayRange) => {
187
- const dayNodes = [];
188
- for (let dayIndex = 0; dayIndex < segsByDay.length; dayIndex += 1) {
189
- let daySegs = segsByDay[dayIndex];
190
- if (daySegs) { // sparse array, so might be undefined
191
- const dayDate = dayDates[dayIndex];
192
- const key = internal_cjs.formatDayString(dayDate);
193
- dayNodes.push(preact_cjs.createElement(ListDay, { key: key, dayDate: dayDate, nowDate: nowDate, todayRange: todayRange, segs: daySegs, forPrint: this.props.forPrint, timeWidthRef: this.timeWidthRefMap.createRef(key), timeOuterWidth: this.state.timeOuterWidth }));
193
+ return (preact_cjs.createElement("div", { role: 'list', "aria-labelledby": this.props.labelId, "aria-label": this.props.labelStr },
194
+ preact_cjs.createElement(internal_cjs.NowTimer, { unit: "day" }, (nowDate, todayRange) => {
195
+ const dayNodes = [];
196
+ for (let dayIndex = 0; dayIndex < segsByDay.length; dayIndex += 1) {
197
+ let daySegs = segsByDay[dayIndex];
198
+ if (daySegs) { // sparse array, so might be undefined
199
+ const dayDate = dayDates[dayIndex];
200
+ const key = internal_cjs.formatDayString(dayDate);
201
+ dayNodes.push(preact_cjs.createElement(ListDay, { key: key, dayDate: dayDate, nowDate: nowDate, todayRange: todayRange, segs: daySegs, forPrint: this.props.forPrint, timeWidthRef: this.timeWidthRefMap.createRef(key), timeOuterWidth: this.state.timeOuterWidth }));
202
+ }
194
203
  }
195
- }
196
- return (preact_cjs.createElement(preact_cjs.Fragment, null, dayNodes));
197
- }));
204
+ return (preact_cjs.createElement(preact_cjs.Fragment, null, dayNodes));
205
+ })));
198
206
  }
199
207
  _eventStoreToSegs(eventStore, eventUiBases, dayRanges) {
200
208
  return this.eventRangesToSegs(internal_cjs.sliceEventStore(eventStore, eventUiBases,
package/internal.js CHANGED
@@ -1,4 +1,4 @@
1
- import { BaseComponent, getStickyHeaderDates, getDateMeta, buildNavLinkAttrs, joinClassNames, ContentContainer, getDayClassName, formatDayString, createFormatter, watchWidth, setRef, getEventRangeAnchorAttrs, EventContainer, buildEventRangeTimeText, memoize, sortEventSegs, RefMap, afterSize, getEventKey, getEventRangeMeta, DateComponent, getIsHeightAuto, ViewContainer, Scroller, NowTimer, sliceEventStore, intersectRanges, startOfDay, addDays, injectStyles } from '@fullcalendar/core/internal.js';
1
+ import { BaseComponent, getStickyHeaderDates, getDateMeta, buildNavLinkAttrs, joinClassNames, ContentContainer, getDayClassName, formatDayString, createFormatter, watchWidth, setRef, getEventTagAndAttrs, EventContainer, buildEventRangeTimeText, memoize, sortEventSegs, RefMap, afterSize, buildDateStr, getEventKey, getEventRangeMeta, DateComponent, getIsHeightAuto, ViewContainer, Scroller, NowTimer, sliceEventStore, intersectRanges, startOfDay, addDays, injectStyles } from '@fullcalendar/core/internal.js';
2
2
  import { createElement, Fragment } from '@fullcalendar/core/preact.js';
3
3
 
4
4
  class ListDayHeader extends BaseComponent {
@@ -11,19 +11,23 @@ class ListDayHeader extends BaseComponent {
11
11
  let text = options.listDayFormat ? dateEnv.format(dayDate, options.listDayFormat) : '';
12
12
  // will ever be falsy? also, BAD NAME "alt"
13
13
  let sideText = options.listDaySideFormat ? dateEnv.format(dayDate, options.listDaySideFormat) : '';
14
+ let isNavLink = options.navLinks;
14
15
  let renderProps = Object.assign({ date: dateEnv.toDate(dayDate), view: viewApi, text,
15
- sideText, navLinkAttrs: buildNavLinkAttrs(this.context, dayDate), sideNavLinkAttrs: buildNavLinkAttrs(this.context, dayDate, 'day', false) }, dayMeta);
16
+ sideText, navLinkAttrs: isNavLink
17
+ ? buildNavLinkAttrs(this.context, dayDate, undefined, text)
18
+ : {}, sideNavLinkAttrs: isNavLink
19
+ // duplicate navLink, so does not need to be tabbable
20
+ ? buildNavLinkAttrs(this.context, dayDate, undefined, sideText, /* isTabbable = */ false)
21
+ : {} }, dayMeta);
16
22
  // TODO: make a reusable HOC for dayHeader (used in daygrid/timegrid too)
17
23
  return (createElement("div", { className: joinClassNames('fc-list-day-outer', stickyHeaderDates && 'fc-list-day-outer-sticky') },
18
- createElement(ContentContainer, { tag: "div", className: joinClassNames('fc-list-day', getDayClassName(dayMeta)), attrs: {
19
- 'data-date': formatDayString(dayDate),
20
- }, renderProps: renderProps, generatorName: "dayHeaderContent", customGenerator: options.dayHeaderContent, defaultGenerator: renderInnerContent, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount })));
24
+ createElement(ContentContainer, { tag: "div", className: joinClassNames('fc-list-day', getDayClassName(dayMeta)), attrs: Object.assign({ 'data-date': formatDayString(dayDate) }, (dayMeta.isToday ? { 'aria-current': 'date' } : {})), renderProps: renderProps, generatorName: "dayHeaderContent", customGenerator: options.dayHeaderContent, defaultGenerator: renderInnerContent, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount })));
21
25
  }
22
26
  }
23
27
  function renderInnerContent(props) {
24
28
  return (createElement(Fragment, null,
25
- props.text && (createElement("a", Object.assign({ id: props.textId, className: "fc-list-day-text" }, props.navLinkAttrs), props.text)),
26
- props.sideText && ( /* not keyboard tabbable */createElement("a", Object.assign({ className: "fc-list-day-side-text" }, props.sideNavLinkAttrs), props.sideText))));
29
+ props.text && (createElement("div", Object.assign({ className: "fc-list-day-text" }, props.navLinkAttrs), props.text)),
30
+ props.sideText && (createElement("div", Object.assign({ className: "fc-list-day-side-text" }, props.sideNavLinkAttrs), props.sideText))));
27
31
  }
28
32
 
29
33
  const DEFAULT_TIME_FORMAT = createFormatter({
@@ -50,8 +54,8 @@ class ListEvent extends BaseComponent {
50
54
  let { eventRange } = props;
51
55
  let { options } = context;
52
56
  let timeFormat = options.eventTimeFormat || DEFAULT_TIME_FORMAT;
53
- let anchorAttrs = getEventRangeAnchorAttrs(eventRange, context);
54
- return (createElement(EventContainer, Object.assign({}, props, { tag: anchorAttrs ? 'a' : 'div', attrs: anchorAttrs, className: 'fc-list-event', defaultGenerator: renderEventTitleOnly, eventRange: eventRange, timeText: "", disableDragging: true, disableResizing: true }), (InnerContent, eventContentArg) => (createElement(Fragment, null,
57
+ let [tag, attrs] = getEventTagAndAttrs(eventRange, context);
58
+ return (createElement(EventContainer, Object.assign({}, props, { tag: tag, attrs: Object.assign({ role: 'listitem' }, attrs), className: 'fc-list-event', defaultGenerator: renderEventTitleOnly, eventRange: eventRange, timeText: "", disableDragging: true, disableResizing: true }), (InnerContent, eventContentArg) => (createElement(Fragment, null,
55
59
  createElement("div", { className: 'fc-list-event-time-outer', style: { width: props.timeOuterWidth } }, this.buildTimeContent(eventRange, props.slicedStart, props.slicedEnd, props.isStart, props.isEnd, timeFormat, context)),
56
60
  createElement("div", { className: "fc-list-event-dot-outer" },
57
61
  createElement("span", { className: "fc-list-event-dot", style: {
@@ -112,12 +116,13 @@ class ListDay extends BaseComponent {
112
116
  const { nowDate, todayRange } = props;
113
117
  const { options } = context;
114
118
  const segs = this.sortEventSegs(props.segs, options.eventOrder);
115
- return (createElement("div", { className: 'fc-list-day-and-events' },
119
+ const fullDateStr = buildDateStr(this.context, props.dayDate);
120
+ return (createElement("div", { role: 'listitem', "aria-label": fullDateStr, className: 'fc-list-day-and-events' },
116
121
  createElement(ListDayHeader, { dayDate: props.dayDate, todayRange: todayRange, forPrint: props.forPrint }),
117
- segs.map((seg) => {
122
+ createElement("div", { role: 'list', "aria-label": options.eventsHint }, segs.map((seg) => {
118
123
  const key = getEventKey(seg);
119
124
  return (createElement(ListEvent, Object.assign({ key: key, eventRange: seg.eventRange, slicedStart: seg.slicedStart, slicedEnd: seg.slicedEnd, isStart: seg.isStart, isEnd: seg.isEnd, timeWidthRef: timeWidthRefMap.createRef(key), timeOuterWidth: props.timeOuterWidth, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: false }, getEventRangeMeta(seg.eventRange, todayRange, nowDate))));
120
- })));
125
+ }))));
121
126
  }
122
127
  componentWillUnmount() {
123
128
  setRef(this.props.timeWidthRef, null);
@@ -163,11 +168,11 @@ class ListView extends DateComponent {
163
168
  let { dayDates, dayRanges } = this.computeDateVars(props.dateProfile);
164
169
  let eventSegs = this.eventStoreToSegs(props.eventStore, props.eventUiBases, dayRanges);
165
170
  let verticalScrolling = !props.forPrint && !getIsHeightAuto(options);
166
- return (createElement(ViewContainer, { elRef: this.setRootEl, className: 'fc-list fc-flex-col fc-border', viewSpec: context.viewSpec },
171
+ return (createElement(ViewContainer, { viewSpec: context.viewSpec, className: 'fc-list fc-flex-col fc-border', elRef: this.setRootEl },
167
172
  createElement(Scroller // TODO: don't need heavyweight component
168
- , { vertical: verticalScrolling, className: verticalScrolling ? 'fc-liquid' : '' }, eventSegs.length > 0 ?
169
- this.renderSegList(eventSegs, dayDates) :
170
- this.renderEmptyMessage())));
173
+ , { vertical: verticalScrolling, className: verticalScrolling ? 'fc-liquid' : '' },
174
+ this.renderSegList(eventSegs, dayDates),
175
+ !eventSegs.length && this.renderEmptyMessage())));
171
176
  }
172
177
  renderEmptyMessage() {
173
178
  let { options, viewApi } = this.context;
@@ -175,22 +180,25 @@ class ListView extends DateComponent {
175
180
  text: options.noEventsText,
176
181
  view: viewApi,
177
182
  };
178
- return (createElement(ContentContainer, { tag: "div", className: 'fc-list-empty', renderProps: renderProps, generatorName: "noEventsContent", customGenerator: options.noEventsContent, defaultGenerator: renderNoEventsInner, classNameGenerator: options.noEventsClassNames, didMount: options.noEventsDidMount, willUnmount: options.noEventsWillUnmount }, (InnerContent) => (createElement(InnerContent, { tag: "div", className: 'fc-list-empty-inner' }))));
183
+ return (createElement(ContentContainer, { tag: "div", attrs: {
184
+ role: 'status', // does a polite announcement
185
+ }, className: 'fc-list-empty', renderProps: renderProps, generatorName: "noEventsContent", customGenerator: options.noEventsContent, defaultGenerator: renderNoEventsInner, classNameGenerator: options.noEventsClassNames, didMount: options.noEventsDidMount, willUnmount: options.noEventsWillUnmount }, (InnerContent) => (createElement(InnerContent, { tag: "div", className: 'fc-list-empty-inner' }))));
179
186
  }
180
187
  renderSegList(allSegs, dayDates) {
181
188
  let segsByDay = groupSegsByDay(allSegs); // sparse array
182
- return (createElement(NowTimer, { unit: "day" }, (nowDate, todayRange) => {
183
- const dayNodes = [];
184
- for (let dayIndex = 0; dayIndex < segsByDay.length; dayIndex += 1) {
185
- let daySegs = segsByDay[dayIndex];
186
- if (daySegs) { // sparse array, so might be undefined
187
- const dayDate = dayDates[dayIndex];
188
- const key = formatDayString(dayDate);
189
- dayNodes.push(createElement(ListDay, { key: key, dayDate: dayDate, nowDate: nowDate, todayRange: todayRange, segs: daySegs, forPrint: this.props.forPrint, timeWidthRef: this.timeWidthRefMap.createRef(key), timeOuterWidth: this.state.timeOuterWidth }));
189
+ return (createElement("div", { role: 'list', "aria-labelledby": this.props.labelId, "aria-label": this.props.labelStr },
190
+ createElement(NowTimer, { unit: "day" }, (nowDate, todayRange) => {
191
+ const dayNodes = [];
192
+ for (let dayIndex = 0; dayIndex < segsByDay.length; dayIndex += 1) {
193
+ let daySegs = segsByDay[dayIndex];
194
+ if (daySegs) { // sparse array, so might be undefined
195
+ const dayDate = dayDates[dayIndex];
196
+ const key = formatDayString(dayDate);
197
+ dayNodes.push(createElement(ListDay, { key: key, dayDate: dayDate, nowDate: nowDate, todayRange: todayRange, segs: daySegs, forPrint: this.props.forPrint, timeWidthRef: this.timeWidthRefMap.createRef(key), timeOuterWidth: this.state.timeOuterWidth }));
198
+ }
190
199
  }
191
- }
192
- return (createElement(Fragment, null, dayNodes));
193
- }));
200
+ return (createElement(Fragment, null, dayNodes));
201
+ })));
194
202
  }
195
203
  _eventStoreToSegs(eventStore, eventUiBases, dayRanges) {
196
204
  return this.eventRangesToSegs(sliceEventStore(eventStore, eventUiBases,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fullcalendar/list",
3
- "version": "7.0.0-beta.3",
3
+ "version": "7.0.0-beta.4",
4
4
  "title": "FullCalendar List View Plugin",
5
5
  "description": "Display events on a calendar view that looks like a bulleted list",
6
6
  "keywords": [
@@ -12,7 +12,7 @@
12
12
  ],
13
13
  "homepage": "https://fullcalendar.io/docs/list-view",
14
14
  "peerDependencies": {
15
- "@fullcalendar/core": "7.0.0-beta.3"
15
+ "@fullcalendar/core": "7.0.0-beta.4"
16
16
  },
17
17
  "type": "module",
18
18
  "bugs": "https://fullcalendar.io/reporting-bugs",