@fullcalendar/daygrid 7.0.0-beta.3 → 7.0.0-beta.5

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.
@@ -1,5 +1,7 @@
1
- import { Slicer, createFormatter, getDateMeta, formatDayString, buildNavLinkAttrs, getDayClassName, addDays, getEventKey, BaseComponent, StandardEvent, buildEventRangeTimeText, getEventRangeAnchorAttrs, EventContainer, MoreLinkContainer, joinClassNames, getEventRangeMeta, DateComponent, DayCellContainer, hasCustomDayCellContent, watchSize, isDimsEqual, setRef, addMs, SegHierarchy, DaySeriesModel, DayTableModel, fracToCssDim, watchHeight, RefMap, afterSize, sortEventSegs, WeekNumberContainer, buildEventRangeKey, BgEvent, renderFill, memoize, getIsHeightAuto, watchWidth, ContentContainer, renderText, getStickyHeaderDates, Scroller, getStickyFooterScrollbar, StickyFooterScrollbar, getScrollerSyncerClass, ViewContainer, NowTimer, DateProfileGenerator, addWeeks, diffWeeks, injectStyles } from '@fullcalendar/core/internal.js';
2
- import { createElement, Fragment, createRef, Component } from '@fullcalendar/core/preact.js';
1
+ import { Slicer, computeMajorUnit, isMajorUnit, addDays, getDateMeta, findWeekdayText, findDayNumberText, buildDateStr, formatDayString, buildNavLinkAttrs, WEEKDAY_ONLY_FORMAT, getEventKey, createFormatter, BaseComponent, MoreLinkContainer, StandardEvent, getEventRangeMeta, DateComponent, memoize, memoizeObjArg, setRef, watchSize, isDimsEqual, joinArrayishClassNames, generateClassName, ContentContainer, addMs, findMonthText, SegHierarchy, DaySeriesModel, DayTableModel, fracToCssDim, watchHeight, RefMap, afterSize, sortEventSegs, renderText, buildEventRangeKey, BgEvent, renderFill, getIsHeightAuto, getStickyHeaderDates, Scroller, Ruler, getStickyFooterScrollbar, FooterScrollbar, getScrollerSyncerClass, ViewContainer, NowTimer, DateProfileGenerator, addWeeks, diffWeeks } from '@fullcalendar/core/internal';
2
+ import { createElement, Fragment, createRef, Component } from '@fullcalendar/core/preact';
3
+ import { joinClassNames } from '@fullcalendar/core';
4
+ import classNames from '@fullcalendar/core/internal-classnames';
3
5
 
4
6
  class DayTableSlicer extends Slicer {
5
7
  constructor() {
@@ -16,55 +18,96 @@ class DayTableSlicer extends Slicer {
16
18
  // but can share some of the same types/utils
17
19
  // Date Cells
18
20
  // -------------------------------------------------------------------------------------------------
19
- const WEEKDAY_FORMAT = createFormatter({ weekday: 'long' });
20
21
  const firstSunday = new Date(259200000);
21
- function buildDateRowConfigs(...args) {
22
- return [buildDateRowConfig(...args)];
22
+ function buildDateRowConfigs(dates, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, // TODO: rename to dateHeaderFormat?
23
+ context) {
24
+ const rowConfig = buildDateRowConfig(dates, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, context);
25
+ const majorUnit = computeMajorUnit(dateProfile, context.dateEnv);
26
+ // HACK mutate isMajor
27
+ if (datesRepDistinctDays) {
28
+ for (const dataConfig of rowConfig.dataConfigs) {
29
+ if (isMajorUnit(dataConfig.dateMarker, majorUnit, context.dateEnv)) {
30
+ dataConfig.renderProps.isMajor = true;
31
+ }
32
+ }
33
+ }
34
+ return [rowConfig];
23
35
  }
24
36
  /*
25
37
  Should this receive resource data attributes?
26
38
  Or ResourceApi object itself?
27
39
  */
28
- function buildDateRowConfig(dates, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, // TODO: rename to dateHeaderFormat?
29
- context, colSpan) {
40
+ function buildDateRowConfig(dateMarkers, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, // TODO: rename to dateHeaderFormat?
41
+ context, colSpan, isMajorMod) {
30
42
  return {
43
+ isDateRow: true,
31
44
  renderConfig: buildDateRenderConfig(context),
32
- dataConfigs: buildDateDataConfigs(dates, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, context, colSpan)
45
+ dataConfigs: buildDateDataConfigs(dateMarkers, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, context, colSpan, undefined, undefined, undefined, undefined, isMajorMod)
33
46
  };
34
47
  }
48
+ /*
49
+ For header cells: how to connect w/ custom rendering
50
+ Applies to all cells in a row
51
+ */
35
52
  function buildDateRenderConfig(context) {
36
53
  const { options } = context;
37
54
  return {
38
55
  generatorName: 'dayHeaderContent',
39
56
  customGenerator: options.dayHeaderContent,
40
- classNameGenerator: options.dayHeaderClassNames,
57
+ classNameGenerator: options.dayHeaderClass,
58
+ innerClassNameGenerator: options.dayHeaderInnerClass,
41
59
  didMount: options.dayHeaderDidMount,
42
60
  willUnmount: options.dayHeaderWillUnmount,
61
+ align: options.dayHeaderAlign,
62
+ sticky: options.dayHeaderSticky,
43
63
  };
44
64
  }
45
- function buildDateDataConfigs(dates, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, // TODO: rename to dateHeaderFormat?
46
- context, colSpan = 1, keyPrefix = '') {
65
+ const dowDates = [];
66
+ for (let dow = 0; dow < 7; dow++) {
67
+ dowDates.push(addDays(new Date(259200000), dow)); // start with Sun, 04 Jan 1970 00:00:00 GMT)
68
+ }
69
+ /*
70
+ For header cells: data
71
+ */
72
+ function buildDateDataConfigs(dateMarkers, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, // TODO: rename to dateHeaderFormat?
73
+ context, colSpan = 1, keyPrefix = '', extraRenderProps = {}, // TODO
74
+ extraAttrs = {}, // TODO
75
+ className = '', isMajorMod) {
47
76
  const { dateEnv, viewApi, options } = context;
48
77
  return datesRepDistinctDays
49
- ? dates.map((date) => {
50
- const dateMeta = getDateMeta(date, todayRange, null, dateProfile);
51
- const text = dateEnv.format(date, dayHeaderFormat);
52
- const renderProps = Object.assign(Object.assign({}, dateMeta), { date: dateEnv.toDate(date), view: viewApi, text });
53
- const isNavLink = options.navLinks && !dateMeta.isDisabled;
78
+ ? dateMarkers.map((dateMarker, i) => {
79
+ const dateMeta = getDateMeta(dateMarker, dateEnv, dateProfile, todayRange);
80
+ const isMajor = isMajorMod != null && !(i % isMajorMod);
81
+ const [text, textParts] = dateEnv.format(dateMarker, dayHeaderFormat);
82
+ const hasNavLink = options.navLinks && !dateMeta.isDisabled &&
83
+ dateMarkers.length > 1; // don't show navlink to day if only one day
84
+ const renderProps = Object.assign(Object.assign(Object.assign({}, dateMeta), extraRenderProps), { text,
85
+ textParts,
86
+ get weekdayText() { return findWeekdayText(textParts); },
87
+ get dayNumberText() { return datesRepDistinctDays ? findDayNumberText(textParts) : ''; },
88
+ isMajor, isNarrow: false, isSticky: false, inPopover: false, level: 0, // HACK. gets overridden
89
+ hasNavLink, view: viewApi });
90
+ const fullDateStr = buildDateStr(context, dateMarker);
91
+ // for DayGridHeaderCell
54
92
  return {
55
- key: keyPrefix + date.toUTCString(),
93
+ key: keyPrefix + dateMarker.toUTCString(),
94
+ dateMarker,
56
95
  renderProps,
57
- attrs: { 'data-date': !dateMeta.isDisabled ? formatDayString(date) : undefined },
58
- innerAttrs: isNavLink ? buildNavLinkAttrs(context, date) : {},
96
+ attrs: Object.assign(Object.assign(Object.assign({ 'aria-label': fullDateStr }, (dateMeta.isToday ? { 'aria-current': 'date' } : {})), { 'data-date': formatDayString(dateMarker) }), extraAttrs),
97
+ // for navlink
98
+ innerAttrs: hasNavLink
99
+ ? buildNavLinkAttrs(context, dateMarker, undefined, fullDateStr)
100
+ : { 'aria-hidden': true },
59
101
  colSpan,
60
- isNavLink,
61
- className: getDayClassName(dateMeta),
102
+ hasNavLink,
103
+ className,
62
104
  };
63
105
  })
64
- : dates.map((date) => {
65
- const dow = date.getUTCDay();
106
+ : dateMarkers.map((dateMarker, i) => {
107
+ const dow = dateMarker.getUTCDay();
66
108
  const normDate = addDays(firstSunday, dow);
67
- const dayMeta = {
109
+ const dateMeta = {
110
+ date: dateEnv.toDate(dateMarker),
68
111
  dow,
69
112
  isDisabled: false,
70
113
  isFuture: false,
@@ -72,14 +115,25 @@ context, colSpan = 1, keyPrefix = '') {
72
115
  isToday: false,
73
116
  isOther: false,
74
117
  };
75
- const text = dateEnv.format(normDate, dayHeaderFormat);
76
- const renderProps = Object.assign(Object.assign({}, dayMeta), { date, view: viewApi, text });
118
+ const isMajor = isMajorMod != null && !(i % isMajorMod);
119
+ const [text, textParts] = dateEnv.format(normDate, dayHeaderFormat);
120
+ const renderProps = Object.assign(Object.assign(Object.assign({}, dateMeta), { date: dowDates[dow], isMajor, isNarrow: false, isSticky: false, inPopover: false, hasNavLink: false, level: 0, view: viewApi, text,
121
+ textParts,
122
+ get weekdayText() { return findWeekdayText(textParts); },
123
+ get dayNumberText() { return datesRepDistinctDays ? findDayNumberText(textParts) : ''; } }), extraRenderProps);
124
+ const fullWeekDayStr = dateEnv.format(normDate, WEEKDAY_ONLY_FORMAT)[0];
125
+ // for DayGridHeaderCell
77
126
  return {
78
127
  key: keyPrefix + String(dow),
128
+ dateMarker,
79
129
  renderProps,
80
- innerAttrs: { 'aria-label': dateEnv.format(normDate, WEEKDAY_FORMAT) },
130
+ attrs: Object.assign({ 'aria-label': fullWeekDayStr }, extraAttrs),
131
+ // NOT a navlink
132
+ innerAttrs: {
133
+ 'aria-hidden': true, // label already on cell
134
+ },
81
135
  colSpan,
82
- className: getDayClassName(dayMeta),
136
+ className,
83
137
  };
84
138
  });
85
139
  }
@@ -95,9 +149,9 @@ function getEventPartKey(seg) {
95
149
  }
96
150
  // DayGridRange utils (TODO: move)
97
151
  // -------------------------------------------------------------------------------------------------
98
- function splitSegsByRow(segs, rowCnt) {
152
+ function splitSegsByRow(segs, rowCount) {
99
153
  const byRow = [];
100
- for (let row = 0; row < rowCnt; row++) {
154
+ for (let row = 0; row < rowCount; row++) {
101
155
  byRow[row] = [];
102
156
  }
103
157
  for (const seg of segs) {
@@ -105,15 +159,15 @@ function splitSegsByRow(segs, rowCnt) {
105
159
  }
106
160
  return byRow;
107
161
  }
108
- function splitInteractionByRow(ui, rowCnt) {
162
+ function splitInteractionByRow(ui, rowCount) {
109
163
  const byRow = [];
110
164
  if (!ui) {
111
- for (let row = 0; row < rowCnt; row++) {
165
+ for (let row = 0; row < rowCount; row++) {
112
166
  byRow[row] = null;
113
167
  }
114
168
  }
115
169
  else {
116
- for (let row = 0; row < rowCnt; row++) {
170
+ for (let row = 0; row < rowCount; row++) {
117
171
  byRow[row] = {
118
172
  affectedInstances: ui.affectedInstances,
119
173
  isEvent: ui.isEvent,
@@ -146,61 +200,55 @@ function hasListItemDisplay(seg) {
146
200
  );
147
201
  }
148
202
 
149
- class DayGridBlockEvent extends BaseComponent {
150
- render() {
151
- let { props } = this;
152
- return (createElement(StandardEvent, Object.assign({}, props, { className: 'fc-daygrid-block-event fc-daygrid-event fc-h-event', defaultTimeFormat: DEFAULT_TABLE_EVENT_TIME_FORMAT, defaultDisplayEventEnd: props.defaultDisplayEventEnd, disableResizing: !props.eventRange.def.allDay })));
153
- }
154
- }
155
-
156
- class DayGridListEvent extends BaseComponent {
157
- render() {
158
- let { props, context } = this;
159
- let { options } = context;
160
- let { eventRange } = props;
161
- let timeFormat = options.eventTimeFormat || DEFAULT_TABLE_EVENT_TIME_FORMAT;
162
- let timeText = buildEventRangeTimeText(timeFormat, eventRange,
163
- /* slicedStart = */ undefined,
164
- /* slicedEnd = */ undefined, props.isStart, props.isEnd, context,
165
- /* defaultDisplayEventTime = */ true, props.defaultDisplayEventEnd);
166
- let anchorAttrs = getEventRangeAnchorAttrs(eventRange, context);
167
- return (createElement(EventContainer, Object.assign({}, props, { tag: anchorAttrs ? 'a' : 'div', attrs: anchorAttrs, className: 'fc-daygrid-dot-event fc-daygrid-event', defaultGenerator: renderInnerContent, timeText: timeText, isResizing: false, isDateSelecting: false })));
168
- }
169
- }
170
- function renderInnerContent(renderProps) {
171
- return (createElement(Fragment, null,
172
- createElement("div", { className: "fc-daygrid-event-dot", style: { borderColor: renderProps.borderColor || renderProps.backgroundColor } }),
173
- renderProps.timeText && (createElement("div", { className: "fc-event-time" }, renderProps.timeText)),
174
- createElement("div", { className: "fc-event-title" }, renderProps.event.title || createElement(Fragment, null, "\u00A0"))));
175
- }
176
-
177
203
  class DayGridMoreLink extends BaseComponent {
178
204
  render() {
179
205
  let { props } = this;
180
- return (createElement(MoreLinkContainer, { className: joinClassNames('fc-daygrid-more-link', props.isBlock
181
- ? 'fc-daygrid-more-link-block'
182
- : 'fc-daygrid-more-link-button'), dateProfile: props.dateProfile, todayRange: props.todayRange, allDayDate: props.allDayDate, segs: props.segs, hiddenSegs: props.hiddenSegs, alignElRef: props.alignElRef, alignParentTop: props.alignParentTop, dateSpanProps: props.dateSpanProps, popoverContent: () => {
183
- let forcedInvisibleMap = // TODO: more convenient/DRY
184
- (props.eventDrag ? props.eventDrag.affectedInstances : null) ||
185
- (props.eventResize ? props.eventResize.affectedInstances : null) ||
186
- {};
187
- return (createElement(Fragment, null, props.segs.map((seg) => {
188
- let { eventRange } = seg;
189
- let { instanceId } = eventRange.instance;
190
- return (createElement("div", { key: instanceId, style: {
191
- visibility: forcedInvisibleMap[instanceId] ? 'hidden' : '',
192
- } }, hasListItemDisplay(seg) ? (createElement(DayGridListEvent, Object.assign({ eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, getEventRangeMeta(eventRange, props.todayRange)))) : (createElement(DayGridBlockEvent, Object.assign({ eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, getEventRangeMeta(eventRange, props.todayRange))))));
193
- })));
194
- } }));
206
+ return (createElement(MoreLinkContainer, { display: 'row', className: props.className, isNarrow: props.isNarrow, isMicro: props.isMicro, dateProfile: props.dateProfile, todayRange: props.todayRange, allDayDate: props.allDayDate, segs: props.segs, hiddenSegs: props.hiddenSegs, alignElRef: props.alignElRef, alignParentTop: props.alignParentTop, dateSpanProps: props.dateSpanProps, popoverContent: () => (createElement(Fragment, null, props.segs.map((seg) => {
207
+ let { eventRange } = seg;
208
+ let { instanceId } = eventRange.instance;
209
+ let isDragging = Boolean(props.eventDrag && props.eventDrag.affectedInstances[instanceId]);
210
+ let isResizing = Boolean(props.eventResize && props.eventResize.affectedInstances[instanceId]);
211
+ let isInvisible = isDragging || isResizing;
212
+ return (createElement("div", { key: instanceId, style: {
213
+ visibility: isInvisible ? 'hidden' : undefined,
214
+ } },
215
+ createElement(StandardEvent, Object.assign({ display: hasListItemDisplay(seg) ? 'list-item' : 'row', eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: isDragging, isResizing: isResizing, isMirror: false, isSelected: instanceId === props.eventSelection, defaultTimeFormat: DEFAULT_TABLE_EVENT_TIME_FORMAT, defaultDisplayEventEnd: false }, getEventRangeMeta(eventRange, props.todayRange)))));
216
+ }))) }));
195
217
  }
196
218
  }
197
219
 
198
220
  class DayGridCell extends DateComponent {
199
221
  constructor() {
200
222
  super(...arguments);
223
+ // memo
224
+ this.getDateMeta = memoize(getDateMeta);
225
+ this.refineRenderProps = memoizeObjArg(refineRenderProps);
201
226
  // ref
202
227
  this.rootElRef = createRef();
203
- this.bodyElRef = createRef();
228
+ this.handleBodyEl = (bodyEl) => {
229
+ if (this.disconnectBodyHeight) {
230
+ this.disconnectBodyHeight();
231
+ this.disconnectBodyHeight = undefined;
232
+ setRef(this.props.headerHeightRef, null);
233
+ setRef(this.props.mainHeightRef, null);
234
+ }
235
+ if (bodyEl) {
236
+ // we want to fire on ANY size change, because we do more advanced stuff
237
+ this.disconnectBodyHeight = watchSize(bodyEl, (_bodyWidth, bodyHeight) => {
238
+ const { props } = this;
239
+ const mainRect = bodyEl.getBoundingClientRect();
240
+ const rootRect = this.rootElRef.current.getBoundingClientRect();
241
+ const headerHeight = mainRect.top - rootRect.top;
242
+ if (!isDimsEqual(this.headerHeight, headerHeight)) {
243
+ this.headerHeight = headerHeight;
244
+ setRef(props.headerHeightRef, headerHeight);
245
+ }
246
+ if (props.fgLiquidHeight) {
247
+ setRef(props.mainHeightRef, bodyHeight);
248
+ }
249
+ });
250
+ }
251
+ };
204
252
  }
205
253
  render() {
206
254
  let { props, context } = this;
@@ -208,43 +256,53 @@ class DayGridCell extends DateComponent {
208
256
  // TODO: memoize this
209
257
  const isMonthStart = props.showDayNumber &&
210
258
  shouldDisplayMonthStart(props.date, props.dateProfile.currentRange, dateEnv);
211
- return (createElement(DayCellContainer, { tag: "div", className: joinClassNames(props.className, 'fc-daygrid-day fc-flex-col', props.borderStart && 'fc-border-s', props.width != null ? '' : 'fc-liquid'), attrs: Object.assign(Object.assign({}, props.attrs), { role: 'gridcell' }), style: {
212
- width: props.width
213
- }, elRef: this.rootElRef, renderProps: props.renderProps, defaultGenerator: renderTopInner, date: props.date, dateProfile: props.dateProfile, todayRange: props.todayRange, showDayNumber: props.showDayNumber, isMonthStart: isMonthStart }, (InnerContent, renderProps) => (createElement(Fragment, null,
214
- !renderProps.isDisabled && (props.showDayNumber || hasCustomDayCellContent(options)) && (createElement("div", { className: "fc-daygrid-day-header" },
215
- createElement(InnerContent, { tag: "a", attrs: buildNavLinkAttrs(context, props.date), className: joinClassNames('fc-daygrid-day-number', isMonthStart && 'fc-daygrid-month-start') }))),
216
- createElement("div", { className: joinClassNames('fc-daygrid-day-body', props.isTall && 'fc-daygrid-day-body-tall', props.fgLiquidHeight ? 'fc-liquid' : 'fc-grow'), ref: this.bodyElRef },
217
- createElement("div", { className: 'fc-daygrid-day-events', style: { height: props.fgHeight } }, props.fg),
218
- createElement(DayGridMoreLink, { isBlock: props.isCompact, allDayDate: props.date, segs: props.segs, hiddenSegs: props.hiddenSegs, alignElRef: this.rootElRef, alignParentTop: props.showDayNumber ? '[role=row]' : '.fc-view', dateSpanProps: props.dateSpanProps, dateProfile: props.dateProfile, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, todayRange: props.todayRange }))))));
219
- }
220
- componentDidMount() {
221
- const bodyEl = this.bodyElRef.current;
222
- // we want to fire on ANY size change, because we do more advanced stuff
223
- this.disconnectBodyHeight = watchSize(bodyEl, (_bodyWidth, bodyHeight) => {
224
- const { props } = this;
225
- const mainRect = bodyEl.getBoundingClientRect();
226
- const rootRect = this.rootElRef.current.getBoundingClientRect();
227
- const headerHeight = mainRect.top - rootRect.top;
228
- if (!isDimsEqual(this.headerHeight, headerHeight)) {
229
- this.headerHeight = headerHeight;
230
- setRef(props.headerHeightRef, headerHeight);
231
- }
232
- if (props.fgLiquidHeight) {
233
- setRef(props.mainHeightRef, bodyHeight);
234
- }
259
+ const dateMeta = this.getDateMeta(props.date, dateEnv, props.dateProfile, props.todayRange);
260
+ const baseClassName = joinClassNames(props.borderStart ? classNames.borderOnlyS : classNames.borderNone, props.width != null ? '' : classNames.liquid, classNames.flexCol);
261
+ const hasNavLink = options.navLinks;
262
+ const renderProps = this.refineRenderProps({
263
+ date: props.date,
264
+ isMajor: props.isMajor,
265
+ isNarrow: props.isNarrow,
266
+ dateMeta: dateMeta,
267
+ hasLabel: props.showDayNumber,
268
+ hasMonthLabel: isMonthStart,
269
+ hasNavLink,
270
+ renderProps: props.renderProps,
271
+ viewApi: context.viewApi,
272
+ dateEnv: context.dateEnv,
273
+ monthStartFormat: options.monthStartFormat,
274
+ dayCellFormat: options.dayCellFormat,
275
+ businessHours: Boolean(options.businessHours),
235
276
  });
236
- }
237
- componentWillUnmount() {
238
- this.disconnectBodyHeight();
239
- const { props } = this;
240
- setRef(props.headerHeightRef, null);
241
- setRef(props.mainHeightRef, null);
277
+ if (dateMeta.isDisabled) {
278
+ return (createElement("div", { role: 'gridcell', "aria-disabled": true, className: joinArrayishClassNames(generateClassName(options.dayCellClass, renderProps), props.className, baseClassName), style: {
279
+ width: props.width
280
+ } }));
281
+ }
282
+ const fullDateStr = buildDateStr(context, props.date);
283
+ return (createElement(ContentContainer, { tag: "div", elRef: this.rootElRef, className: joinClassNames(props.className, baseClassName), attrs: Object.assign(Object.assign(Object.assign(Object.assign({}, props.attrs), { role: 'gridcell', 'aria-label': fullDateStr }), (renderProps.isToday ? { 'aria-current': 'date' } : {})), { 'data-date': formatDayString(props.date) }), style: {
284
+ width: props.width,
285
+ }, renderProps: renderProps, generatorName: "dayCellTopContent" // !!! for top
286
+ , customGenerator: options.dayCellTopContent /* !!! for top */, defaultGenerator: renderTopInner, classNameGenerator: options.dayCellClass, didMount: options.dayCellDidMount, willUnmount: options.dayCellWillUnmount }, (InnerContent) => (createElement(Fragment, null,
287
+ createElement("div", { className: joinClassNames(classNames.rel, // puts it above bg-fills, which are positioned on TOP of this component :|
288
+ generateClassName(options.dayCellTopClass, renderProps)) }, props.showDayNumber && (createElement(InnerContent // the dayCellTopContent
289
+ , { tag: 'div', attrs: hasNavLink
290
+ ? buildNavLinkAttrs(context, props.date, undefined, fullDateStr)
291
+ : { 'aria-hidden': true } // label already on cell
292
+ , className: generateClassName(options.dayCellTopInnerClass, renderProps) }))),
293
+ createElement("div", { className: joinClassNames(classNames.flexCol, props.fgLiquidHeight ? classNames.liquid : classNames.grow), ref: this.handleBodyEl },
294
+ createElement("div", { className: generateClassName(options.dayCellInnerClass, renderProps), style: { minHeight: props.fgHeight } }, props.fg),
295
+ createElement(DayGridMoreLink, { className: classNames.rel, allDayDate: props.date, segs: props.segs, hiddenSegs: props.hiddenSegs, alignElRef: this.rootElRef, alignParentTop: props.showDayNumber
296
+ ? '[role=row]'
297
+ : `.${classNames.internalView}`, dateSpanProps: props.dateSpanProps, dateProfile: props.dateProfile, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, todayRange: props.todayRange, isNarrow: props.isNarrow, isMicro: props.isMicro })),
298
+ createElement("div", { className: joinClassNames(classNames.rel, // puts it above bg-fills
299
+ generateClassName(options.dayCellBottomClass, renderProps)) })))));
242
300
  }
243
301
  }
244
302
  // Utils
245
303
  // -------------------------------------------------------------------------------------------------
246
304
  function renderTopInner(props) {
247
- return props.dayNumberText || createElement(Fragment, null, "\u00A0");
305
+ return props.text || createElement(Fragment, null, "\u00A0"); // TODO: DRY?
248
306
  }
249
307
  function shouldDisplayMonthStart(date, currentRange, dateEnv) {
250
308
  const { start: currentStart, end: currentEnd } = currentRange;
@@ -261,6 +319,16 @@ function shouldDisplayMonthStart(date, currentRange, dateEnv) {
261
319
  // a month-start that's within the current range?
262
320
  (dateEnv.getDay(date) === 1 && date.valueOf() < currentEnd.valueOf()));
263
321
  }
322
+ function refineRenderProps(raw) {
323
+ let { date, dateEnv, hasLabel, hasMonthLabel, hasNavLink, businessHours } = raw;
324
+ let [text, textParts] = hasLabel
325
+ ? dateEnv.format(date, hasMonthLabel ? raw.monthStartFormat : raw.dayCellFormat)
326
+ : ['', []];
327
+ return Object.assign(Object.assign(Object.assign({}, raw.dateMeta), raw.renderProps), { text,
328
+ textParts, isMajor: raw.isMajor, isNarrow: raw.isNarrow, inPopover: false, hasNavLink,
329
+ get dayNumberText() { return findDayNumberText(textParts); },
330
+ get monthText() { return findMonthText(textParts); }, options: { businessHours }, view: raw.viewApi });
331
+ }
264
332
 
265
333
  function computeFgSegVerticals(segs, segHeightMap, cells, maxHeight, strictOrder, allowSlicing = true, dayMaxEvents, dayMaxEventRows) {
266
334
  let maxCoord;
@@ -383,20 +451,19 @@ function compileSegMap(segs, segMap) {
383
451
  return res;
384
452
  }
385
453
 
386
- /*
387
- TODO: move this so @fullcalendar/daygrid
388
- */
389
- function buildDayTableModel(dateProfile, dateProfileGenerator) {
390
- let daySeries = new DaySeriesModel(dateProfile.renderRange, dateProfileGenerator);
391
- return new DayTableModel(daySeries, /year|month|week/.test(dateProfile.currentRangeUnit));
454
+ function buildDayTableModel(dateProfile, dateProfileGenerator, dateEnv) {
455
+ const daySeries = new DaySeriesModel(dateProfile.renderRange, dateProfileGenerator);
456
+ const breakOnWeeks = /year|month|week/.test(dateProfile.currentRangeUnit);
457
+ const majorUnit = !breakOnWeeks && computeMajorUnit(dateProfile, dateEnv);
458
+ return new DayTableModel(daySeries, breakOnWeeks, dateEnv, majorUnit);
392
459
  }
393
- function computeColWidth(colCnt, colMinWidth, viewportWidth) {
460
+ function computeColWidth(colCount, colMinWidth, viewportWidth) {
394
461
  if (viewportWidth == null) {
395
462
  return [undefined, undefined];
396
463
  }
397
- const colTempWidth = viewportWidth / colCnt;
464
+ const colTempWidth = viewportWidth / colCount;
398
465
  if (colTempWidth < colMinWidth) {
399
- return [colMinWidth * colCnt, colMinWidth];
466
+ return [colMinWidth * colCount, colMinWidth];
400
467
  }
401
468
  return [viewportWidth, undefined];
402
469
  }
@@ -422,29 +489,24 @@ function computeTopFromDate(date, cellRows, rowHeightMap, adjust = 0) {
422
489
  /*
423
490
  FYI, `width` is not dependable for aligning completely to farside
424
491
  */
425
- function computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl) {
492
+ function computeHorizontalsFromSeg(seg, colWidth, colCount) {
426
493
  let fromStart;
427
494
  let fromEnd;
428
495
  if (colWidth != null) {
429
496
  fromStart = seg.start * colWidth;
430
- fromEnd = (colCnt - seg.end) * colWidth;
497
+ fromEnd = (colCount - seg.end) * colWidth;
431
498
  }
432
499
  else {
433
- const colWidthFrac = 1 / colCnt;
500
+ const colWidthFrac = 1 / colCount;
434
501
  fromStart = fracToCssDim(seg.start * colWidthFrac);
435
502
  fromEnd = fracToCssDim(1 - seg.end * colWidthFrac);
436
503
  }
437
- if (isRtl) {
438
- return { right: fromStart, left: fromEnd };
439
- }
440
- else {
441
- return { left: fromStart, right: fromEnd };
442
- }
504
+ return { insetInlineStart: fromStart, insetInlineEnd: fromEnd };
443
505
  }
444
- function computeColFromPosition(positionLeft, elWidth, colWidth, colCnt, isRtl) {
445
- const realColWidth = colWidth != null ? colWidth : elWidth / colCnt;
506
+ function computeColFromPosition(positionLeft, elWidth, colWidth, colCount, isRtl) {
507
+ const realColWidth = colWidth != null ? colWidth : elWidth / colCount;
446
508
  const colFromLeft = Math.floor(positionLeft / realColWidth);
447
- const col = isRtl ? (colCnt - colFromLeft - 1) : colFromLeft;
509
+ const col = isRtl ? (colCount - colFromLeft - 1) : colFromLeft;
448
510
  const left = colFromLeft * realColWidth;
449
511
  const right = left + realColWidth;
450
512
  return { col, left, right };
@@ -467,13 +529,17 @@ function computeRowFromPosition(positionTop, cellRows, rowHeightMap) {
467
529
  // Hit Element
468
530
  // -------------------------------------------------------------------------------------------------
469
531
  function getRowEl(rootEl, row) {
470
- return rootEl.querySelectorAll(':scope > [role=row]')[row];
532
+ return rootEl.querySelectorAll('[role=row]')[row];
471
533
  }
472
534
  function getCellEl(rowEl, col) {
473
- return rowEl.querySelectorAll(':scope > [role=gridcell]')[col];
535
+ return rowEl.querySelectorAll('[role=gridcell]')[col];
474
536
  }
475
537
  // Header Formatting
476
538
  // -------------------------------------------------------------------------------------------------
539
+ const dayMicroWidth = 50;
540
+ const dayHeaderMicroFormat = createFormatter({
541
+ weekday: 'narrow'
542
+ });
477
543
  function createDayHeaderFormatter(explicitFormat, datesRepDistinctDays, dateCnt) {
478
544
  return explicitFormat || computeFallbackHeaderFormat(datesRepDistinctDays, dateCnt);
479
545
  }
@@ -481,13 +547,23 @@ function createDayHeaderFormatter(explicitFormat, datesRepDistinctDays, dateCnt)
481
547
  function computeFallbackHeaderFormat(datesRepDistinctDays, dayCnt) {
482
548
  // if more than one week row, or if there are a lot of columns with not much space,
483
549
  // put just the day numbers will be in each cell
484
- if (!datesRepDistinctDays || dayCnt > 10) {
550
+ if (!datesRepDistinctDays) {
485
551
  return createFormatter({ weekday: 'short' }); // "Sat"
486
552
  }
487
553
  if (dayCnt > 1) {
488
- return createFormatter({ weekday: 'short', month: 'numeric', day: 'numeric', omitCommas: true }); // "Sat 11/12"
554
+ return createFormatter({
555
+ weekday: 'short',
556
+ weekdayJustify: 'start',
557
+ day: 'numeric',
558
+ omitCommas: true,
559
+ });
489
560
  }
490
- return createFormatter({ weekday: 'long' }); // "Saturday"
561
+ return createFormatter({
562
+ weekday: 'long',
563
+ weekdayJustify: 'start',
564
+ day: 'numeric',
565
+ omitCommas: true,
566
+ });
491
567
  }
492
568
 
493
569
  class DayGridEventHarness extends Component {
@@ -498,7 +574,7 @@ class DayGridEventHarness extends Component {
498
574
  }
499
575
  render() {
500
576
  const { props } = this;
501
- return (createElement("div", { className: joinClassNames(props.className, 'fc-abs'), style: props.style, ref: this.rootElRef }, props.children));
577
+ return (createElement("div", { className: joinClassNames(props.className, classNames.abs), style: props.style, ref: this.rootElRef }, props.children));
502
578
  }
503
579
  componentDidMount() {
504
580
  const rootEl = this.rootElRef.current; // TODO: make dynamic with useEffect
@@ -528,6 +604,8 @@ class DayGridRow extends BaseComponent {
528
604
  this.segHeightRefMap = new RefMap(() => {
529
605
  afterSize(this.handleSegPositioning);
530
606
  });
607
+ // memo
608
+ this.buildWeekNumberRenderProps = memoize(buildWeekNumberRenderProps);
531
609
  this.handleRootEl = (rootEl) => {
532
610
  this.rootEl = rootEl;
533
611
  setRef(this.props.rootElRef, rootEl);
@@ -540,7 +618,7 @@ class DayGridRow extends BaseComponent {
540
618
  const { props, context, headerHeightRefMap, mainHeightRefMap } = this;
541
619
  const { cells } = props;
542
620
  const { options } = context;
543
- const weekDate = props.cells[0].date;
621
+ const weekDateMarker = props.cells[0].date;
544
622
  const fgLiquidHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;
545
623
  // TODO: memoize? sort all types of segs?
546
624
  const fgEventSegs = sortEventSegs(props.fgEventSegs, options.eventOrder);
@@ -559,20 +637,29 @@ class DayGridRow extends BaseComponent {
559
637
  }
560
638
  const highlightSegs = this.getHighlightSegs();
561
639
  const mirrorSegs = this.getMirrorSegs();
562
- const forcedInvisibleMap = // TODO: more convenient/DRY
563
- (props.eventDrag && props.eventDrag.affectedInstances) ||
564
- (props.eventResize && props.eventResize.affectedInstances) ||
565
- {};
566
- return (createElement("div", { role: 'row' // TODO: audit this for all scenarios
567
- , className: joinClassNames('fc-flex-row fc-rel', props.className), style: {
568
- minHeight: props.minHeight,
640
+ const hasNavLink = options.navLinks;
641
+ const fullWeekStr = buildDateStr(context, weekDateMarker, 'week');
642
+ const weekNumberRenderProps = this.buildWeekNumberRenderProps(weekDateMarker, context, props.cellIsNarrow, hasNavLink);
643
+ return (createElement("div", { role: props.role /* !!! */, "aria-label": props.role === 'row' // HACK
644
+ ? fullWeekStr
645
+ : undefined // can't have label on non-role div
646
+ , className: joinArrayishClassNames(options.dayRowClass, props.className, classNames.flexRow, classNames.rel, // origin for inlineWeekNumber?
647
+ classNames.isolate, (props.forPrint && props.basis !== undefined) && // basis implies siblings (must share height)
648
+ classNames.printSiblingRow), style: {
649
+ 'flex-basis': props.basis,
569
650
  }, ref: this.handleRootEl },
651
+ (props.showWeekNumbers && !props.cellIsMicro) && (createElement(ContentContainer, { tag: 'div', attrs: Object.assign(Object.assign({}, (hasNavLink
652
+ ? buildNavLinkAttrs(context, weekDateMarker, 'week', fullWeekStr, /* isTabbable = */ false)
653
+ : {})), { 'role': undefined, 'aria-hidden': true }),
654
+ // put above all cells (TODO: put explicit z0 on each cell?)
655
+ className: classNames.z1, renderProps: weekNumberRenderProps, generatorName: "inlineWeekNumberContent", customGenerator: options.inlineWeekNumberContent, defaultGenerator: renderText, classNameGenerator: options.inlineWeekNumberClass, didMount: options.inlineWeekNumberDidMount, willUnmount: options.inlineWeekNumberWillUnmount })),
570
656
  this.renderFillSegs(props.businessHourSegs, 'non-business'),
571
657
  this.renderFillSegs(props.bgEventSegs, 'bg-event'),
572
658
  this.renderFillSegs(highlightSegs, 'highlight'),
573
- createElement("div", { className: 'fc-flex-row fc-liquid fc-rel' }, props.cells.map((cell, col) => {
574
- const normalFgNodes = this.renderFgSegs(maxMainTop, renderableSegsByCol[col], segTops, props.todayRange, forcedInvisibleMap);
575
- return (createElement(DayGridCell, { key: cell.key, dateProfile: props.dateProfile, todayRange: props.todayRange, date: cell.date, showDayNumber: props.showDayNumbers, isCompact: props.isCompact, isTall: props.isTall, borderStart: Boolean(col),
659
+ props.cells.map((cell, col) => {
660
+ const normalFgNodes = this.renderFgSegs(maxMainTop, renderableSegsByCol[col], segTops, props.todayRange,
661
+ /* isMirror = */ false);
662
+ return (createElement(DayGridCell, { key: cell.key, dateProfile: props.dateProfile, todayRange: props.todayRange, date: cell.date, isMajor: cell.isMajor, showDayNumber: props.showDayNumbers, isNarrow: props.cellIsNarrow, isMicro: props.cellIsMicro, borderStart: Boolean(col),
576
663
  // content
577
664
  segs: segsByCol[col], hiddenSegs: hiddenSegsByCol[col], fgLiquidHeight: fgLiquidHeight, fg: (createElement(Fragment, null, normalFgNodes)), eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
578
665
  // render hooks
@@ -581,19 +668,16 @@ class DayGridRow extends BaseComponent {
581
668
  fgHeight: heightsByCol[col], width: props.colWidth,
582
669
  // refs
583
670
  headerHeightRef: headerHeightRefMap.createRef(cell.key), mainHeightRef: mainHeightRefMap.createRef(cell.key) }));
584
- })),
585
- props.showWeekNumbers && (createElement(WeekNumberContainer, { tag: "a", attrs: buildNavLinkAttrs(context, weekDate, 'week'), className: 'fc-daygrid-week-number', date: weekDate, defaultFormat: DEFAULT_WEEK_NUM_FORMAT })),
586
- this.renderFgSegs(maxMainTop, mirrorSegs, segTops, props.todayRange, {}, // forcedInvisibleMap
587
- Boolean(props.eventDrag), Boolean(props.eventResize), false)));
671
+ }),
672
+ this.renderFgSegs(maxMainTop, mirrorSegs, segTops, props.todayRange,
673
+ /* isMirror = */ true)));
588
674
  }
589
- renderFgSegs(headerHeight, segs, segTops, todayRange, forcedInvisibleMap, isDragging, isResizing, isDateSelecting) {
675
+ renderFgSegs(headerHeight, segs, segTops, todayRange, isMirror) {
590
676
  var _a;
591
- const { props, context, segHeightRefMap } = this;
592
- const { isRtl } = context;
593
- const { colWidth, eventSelection } = props;
594
- const colCnt = props.cells.length;
677
+ const { props, segHeightRefMap } = this;
678
+ const { colWidth, eventSelection, cellIsMicro } = props;
679
+ const colCount = props.cells.length;
595
680
  const defaultDisplayEventEnd = props.cells.length === 1;
596
- const isMirror = isDragging || isResizing || isDateSelecting;
597
681
  const nodes = [];
598
682
  for (const seg of segs) {
599
683
  const key = getEventPartKey(seg);
@@ -602,39 +686,43 @@ class DayGridRow extends BaseComponent {
602
686
  if (standinFor) {
603
687
  continue;
604
688
  }
605
- const { left, right } = computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl);
689
+ const { insetInlineStart, insetInlineEnd } = computeHorizontalsFromSeg(seg, colWidth, colCount);
606
690
  const localTop = (_a = segTops.get(standinFor ? getEventPartKey(standinFor) : key)) !== null && _a !== void 0 ? _a : (isMirror ? 0 : undefined);
607
691
  const top = headerHeight != null && localTop != null
608
692
  ? headerHeight + localTop
609
693
  : undefined;
610
- const isInvisible = standinFor || forcedInvisibleMap[instanceId] || top == null;
611
- nodes.push(createElement(DayGridEventHarness, { key: key, className: seg.start ? 'fc-border-transparent fc-border-s' : '', style: {
612
- visibility: isInvisible ? 'hidden' : '',
694
+ const isDragging = Boolean(props.eventDrag && props.eventDrag.affectedInstances[instanceId]);
695
+ const isResizing = Boolean(props.eventResize && props.eventResize.affectedInstances[instanceId]);
696
+ const isInvisible = !isMirror && (isDragging || isResizing || standinFor || top == null);
697
+ const isListItem = hasListItemDisplay(seg);
698
+ nodes.push(createElement(DayGridEventHarness, { key: key, className: seg.start ? classNames.fakeBorderS : '', style: {
699
+ visibility: isInvisible ? 'hidden' : undefined,
613
700
  top,
614
- left,
615
- right,
701
+ insetInlineStart,
702
+ insetInlineEnd,
703
+ zIndex: 0, // container inner z-indexes
616
704
  }, heightRef: (!standinFor && !isMirror)
617
705
  ? segHeightRefMap.createRef(key)
618
- : null }, hasListItemDisplay(seg) ? (createElement(DayGridListEvent, Object.assign({ eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: isDragging, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, getEventRangeMeta(eventRange, todayRange)))) : (createElement(DayGridBlockEvent, Object.assign({ eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, getEventRangeMeta(eventRange, todayRange))))));
706
+ : null },
707
+ createElement(StandardEvent, Object.assign({ display: isListItem ? 'list-item' : 'row', eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: isDragging, isResizing: isResizing, isMirror: isMirror, isSelected: instanceId === eventSelection, isNarrow: props.cellIsNarrow, defaultTimeFormat: DEFAULT_TABLE_EVENT_TIME_FORMAT, defaultDisplayEventEnd: defaultDisplayEventEnd, disableResizing: isListItem, forcedTimeText: cellIsMicro ? '' : undefined }, getEventRangeMeta(eventRange, todayRange)))));
619
708
  }
620
709
  return nodes;
621
710
  }
622
711
  renderFillSegs(segs, fillType) {
623
712
  const { props, context } = this;
624
- const { isRtl } = context;
625
713
  const { todayRange, colWidth } = props;
626
- const colCnt = props.cells.length;
714
+ const colCount = props.cells.length;
627
715
  const nodes = [];
628
716
  for (const seg of segs) {
629
717
  const key = buildEventRangeKey(seg.eventRange); // TODO: use different type of key than fg!?
630
- const { left, right } = computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl);
718
+ const { insetInlineStart, insetInlineEnd } = computeHorizontalsFromSeg(seg, colWidth, colCount);
631
719
  const isVisible = !seg.standinFor;
632
- nodes.push(createElement("div", { key: key, className: "fc-fill-y", style: {
720
+ nodes.push(createElement("div", { key: key, className: classNames.fillY, style: {
633
721
  visibility: isVisible ? '' : 'hidden',
634
- left,
635
- right,
722
+ insetInlineStart,
723
+ insetInlineEnd,
636
724
  } }, fillType === 'bg-event' ?
637
- createElement(BgEvent, Object.assign({ eventRange: seg.eventRange, isStart: seg.isStart, isEnd: seg.isEnd }, getEventRangeMeta(seg.eventRange, todayRange))) : (renderFill(fillType))));
725
+ createElement(BgEvent, Object.assign({ eventRange: seg.eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isNarrow: props.cellIsNarrow, isVertical: false }, getEventRangeMeta(seg.eventRange, todayRange))) : (renderFill(fillType, context.options))));
638
726
  }
639
727
  return createElement(Fragment, {}, ...nodes); // TODO: shouldn't this be an array, so keyed?
640
728
  }
@@ -698,6 +786,22 @@ class DayGridRow extends BaseComponent {
698
786
  return props.dateSelectionSegs;
699
787
  }
700
788
  }
789
+ // Utils
790
+ // -------------------------------------------------------------------------------------------------
791
+ function buildWeekNumberRenderProps(weekDateMarker, context, isNarrow, hasNavLink) {
792
+ const { dateEnv, options } = context;
793
+ const weekNum = dateEnv.computeWeekNumber(weekDateMarker);
794
+ const [weekNumText, weekNumTextParts] = dateEnv.format(weekDateMarker, options.weekNumberFormat || DEFAULT_WEEK_NUM_FORMAT);
795
+ const weekDateZoned = dateEnv.toDate(weekDateMarker);
796
+ return {
797
+ num: weekNum,
798
+ text: weekNumText,
799
+ textParts: weekNumTextParts,
800
+ date: weekDateZoned,
801
+ isNarrow,
802
+ hasNavLink,
803
+ };
804
+ }
701
805
 
702
806
  class DayGridRows extends DateComponent {
703
807
  constructor() {
@@ -733,45 +837,36 @@ class DayGridRows extends DateComponent {
733
837
  render() {
734
838
  let { props, context, rowHeightRefMap } = this;
735
839
  let { options } = context;
736
- let rowCnt = props.cellRows.length;
737
- let fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, rowCnt);
738
- let bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, rowCnt);
739
- let businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, rowCnt);
740
- let dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, rowCnt);
741
- let eventDragByRow = this.splitEventDrag(props.eventDrag, rowCnt);
742
- let eventResizeByRow = this.splitEventResize(props.eventResize, rowCnt);
840
+ let rowCount = props.cellRows.length;
841
+ let fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, rowCount);
842
+ let bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, rowCount);
843
+ let businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, rowCount);
844
+ let dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, rowCount);
845
+ let eventDragByRow = this.splitEventDrag(props.eventDrag, rowCount);
846
+ let eventResizeByRow = this.splitEventResize(props.eventResize, rowCount);
743
847
  let isHeightAuto = getIsHeightAuto(options);
744
848
  let rowHeightsRedistribute = !props.forPrint && !isHeightAuto;
745
- let [rowMinHeight, isCompact] = computeRowHeight(props.visibleWidth, rowCnt, isHeightAuto, props.forPrint, options);
746
- return (createElement("div", { className: joinClassNames(
849
+ let rowBasis = computeRowBasis(props.visibleWidth, rowCount, isHeightAuto, options);
850
+ return (createElement("div", { role: 'rowgroup', className: joinClassNames(props.className,
747
851
  // HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
748
852
  // https://stackoverflow.com/a/60256345
749
- !props.forPrint && 'fc-flex-col', props.className), style: { width: props.width }, ref: this.handleRootEl }, props.cellRows.map((cells, row) => (createElement(DayGridRow, { key: cells[0].key, dateProfile: props.dateProfile, todayRange: props.todayRange, cells: cells, showDayNumbers: rowCnt > 1, showWeekNumbers: options.weekNumbers, forPrint: props.forPrint, isCompact: isCompact,
853
+ !props.forPrint && classNames.flexCol), style: { width: props.width }, ref: this.handleRootEl }, props.cellRows.map((cells, row) => (createElement(DayGridRow, { key: cells[0].key, role: 'row', dateProfile: props.dateProfile, todayRange: props.todayRange, cells: cells, cellIsNarrow: props.cellIsNarrow, cellIsMicro: props.cellIsMicro, showDayNumbers: rowCount > 1, showWeekNumbers: rowCount > 1 && options.weekNumbers, forPrint: props.forPrint,
750
854
  // if not auto-height, distribute height of container somewhat evently to rows
751
- // (treat all as zero, distribute height, then ensure min-heights -- the inner content height)
752
- className: joinClassNames(rowHeightsRedistribute && 'fc-grow fc-basis0', rowCnt > 1 && 'fc-break-inside-avoid', // don't avoid breaks for single tall row
753
- row < rowCnt - 1 && 'fc-border-b'),
855
+ className: joinClassNames(rowHeightsRedistribute && classNames.grow, rowCount > 1 && classNames.breakInsideAvoid, // don't avoid breaks for single tall row
856
+ row < rowCount - 1 ? classNames.borderOnlyB : classNames.borderNone),
754
857
  // content
755
858
  fgEventSegs: fgEventSegsByRow[row], bgEventSegs: bgEventSegsByRow[row].filter(isSegAllDay) /* HACK */, businessHourSegs: businessHourSegsByRow[row], dateSelectionSegs: dateSelectionSegsByRow[row], eventSelection: props.eventSelection, eventDrag: eventDragByRow[row], eventResize: eventResizeByRow[row], dayMaxEvents: props.dayMaxEvents, dayMaxEventRows: props.dayMaxEventRows,
756
859
  // dimensions
757
- colWidth: props.colWidth, minHeight: rowMinHeight,
860
+ colWidth: props.colWidth, basis: rowBasis,
758
861
  // refs
759
862
  heightRef: rowHeightRefMap.createRef(cells[0].key) })))));
760
863
  }
761
- componentDidMount() {
762
- this.disconnectWidth = watchWidth(this.rootEl, (width) => {
763
- this.setState({ width });
764
- });
765
- }
766
- componentWillUnmount() {
767
- this.disconnectWidth();
768
- }
769
864
  // Hit System
770
865
  // -----------------------------------------------------------------------------------------------
771
- queryHit(positionLeft, positionTop, elWidth) {
772
- const { props, context } = this;
773
- const colCnt = props.cellRows[0].length;
774
- const { col, left, right } = computeColFromPosition(positionLeft, elWidth, props.colWidth, colCnt, context.isRtl);
866
+ queryHit(isRtl, positionLeft, positionTop, elWidth) {
867
+ const { props } = this;
868
+ const colCount = props.cellRows[0].length;
869
+ const { col, left, right } = computeColFromPosition(positionLeft, elWidth, props.colWidth, colCount, isRtl);
775
870
  const { row, top, bottom } = computeRowFromPosition(positionTop, props.cellRows, this.rowHeightRefMap.current);
776
871
  const cell = props.cellRows[row][col];
777
872
  const cellStartDate = cell.date;
@@ -782,8 +877,7 @@ class DayGridRows extends DateComponent {
782
877
  start: cellStartDate,
783
878
  end: cellEndDate,
784
879
  }, allDay: true }, cell.dateSpanProps),
785
- // HACK. TODO: This is expensive to do every hit-query
786
- dayEl: getCellEl(getRowEl(this.rootEl, row), col),
880
+ getDayEl: () => getCellEl(getRowEl(this.rootEl, row), col),
787
881
  rect: {
788
882
  left,
789
883
  right,
@@ -799,40 +893,41 @@ class DayGridRows extends DateComponent {
799
893
  function isSegAllDay(seg) {
800
894
  return seg.eventRange.def.allDay;
801
895
  }
802
- function computeRowHeight(visibleWidth, // should INCLUDE any scrollbar width to avoid oscillation
803
- rowCnt, isHeightAuto, forPrint, options) {
896
+ /*
897
+ Amount of height a row should consume prior to expanding
898
+ We don't want to use min-height with flexbox because we leverage min-height:auto,
899
+ which yields value based on natural height of events
900
+ */
901
+ function computeRowBasis(visibleWidth, // should INCLUDE any scrollbar width to avoid oscillation
902
+ rowCount, isHeightAuto, options) {
804
903
  if (visibleWidth != null) {
805
904
  // ensure a consistent row min-height modelled after a month with 6 rows respecting aspectRatio
806
905
  // will result in same minHeight regardless of weekends, dayMinWidth, height:auto
807
- const rowMinHeight = visibleWidth / options.aspectRatio / 6;
808
- return [
809
- forPrint
810
- // special-case for print, which condenses whole-page width without notifying
811
- // this is value that looks natural on paper for portrait/landscape
812
- ? '6em'
813
- // don't give minHeight when single-month non-auto-height
814
- // TODO: better way to detect this with DateProfile?
815
- : (rowCnt > 6 || isHeightAuto)
816
- ? rowMinHeight
817
- : undefined,
818
- // isCompact?: just before most lone +more links hit bottom of cell
819
- rowMinHeight < 70,
820
- ];
906
+ const rowBasis = visibleWidth / options.aspectRatio / 6;
907
+ // don't give minHeight when single-month non-auto-height
908
+ // TODO: better way to detect this with DateProfile?
909
+ return (rowCount > 6 || isHeightAuto) ? rowBasis : 0;
821
910
  }
822
- return [undefined, false];
911
+ return 0;
823
912
  }
824
913
 
825
914
  class DayGridHeaderCell extends BaseComponent {
826
915
  constructor() {
827
916
  super(...arguments);
828
917
  this.handleInnerEl = (innerEl) => {
829
- if (this.disconectInnerHeight) {
830
- this.disconectInnerHeight();
831
- this.disconectInnerHeight = undefined;
918
+ if (this.disconnectSize) {
919
+ this.disconnectSize();
920
+ this.disconnectSize = undefined;
832
921
  }
833
922
  if (innerEl) {
834
- this.disconectInnerHeight = watchHeight(innerEl, (height) => {
923
+ this.disconnectSize = watchSize(innerEl, (width, height) => {
835
924
  setRef(this.props.innerHeightRef, height);
925
+ /*
926
+ TODO: DRY with TimelineHeaderCell
927
+ */
928
+ if (this.align === 'center' && this.isSticky) {
929
+ this.setState({ innerWidth: width });
930
+ }
836
931
  });
837
932
  }
838
933
  else {
@@ -841,16 +936,54 @@ class DayGridHeaderCell extends BaseComponent {
841
936
  };
842
937
  }
843
938
  render() {
844
- const { props } = this;
939
+ const { props, state, context } = this;
845
940
  const { renderConfig, dataConfig } = props;
846
- return (createElement(ContentContainer, { tag: 'div', attrs: dataConfig.attrs, className: joinClassNames(dataConfig.className, 'fc-header-cell fc-cell fc-flex-col fc-align-center', props.borderStart && 'fc-border-s', !props.isSticky && 'fc-crop', props.colWidth == null && 'fc-liquid'), style: {
941
+ // HACK
942
+ const isDisabled = dataConfig.renderProps.isDisabled;
943
+ const finalRenderProps = Object.assign(Object.assign({}, dataConfig.renderProps), { isNarrow: props.cellIsNarrow, level: props.rowLevel });
944
+ if (props.cellIsMicro) {
945
+ // TODO: only if not distinct dates
946
+ const [microText, microTextParts] = context.dateEnv.format(dataConfig.dateMarker, dayHeaderMicroFormat);
947
+ finalRenderProps.text = finalRenderProps.weekdayText = microText;
948
+ finalRenderProps.textParts = microTextParts;
949
+ }
950
+ /*
951
+ TODO: DRY with TimelineHeaderCell
952
+ */
953
+ const alignInput = renderConfig.align;
954
+ const align = this.align =
955
+ typeof alignInput === 'function'
956
+ ? alignInput({ level: props.rowLevel, inPopover: dataConfig.renderProps.inPopover, isNarrow: props.cellIsNarrow })
957
+ : alignInput;
958
+ const stickyInput = renderConfig.sticky;
959
+ const isSticky = this.isSticky =
960
+ props.rowLevel && stickyInput !== false;
961
+ let edgeCoord;
962
+ if (isSticky) {
963
+ if (align === 'center') {
964
+ if (state.innerWidth != null) {
965
+ edgeCoord = `calc(50% - ${state.innerWidth / 2}px)`;
966
+ }
967
+ }
968
+ else {
969
+ edgeCoord = (typeof stickyInput === 'number' ||
970
+ typeof stickyInput === 'string') ? stickyInput : 0;
971
+ }
972
+ }
973
+ return (createElement(ContentContainer, { tag: 'div', attrs: Object.assign({ role: 'columnheader', 'aria-colspan': dataConfig.colSpan }, dataConfig.attrs), className: joinClassNames(dataConfig.className, classNames.tight, classNames.flexCol, props.borderStart ? classNames.borderOnlyS : classNames.borderNone, align === 'center' ? classNames.alignCenter :
974
+ align === 'end' ? classNames.alignEnd :
975
+ classNames.alignStart, props.colWidth == null && classNames.liquid, !isSticky && classNames.crop), style: {
847
976
  width: props.colWidth != null
848
977
  ? props.colWidth * (dataConfig.colSpan || 1)
849
978
  : undefined,
850
- }, renderProps: dataConfig.renderProps, generatorName: renderConfig.generatorName, customGenerator: renderConfig.customGenerator, defaultGenerator: renderText, classNameGenerator:
979
+ }, renderProps: finalRenderProps, generatorName: renderConfig.generatorName, customGenerator: renderConfig.customGenerator, defaultGenerator: renderText, classNameGenerator:
851
980
  // don't use custom classNames if disabled
852
981
  // TODO: make DRY with DayCellContainer
853
- dataConfig.renderProps.isDisabled ? undefined : renderConfig.classNameGenerator, didMount: renderConfig.didMount, willUnmount: renderConfig.willUnmount }, (InnerContainer) => (!dataConfig.renderProps.isDisabled && (createElement(InnerContainer, { tag: dataConfig.isNavLink ? 'a' : 'div', attrs: dataConfig.innerAttrs, className: joinClassNames('fc-cell-inner fc-flex-col fc-padding-sm', props.isSticky && 'fc-sticky-s'), elRef: this.handleInnerEl })))));
982
+ isDisabled ? undefined : renderConfig.classNameGenerator, didMount: renderConfig.didMount, willUnmount: renderConfig.willUnmount }, (InnerContainer) => (createElement("div", { ref: this.handleInnerEl, className: joinClassNames(classNames.flexCol, classNames.rigid, isSticky && classNames.sticky), style: {
983
+ left: edgeCoord,
984
+ right: edgeCoord,
985
+ } },
986
+ createElement(InnerContainer, { tag: 'div', attrs: dataConfig.innerAttrs, className: generateClassName(renderConfig.innerClassNameGenerator, finalRenderProps) })))));
854
987
  }
855
988
  }
856
989
 
@@ -874,8 +1007,14 @@ class DayGridHeaderRow extends BaseComponent {
874
1007
  };
875
1008
  }
876
1009
  render() {
877
- const { props } = this;
878
- return (createElement("div", { role: 'row', className: joinClassNames('fc-flex-row fc-content-box', props.className), style: { height: props.height } }, props.dataConfigs.map((dataConfig, cellI) => (createElement(DayGridHeaderCell, { key: dataConfig.key, renderConfig: props.renderConfig, dataConfig: dataConfig, isSticky: props.isSticky, borderStart: Boolean(cellI), colWidth: props.colWidth, innerHeightRef: props.innerHeightRef })))));
1010
+ const { props, context } = this;
1011
+ const { options } = context;
1012
+ return (createElement("div", { role: props.role /* !!! */, "aria-rowindex": props.rowIndex != null ? 1 + props.rowIndex : undefined, className: joinArrayishClassNames(options.dayHeaderRowClass, props.className, classNames.flexRow, classNames.contentBox, props.borderBottom ? classNames.borderOnlyB : classNames.borderNone), style: {
1013
+ height: props.height,
1014
+ } }, props.dataConfigs.map((dataConfig, cellI) => (createElement(DayGridHeaderCell, { key: dataConfig.key, renderConfig: props.renderConfig, dataConfig: dataConfig, borderStart: Boolean(cellI), colWidth: props.colWidth, innerHeightRef: this.innerHeightRefMap.createRef(dataConfig.key), cellIsNarrow: props.cellIsNarrow, cellIsMicro: props.cellIsMicro, rowLevel: props.rowLevel })))));
1015
+ }
1016
+ componentWillUnmount() {
1017
+ setRef(this.props.innerHeightRef, null);
879
1018
  }
880
1019
  }
881
1020
 
@@ -885,9 +1024,10 @@ TODO: kill this class in favor of DayGridHeaderRows?
885
1024
  class DayGridHeader extends BaseComponent {
886
1025
  render() {
887
1026
  const { props } = this;
888
- return (createElement("div", { className: joinClassNames(props.className, 'fc-flex-col', props.width == null && 'fc-liquid'), style: {
889
- width: props.width
890
- } }, props.headerTiers.map((rowConfig, tierNum) => (createElement(DayGridHeaderRow, Object.assign({}, rowConfig, { key: tierNum, className: tierNum ? 'fc-border-t' : '', colWidth: props.colWidth }))))));
1027
+ const { headerTiers } = props;
1028
+ return (createElement("div", { role: 'rowgroup', className: joinClassNames(props.className, classNames.flexCol, props.width == null && classNames.liquid), style: {
1029
+ width: props.width,
1030
+ } }, headerTiers.map((rowConfig, i) => (createElement(DayGridHeaderRow, Object.assign({}, rowConfig, { key: i, role: 'row', borderBottom: i < headerTiers.length - 1, colWidth: props.colWidth, cellIsNarrow: props.cellIsNarrow, cellIsMicro: props.cellIsMicro, rowLevel: headerTiers.length - i - 1 }))))));
891
1031
  }
892
1032
  }
893
1033
 
@@ -897,37 +1037,54 @@ class DayGridLayoutNormal extends BaseComponent {
897
1037
  this.handleScroller = (scroller) => {
898
1038
  setRef(this.props.scrollerRef, scroller);
899
1039
  };
1040
+ this.handleTotalWidth = (totalWidth) => {
1041
+ this.setState({ totalWidth });
1042
+ };
900
1043
  this.handleClientWidth = (clientWidth) => {
901
1044
  this.setState({ clientWidth });
902
1045
  };
903
- this.handleEndScrollbarWidth = (endScrollbarWidth) => {
904
- this.setState({ endScrollbarWidth });
905
- };
906
1046
  }
907
1047
  render() {
908
1048
  const { props, state, context } = this;
909
1049
  const { options } = context;
1050
+ const { totalWidth, clientWidth } = state;
1051
+ let endScrollbarWidth = (totalWidth != null && clientWidth != null)
1052
+ ? totalWidth - clientWidth
1053
+ : undefined;
1054
+ // HACK when clientWidth does NOT include body-border, compared to totalWidth
1055
+ if (endScrollbarWidth < 3) {
1056
+ endScrollbarWidth = 0;
1057
+ }
910
1058
  const verticalScrollbars = !props.forPrint && !getIsHeightAuto(options);
911
1059
  const stickyHeaderDates = !props.forPrint && getStickyHeaderDates(options);
1060
+ const colCount = props.cellRows[0].length;
1061
+ const cellWidth = clientWidth != null ? clientWidth / colCount : undefined;
1062
+ const cellIsMicro = cellWidth != null && cellWidth <= dayMicroWidth;
1063
+ const cellIsNarrow = cellIsMicro || (cellWidth != null && cellWidth <= options.dayNarrowWidth);
912
1064
  return (createElement(Fragment, null,
913
- options.dayHeaders && (createElement("div", { className: joinClassNames(props.forPrint ? 'fc-print-header' : 'fc-flex-row', // col for print, row for screen
914
- 'fc-border-b') },
915
- createElement(DayGridHeader, { headerTiers: props.headerTiers, className: joinClassNames('fc-daygrid-header', stickyHeaderDates && 'fc-table-header-sticky') }),
916
- Boolean(state.endScrollbarWidth) && (createElement("div", { className: 'fc-border-s fc-filler', style: { minWidth: state.endScrollbarWidth } })))),
917
- createElement(Scroller, { vertical: verticalScrollbars, clientWidthRef: this.handleClientWidth, endScrollbarWidthRef: this.handleEndScrollbarWidth, className: joinClassNames('fc-daygrid-body',
1065
+ options.dayHeaders && (createElement("div", { className: joinClassNames(generateClassName(options.tableHeaderClass, {
1066
+ isSticky: stickyHeaderDates,
1067
+ }), props.borderlessX && classNames.borderlessX, classNames.printHeader, // either flexCol or table-header-group
1068
+ stickyHeaderDates && classNames.tableHeaderSticky) },
1069
+ createElement("div", { className: classNames.flexRow },
1070
+ createElement(DayGridHeader, { headerTiers: props.headerTiers, cellIsNarrow: cellIsNarrow, cellIsMicro: cellIsMicro }),
1071
+ Boolean(endScrollbarWidth) && (createElement("div", { className: joinArrayishClassNames(generateClassName(options.fillerClass, { isHeader: true }), classNames.borderOnlyS), style: { minWidth: endScrollbarWidth } }))),
1072
+ createElement("div", { className: generateClassName(options.dayHeaderDividerClass, {
1073
+ isSticky: stickyHeaderDates,
1074
+ options: { allDaySlot: Boolean(options.allDaySlot) },
1075
+ }) }))),
1076
+ createElement(Scroller, { vertical: verticalScrollbars, className: joinArrayishClassNames(options.tableBodyClass, props.borderlessX && classNames.borderlessX, stickyHeaderDates && classNames.borderlessTop, (stickyHeaderDates || props.noEdgeEffects) && classNames.noEdgeEffects,
918
1077
  // HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
919
1078
  // https://stackoverflow.com/a/60256345
920
- !props.forPrint && 'fc-flex-col', verticalScrollbars && 'fc-liquid'), ref: this.handleScroller },
921
- createElement(DayGridRows, { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: props.cellRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed, className: 'fc-grow', dayMaxEvents: props.forPrint ? undefined : options.dayMaxEvents, dayMaxEventRows: options.dayMaxEventRows,
1079
+ !props.forPrint && classNames.flexCol, verticalScrollbars && classNames.liquid), ref: this.handleScroller, clientWidthRef: this.handleClientWidth },
1080
+ createElement(DayGridRows, { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: props.cellRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed, className: classNames.grow, dayMaxEvents: props.forPrint ? undefined : options.dayMaxEvents, dayMaxEventRows: options.dayMaxEventRows,
922
1081
  // content
923
1082
  fgEventSegs: props.fgEventSegs, bgEventSegs: props.bgEventSegs, businessHourSegs: props.businessHourSegs, dateSelectionSegs: props.dateSelectionSegs, eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
924
1083
  // dimensions
925
- visibleWidth: // TODO: DRY
926
- state.clientWidth != null && state.endScrollbarWidth != null
927
- ? state.clientWidth + state.endScrollbarWidth
928
- : undefined,
1084
+ visibleWidth: totalWidth, cellIsNarrow: cellIsNarrow, cellIsMicro: cellIsMicro,
929
1085
  // refs
930
- rowHeightRefMap: props.rowHeightRefMap }))));
1086
+ rowHeightRefMap: props.rowHeightRefMap })),
1087
+ createElement(Ruler, { widthRef: this.handleTotalWidth })));
931
1088
  }
932
1089
  }
933
1090
 
@@ -939,43 +1096,54 @@ class DayGridLayoutPannable extends BaseComponent {
939
1096
  this.footerScrollerRef = createRef();
940
1097
  // Sizing
941
1098
  // -----------------------------------------------------------------------------------------------
1099
+ this.handleTotalWidth = (totalWidth) => {
1100
+ this.setState({ totalWidth });
1101
+ };
942
1102
  this.handleClientWidth = (clientWidth) => {
943
1103
  this.setState({ clientWidth });
944
1104
  };
945
- this.handleEndScrollbarWidth = (endScrollbarWidth) => {
946
- this.setState({ endScrollbarWidth });
947
- };
948
1105
  }
949
1106
  render() {
950
1107
  const { props, state, context } = this;
951
1108
  const { options } = context;
1109
+ const { totalWidth, clientWidth } = state;
1110
+ const endScrollbarWidth = (totalWidth != null && clientWidth != null)
1111
+ ? totalWidth - clientWidth
1112
+ : undefined;
952
1113
  const verticalScrollbars = !props.forPrint && !getIsHeightAuto(options);
953
1114
  const stickyHeaderDates = !props.forPrint && getStickyHeaderDates(options);
954
1115
  const stickyFooterScrollbar = !props.forPrint && getStickyFooterScrollbar(options);
955
- const colCnt = props.cellRows[0].length;
956
- const [canvasWidth, colWidth] = computeColWidth(colCnt, props.dayMinWidth, state.clientWidth);
1116
+ const colCount = props.cellRows[0].length;
1117
+ const [canvasWidth, colWidth] = computeColWidth(colCount, props.dayMinWidth, clientWidth);
1118
+ const cellIsMicro = colWidth != null && colWidth <= dayMicroWidth;
1119
+ const cellIsNarrow = cellIsMicro || (colWidth != null && colWidth <= options.dayNarrowWidth);
957
1120
  return (createElement(Fragment, null,
958
- options.dayHeaders && (createElement("div", { className: 'fc-print-header' },
959
- createElement(Scroller, { horizontal: true, hideScrollbars: true, className: joinClassNames('fc-daygrid-header fc-flex-row fc-border-b', stickyHeaderDates && 'fc-table-header-sticky'), ref: this.headerScrollerRef },
960
- createElement(DayGridHeader, { headerTiers: props.headerTiers, colWidth: colWidth, width: canvasWidth }),
961
- Boolean(state.endScrollbarWidth) && (createElement("div", { className: 'fc-border-s fc-filler', style: { minWidth: state.endScrollbarWidth } }))))),
1121
+ options.dayHeaders && (createElement("div", { className: joinClassNames(generateClassName(options.tableHeaderClass, {
1122
+ isSticky: stickyHeaderDates,
1123
+ }), props.borderlessX && classNames.borderlessX, classNames.printHeader, // either flexCol or table-header-group
1124
+ stickyHeaderDates && classNames.tableHeaderSticky) },
1125
+ createElement(Scroller, { horizontal: true, hideScrollbars: true, className: classNames.flexRow, ref: this.headerScrollerRef },
1126
+ createElement(DayGridHeader, { headerTiers: props.headerTiers, colWidth: colWidth, width: canvasWidth, cellIsNarrow: cellIsNarrow, cellIsMicro: cellIsMicro }),
1127
+ Boolean(endScrollbarWidth) && (createElement("div", { className: joinArrayishClassNames(generateClassName(options.fillerClass, { isHeader: true }), classNames.borderOnlyS), style: { minWidth: endScrollbarWidth } }))),
1128
+ createElement("div", { className: generateClassName(options.dayHeaderDividerClass, {
1129
+ isSticky: stickyHeaderDates,
1130
+ options: { allDaySlot: Boolean(options.allDaySlot) },
1131
+ }) }))),
962
1132
  createElement(Scroller, { vertical: verticalScrollbars, horizontal: true, hideScrollbars: stickyFooterScrollbar ||
963
1133
  props.forPrint // prevents blank space in print-view on Safari
964
- , className: joinClassNames('fc-daygrid-body',
1134
+ , className: joinArrayishClassNames(options.tableBodyClass, props.borderlessX && classNames.borderlessX, stickyHeaderDates && classNames.borderlessTop, (stickyHeaderDates || props.noEdgeEffects) && classNames.noEdgeEffects,
965
1135
  // HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
966
1136
  // https://stackoverflow.com/a/60256345
967
- !props.forPrint && 'fc-flex-col', verticalScrollbars && 'fc-liquid'), ref: this.bodyScrollerRef, clientWidthRef: this.handleClientWidth, endScrollbarWidthRef: this.handleEndScrollbarWidth },
968
- createElement(DayGridRows, { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: props.cellRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed, className: 'fc-grow', dayMaxEvents: props.forPrint ? undefined : options.dayMaxEvents, dayMaxEventRows: options.dayMaxEventRows,
1137
+ !props.forPrint && classNames.flexCol, verticalScrollbars && classNames.liquid), ref: this.bodyScrollerRef, clientWidthRef: this.handleClientWidth },
1138
+ createElement(DayGridRows, { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: props.cellRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed, className: classNames.grow, dayMaxEvents: props.forPrint ? undefined : options.dayMaxEvents, dayMaxEventRows: options.dayMaxEventRows,
969
1139
  // content
970
1140
  fgEventSegs: props.fgEventSegs, bgEventSegs: props.bgEventSegs, businessHourSegs: props.businessHourSegs, dateSelectionSegs: props.dateSelectionSegs, eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
971
1141
  // dimensions
972
- colWidth: colWidth, width: canvasWidth, visibleWidth: // TODO: DRY
973
- state.clientWidth != null && state.endScrollbarWidth != null
974
- ? state.clientWidth + state.endScrollbarWidth
975
- : undefined,
1142
+ colWidth: colWidth, width: canvasWidth, visibleWidth: totalWidth, cellIsNarrow: cellIsNarrow, cellIsMicro: cellIsMicro,
976
1143
  // refs
977
1144
  rowHeightRefMap: props.rowHeightRefMap })),
978
- Boolean(stickyFooterScrollbar) && (createElement(StickyFooterScrollbar, { canvasWidth: canvasWidth, scrollerRef: this.footerScrollerRef }))));
1145
+ Boolean(stickyFooterScrollbar) && (createElement(FooterScrollbar, { isSticky: true, canvasWidth: canvasWidth, scrollerRef: this.footerScrollerRef })),
1146
+ createElement(Ruler, { widthRef: this.handleTotalWidth })));
979
1147
  }
980
1148
  // Lifecycle
981
1149
  // -----------------------------------------------------------------------------------------------
@@ -1030,21 +1198,30 @@ class DayGridLayout extends BaseComponent {
1030
1198
  }
1031
1199
  }
1032
1200
  };
1033
- this.clearScroll = () => {
1034
- this.scrollDate = null;
1201
+ this.handleScrollEnd = (isUser) => {
1202
+ if (isUser) {
1203
+ this.scrollDate = null;
1204
+ }
1035
1205
  };
1036
1206
  }
1037
1207
  render() {
1038
1208
  const { props, context } = this;
1039
1209
  const { options } = context;
1040
1210
  const commonLayoutProps = Object.assign(Object.assign({}, props), { scrollerRef: this.scrollerRef, rowHeightRefMap: this.rowHeightRefMap });
1041
- return (createElement(ViewContainer, { viewSpec: context.viewSpec, className: joinClassNames(props.className, 'fc-print-root fc-border') }, options.dayMinWidth ? (createElement(DayGridLayoutPannable, Object.assign({}, commonLayoutProps, { dayMinWidth: options.dayMinWidth }))) : (createElement(DayGridLayoutNormal, Object.assign({}, commonLayoutProps)))));
1211
+ return (createElement(ViewContainer, { viewSpec: context.viewSpec, attrs: {
1212
+ role: 'grid',
1213
+ 'aria-rowcount': props.headerTiers.length + props.cellRows.length,
1214
+ 'aria-colcount': props.cellRows[0].length,
1215
+ 'aria-labelledby': props.labelId,
1216
+ 'aria-label': props.labelStr,
1217
+ }, className: joinArrayishClassNames(props.className, classNames.printRoot, // either flexCol or table
1218
+ options.tableClass), borderlessX: props.borderlessX, borderlessTop: props.borderlessTop, borderlessBottom: props.borderlessBottom, noEdgeEffects: props.noEdgeEffects }, options.dayMinWidth ? (createElement(DayGridLayoutPannable, Object.assign({}, commonLayoutProps, { dayMinWidth: options.dayMinWidth }))) : (createElement(DayGridLayoutNormal, Object.assign({}, commonLayoutProps)))));
1042
1219
  }
1043
1220
  // Lifecycle
1044
1221
  // -----------------------------------------------------------------------------------------------
1045
1222
  componentDidMount() {
1046
1223
  this.resetScroll();
1047
- this.scrollerRef.current.addScrollEndListener(this.clearScroll);
1224
+ this.scrollerRef.current.addScrollEndListener(this.handleScrollEnd);
1048
1225
  }
1049
1226
  componentDidUpdate(prevProps) {
1050
1227
  if (prevProps.dateProfile !== this.props.dateProfile && this.context.options.scrollTimeReset) {
@@ -1052,14 +1229,13 @@ class DayGridLayout extends BaseComponent {
1052
1229
  }
1053
1230
  }
1054
1231
  componentWillUnmount() {
1055
- this.scrollerRef.current.removeScrollEndListener(this.clearScroll);
1232
+ this.scrollerRef.current.removeScrollEndListener(this.handleScrollEnd);
1056
1233
  }
1057
1234
  // Scrolling
1058
1235
  // -----------------------------------------------------------------------------------------------
1059
1236
  resetScroll() {
1060
1237
  this.scrollDate = this.props.dateProfile.currentDate;
1061
1238
  this.updateScrollY();
1062
- // updateScrollX
1063
1239
  const scroller = this.scrollerRef.current;
1064
1240
  scroller.scrollTo({ x: 0 });
1065
1241
  }
@@ -1077,18 +1253,19 @@ class DayGridView extends BaseComponent {
1077
1253
  }
1078
1254
  render() {
1079
1255
  const { props, context } = this;
1080
- const { options } = context;
1081
- const dayTableModel = this.buildDayTableModel(props.dateProfile, context.dateProfileGenerator);
1082
- const datesRepDistinctDays = dayTableModel.rowCnt === 1;
1083
- const dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, datesRepDistinctDays, dayTableModel.colCnt);
1084
- const slicedProps = this.slicer.sliceProps(props, props.dateProfile, options.nextDayThreshold, context, dayTableModel);
1256
+ const { dateProfile } = props;
1257
+ const { options, dateEnv } = context;
1258
+ const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator, dateEnv);
1259
+ const datesRepDistinctDays = dayTableModel.rowCount === 1;
1260
+ const dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, datesRepDistinctDays, dayTableModel.colCount);
1261
+ const slicedProps = this.slicer.sliceProps(props, dateProfile, options.nextDayThreshold, context, dayTableModel);
1085
1262
  return (createElement(NowTimer, { unit: "day" }, (nowDate, todayRange) => {
1086
- const headerTiers = this.buildDateRowConfigs(dayTableModel.headerDates, datesRepDistinctDays, props.dateProfile, todayRange, dayHeaderFormat, context);
1087
- return (createElement(DayGridLayout, { dateProfile: props.dateProfile, todayRange: todayRange, cellRows: dayTableModel.cellRows, forPrint: props.forPrint, className: 'fc-daygrid',
1263
+ const headerTiers = this.buildDateRowConfigs(dayTableModel.headerDates, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, context);
1264
+ return (createElement(DayGridLayout, { labelId: props.labelId, labelStr: props.labelStr, dateProfile: dateProfile, todayRange: todayRange, cellRows: dayTableModel.cellRows, forPrint: props.forPrint, className: props.className,
1088
1265
  // header content
1089
1266
  headerTiers: headerTiers,
1090
1267
  // body content
1091
- fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection }));
1268
+ fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection, borderlessX: props.borderlessX, borderlessTop: props.borderlessTop, borderlessBottom: props.borderlessBottom, noEdgeEffects: props.noEdgeEffects }));
1092
1269
  }));
1093
1270
  }
1094
1271
  }
@@ -1124,14 +1301,11 @@ function buildDayTableRenderRange(props) {
1124
1301
  // TODO: instead of these date-math gymnastics (for multimonth view),
1125
1302
  // compute dateprofiles of all months, then use start of first and end of last.
1126
1303
  let lastMonthRenderStart = dateEnv.startOfWeek(dateEnv.startOfMonth(addDays(currentRange.end, -1)));
1127
- let rowCnt = Math.ceil(// could be partial weeks due to hiddenDays
1304
+ let rowCount = Math.ceil(// could be partial weeks due to hiddenDays
1128
1305
  diffWeeks(lastMonthRenderStart, end));
1129
- end = addWeeks(end, 6 - rowCnt);
1306
+ end = addWeeks(end, 6 - rowCount);
1130
1307
  }
1131
1308
  return { start, end };
1132
1309
  }
1133
1310
 
1134
- var css_248z = ":root{--fc-daygrid-event-dot-width:8px}.fc-daygrid-day.fc-day-today{background-color:var(--fc-today-bg-color)}.fc-daygrid-day-header{display:flex;flex-direction:row-reverse}.fc-day-other .fc-daygrid-day-header{opacity:.3}.fc-daygrid-day-number{padding:4px;position:relative}.fc-daygrid-month-start{font-size:1.1em;font-weight:700}.fc-daygrid-day-body{display:flex;flex-direction:column;margin-bottom:1px}.fc-daygrid-day-body-tall{margin-bottom:1em;min-height:2em}.fc-daygrid-day-body:only-child{margin-top:2px}.fc-daygrid-more-link{border-radius:3px;cursor:pointer;font-size:var(--fc-small-font-size);margin:0 2px 1px;max-width:100%;overflow:hidden;padding:2px;position:relative;white-space:nowrap}.fc-daygrid-more-link:hover{background-color:rgba(0,0,0,.1)}.fc-daygrid-more-link-button{align-self:flex-start}.fc-daygrid-more-link-block{border:1px solid var(--fc-event-border-color);padding:1px}.fc-daygrid-week-number{background-color:var(--fc-neutral-bg-color);color:var(--fc-neutral-text-color);min-width:1.5em;padding:2px;position:absolute;text-align:center;top:0}.fc-more-popover .fc-popover-body{min-width:220px;padding:10px}.fc-daygrid-event{border-radius:3px;font-size:var(--fc-small-font-size);margin-bottom:1px}.fc-media-print .fc-daygrid-event{overflow:hidden!important;white-space:nowrap!important}.fc-direction-ltr .fc-daygrid-event.fc-event-start,.fc-direction-rtl .fc-daygrid-event.fc-event-end{margin-left:2px}.fc-direction-ltr .fc-daygrid-event.fc-event-end,.fc-direction-rtl .fc-daygrid-event.fc-event-start{margin-right:2px}.fc-direction-ltr .fc-daygrid-event .fc-event-time{margin-right:3px}.fc-direction-rtl .fc-daygrid-event .fc-event-time{margin-left:3px}.fc-direction-ltr .fc-daygrid-block-event:not(.fc-event-start),.fc-direction-rtl .fc-daygrid-block-event:not(.fc-event-end){border-bottom-left-radius:0;border-left-width:0;border-top-left-radius:0}.fc-direction-ltr .fc-daygrid-block-event:not(.fc-event-end),.fc-direction-rtl .fc-daygrid-block-event:not(.fc-event-start){border-bottom-right-radius:0;border-right-width:0;border-top-right-radius:0}.fc-daygrid-block-event .fc-event-time{font-weight:700}.fc-daygrid-block-event .fc-event-time,.fc-daygrid-block-event .fc-event-title{padding:1px}.fc-daygrid-dot-event{align-items:center;direction:row;display:flex;padding:2px 0;position:relative;z-index:2}.fc-daygrid-dot-event.fc-event-mirror,.fc-daygrid-dot-event:hover{background:rgba(0,0,0,.1)}.fc-daygrid-dot-event.fc-event-selected:before{bottom:-10px;top:-10px}.fc-daygrid-event-dot{border:calc(var(--fc-daygrid-event-dot-width)/2) solid var(--fc-event-border-color);border-radius:calc(var(--fc-daygrid-event-dot-width)/2);box-sizing:content-box;height:0;margin:0 4px;width:0}.fc-daygrid-dot-event .fc-event-time,.fc-daygrid-dot-event .fc-event-title{overflow:hidden;white-space:nowrap}.fc-daygrid-dot-event .fc-event-title{flex-basis:0;flex-grow:1;font-weight:700;min-height:0;min-width:0}";
1135
- injectStyles(css_248z);
1136
-
1137
- export { DayGridHeaderRow, DayGridLayout, DayGridRow, DayGridRows, DayGridView, DayTableSlicer, TableDateProfileGenerator, buildDateDataConfigs, buildDateRenderConfig, buildDateRowConfig, buildDateRowConfigs, buildDayTableModel, buildDayTableRenderRange, computeColFromPosition, computeColWidth, computeRowHeight, createDayHeaderFormatter, getCellEl, getRowEl };
1311
+ export { DayGridHeaderRow, DayGridLayout, DayGridRow, DayGridRows, DayGridView, DayTableSlicer, TableDateProfileGenerator, buildDateDataConfigs, buildDateRenderConfig, buildDateRowConfig, buildDateRowConfigs, buildDayTableModel, buildDayTableRenderRange, computeColFromPosition, computeColWidth, computeRowBasis, createDayHeaderFormatter, dayHeaderMicroFormat, dayMicroWidth, getCellEl, getRowEl };