@fullcalendar/daygrid 7.0.0-beta.4 → 7.0.0-beta.6

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, buildDateStr, formatDayString, buildNavLinkAttrs, getDayClassName, addDays, getEventKey, BaseComponent, StandardEvent, buildEventRangeTimeText, getEventTagAndAttrs, EventContainer, MoreLinkContainer, joinClassNames, getEventRangeMeta, DateComponent, setRef, watchSize, isDimsEqual, hasCustomDayCellContent, DayCellContainer, 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,20 +18,31 @@ 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
  }
35
48
  /*
@@ -41,42 +54,60 @@ function buildDateRenderConfig(context) {
41
54
  return {
42
55
  generatorName: 'dayHeaderContent',
43
56
  customGenerator: options.dayHeaderContent,
44
- classNameGenerator: options.dayHeaderClassNames,
57
+ classNameGenerator: options.dayHeaderClass,
58
+ innerClassNameGenerator: options.dayHeaderInnerClass,
45
59
  didMount: options.dayHeaderDidMount,
46
60
  willUnmount: options.dayHeaderWillUnmount,
61
+ align: options.dayHeaderAlign,
62
+ sticky: options.dayHeaderSticky,
47
63
  };
48
64
  }
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
+ }
49
69
  /*
50
70
  For header cells: data
51
71
  */
52
- function buildDateDataConfigs(dates, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, // TODO: rename to dateHeaderFormat?
53
- context, colSpan = 1, keyPrefix = '') {
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) {
54
76
  const { dateEnv, viewApi, options } = context;
55
77
  return datesRepDistinctDays
56
- ? dates.map((date) => {
57
- const dateMeta = getDateMeta(date, todayRange, null, dateProfile);
58
- const text = dateEnv.format(date, dayHeaderFormat);
59
- const renderProps = Object.assign(Object.assign({}, dateMeta), { date: dateEnv.toDate(date), view: viewApi, text });
60
- const isNavLink = options.navLinks && !dateMeta.isDisabled;
61
- const fullDateStr = buildDateStr(context, date);
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);
62
91
  // for DayGridHeaderCell
63
92
  return {
64
- key: keyPrefix + date.toUTCString(),
93
+ key: keyPrefix + dateMarker.toUTCString(),
94
+ dateMarker,
65
95
  renderProps,
66
- attrs: Object.assign(Object.assign({ 'aria-label': fullDateStr }, (dateMeta.isToday ? { 'aria-current': 'date' } : {})), { 'data-date': formatDayString(date) }),
96
+ attrs: Object.assign(Object.assign(Object.assign({ 'aria-label': fullDateStr }, (dateMeta.isToday ? { 'aria-current': 'date' } : {})), { 'data-date': formatDayString(dateMarker) }), extraAttrs),
67
97
  // for navlink
68
- innerAttrs: isNavLink
69
- ? buildNavLinkAttrs(context, date, undefined, fullDateStr)
98
+ innerAttrs: hasNavLink
99
+ ? buildNavLinkAttrs(context, dateMarker, undefined, fullDateStr)
70
100
  : { 'aria-hidden': true },
71
101
  colSpan,
72
- isNavLink,
73
- className: getDayClassName(dateMeta),
102
+ hasNavLink,
103
+ className,
74
104
  };
75
105
  })
76
- : dates.map((date) => {
77
- const dow = date.getUTCDay();
106
+ : dateMarkers.map((dateMarker, i) => {
107
+ const dow = dateMarker.getUTCDay();
78
108
  const normDate = addDays(firstSunday, dow);
79
- const dayMeta = {
109
+ const dateMeta = {
110
+ date: dateEnv.toDate(dateMarker),
80
111
  dow,
81
112
  isDisabled: false,
82
113
  isFuture: false,
@@ -84,22 +115,25 @@ context, colSpan = 1, keyPrefix = '') {
84
115
  isToday: false,
85
116
  isOther: false,
86
117
  };
87
- const text = dateEnv.format(normDate, dayHeaderFormat);
88
- const renderProps = Object.assign(Object.assign({}, dayMeta), { date, view: viewApi, text });
89
- const fullWeekDayStr = dateEnv.format(normDate, WEEKDAY_FORMAT);
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];
90
125
  // for DayGridHeaderCell
91
126
  return {
92
127
  key: keyPrefix + String(dow),
128
+ dateMarker,
93
129
  renderProps,
94
- attrs: {
95
- 'aria-label': fullWeekDayStr,
96
- },
97
- // for navlink
130
+ attrs: Object.assign({ 'aria-label': fullWeekDayStr }, extraAttrs),
131
+ // NOT a navlink
98
132
  innerAttrs: {
99
133
  'aria-hidden': true, // label already on cell
100
134
  },
101
135
  colSpan,
102
- className: getDayClassName(dayMeta),
136
+ className,
103
137
  };
104
138
  });
105
139
  }
@@ -115,9 +149,9 @@ function getEventPartKey(seg) {
115
149
  }
116
150
  // DayGridRange utils (TODO: move)
117
151
  // -------------------------------------------------------------------------------------------------
118
- function splitSegsByRow(segs, rowCnt) {
152
+ function splitSegsByRow(segs, rowCount) {
119
153
  const byRow = [];
120
- for (let row = 0; row < rowCnt; row++) {
154
+ for (let row = 0; row < rowCount; row++) {
121
155
  byRow[row] = [];
122
156
  }
123
157
  for (const seg of segs) {
@@ -125,15 +159,15 @@ function splitSegsByRow(segs, rowCnt) {
125
159
  }
126
160
  return byRow;
127
161
  }
128
- function splitInteractionByRow(ui, rowCnt) {
162
+ function splitInteractionByRow(ui, rowCount) {
129
163
  const byRow = [];
130
164
  if (!ui) {
131
- for (let row = 0; row < rowCnt; row++) {
165
+ for (let row = 0; row < rowCount; row++) {
132
166
  byRow[row] = null;
133
167
  }
134
168
  }
135
169
  else {
136
- for (let row = 0; row < rowCnt; row++) {
170
+ for (let row = 0; row < rowCount; row++) {
137
171
  byRow[row] = {
138
172
  affectedInstances: ui.affectedInstances,
139
173
  isEvent: ui.isEvent,
@@ -166,58 +200,29 @@ function hasListItemDisplay(seg) {
166
200
  );
167
201
  }
168
202
 
169
- class DayGridBlockEvent extends BaseComponent {
170
- render() {
171
- let { props } = this;
172
- 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 })));
173
- }
174
- }
175
-
176
- class DayGridListEvent extends BaseComponent {
177
- render() {
178
- let { props, context } = this;
179
- let { options } = context;
180
- let { eventRange } = props;
181
- let timeFormat = options.eventTimeFormat || DEFAULT_TABLE_EVENT_TIME_FORMAT;
182
- let timeText = buildEventRangeTimeText(timeFormat, eventRange,
183
- /* slicedStart = */ undefined,
184
- /* slicedEnd = */ undefined, props.isStart, props.isEnd, context,
185
- /* defaultDisplayEventTime = */ true, props.defaultDisplayEventEnd);
186
- let [tag, attrs] = getEventTagAndAttrs(eventRange, context);
187
- return (createElement(EventContainer, Object.assign({}, props, { tag: tag, attrs: attrs, className: 'fc-daygrid-dot-event fc-daygrid-event', defaultGenerator: renderInnerContent, timeText: timeText, isResizing: false, isDateSelecting: false })));
188
- }
189
- }
190
- function renderInnerContent(renderProps) {
191
- return (createElement(Fragment, null,
192
- createElement("div", { className: "fc-daygrid-event-dot", style: { borderColor: renderProps.borderColor || renderProps.backgroundColor } }),
193
- renderProps.timeText && (createElement("div", { className: "fc-event-time" }, renderProps.timeText)),
194
- createElement("div", { className: "fc-event-title" }, renderProps.event.title || createElement(Fragment, null, "\u00A0"))));
195
- }
196
-
197
203
  class DayGridMoreLink extends BaseComponent {
198
204
  render() {
199
205
  let { props } = this;
200
- return (createElement(MoreLinkContainer, { className: joinClassNames('fc-daygrid-more-link', props.isBlock
201
- ? 'fc-daygrid-more-link-block'
202
- : '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: () => {
203
- let forcedInvisibleMap = // TODO: more convenient/DRY
204
- (props.eventDrag ? props.eventDrag.affectedInstances : null) ||
205
- (props.eventResize ? props.eventResize.affectedInstances : null) ||
206
- {};
207
- return (createElement(Fragment, null, props.segs.map((seg) => {
208
- let { eventRange } = seg;
209
- let { instanceId } = eventRange.instance;
210
- return (createElement("div", { key: instanceId, style: {
211
- visibility: forcedInvisibleMap[instanceId] ? 'hidden' : '',
212
- } }, 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))))));
213
- })));
214
- } }));
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
+ }))) }));
215
217
  }
216
218
  }
217
219
 
218
220
  class DayGridCell extends DateComponent {
219
221
  constructor() {
220
222
  super(...arguments);
223
+ // memo
224
+ this.getDateMeta = memoize(getDateMeta);
225
+ this.refineRenderProps = memoizeObjArg(refineRenderProps);
221
226
  // ref
222
227
  this.rootElRef = createRef();
223
228
  this.handleBodyEl = (bodyEl) => {
@@ -251,34 +256,53 @@ class DayGridCell extends DateComponent {
251
256
  // TODO: memoize this
252
257
  const isMonthStart = props.showDayNumber &&
253
258
  shouldDisplayMonthStart(props.date, props.dateProfile.currentRange, dateEnv);
254
- // TODO: memoize this
255
- const dateMeta = getDateMeta(props.date, props.todayRange, null, props.dateProfile);
256
- const baseClassName = joinClassNames('fc-daygrid-day', props.borderStart && 'fc-border-s', props.width != null ? '' : 'fc-liquid', 'fc-flex-col');
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),
276
+ });
257
277
  if (dateMeta.isDisabled) {
258
- return (createElement("div", { role: 'gridcell', "aria-disabled": true, className: joinClassNames(baseClassName, 'fc-day-disabled'), style: {
278
+ return (createElement("div", { role: 'gridcell', "aria-disabled": true, className: joinArrayishClassNames(generateClassName(options.dayCellClass, renderProps), props.className, baseClassName), style: {
259
279
  width: props.width
260
280
  } }));
261
281
  }
262
- const hasDayNumber = props.showDayNumber || hasCustomDayCellContent(options);
263
- const isNavLink = options.navLinks;
264
282
  const fullDateStr = buildDateStr(context, props.date);
265
- return (createElement(DayCellContainer, { tag: "div", className: joinClassNames(baseClassName, props.className), attrs: Object.assign(Object.assign({}, props.attrs), { role: 'gridcell', 'aria-label': fullDateStr }), style: {
266
- width: props.width
267
- }, elRef: this.rootElRef, renderProps: props.renderProps, defaultGenerator: renderTopInner, date: props.date, dateMeta: dateMeta, showDayNumber: props.showDayNumber, isMonthStart: isMonthStart }, (InnerContent) => (createElement(Fragment, null,
268
- hasDayNumber && (createElement("div", { className: "fc-daygrid-day-header" },
269
- createElement(InnerContent, { tag: 'div', attrs: isNavLink
270
- ? buildNavLinkAttrs(context, props.date, undefined, fullDateStr)
271
- : { 'aria-hidden': true } // label already on cell
272
- , className: joinClassNames('fc-daygrid-day-number', isMonthStart && 'fc-daygrid-month-start') }))),
273
- createElement("div", { className: joinClassNames('fc-daygrid-day-body', props.isTall && 'fc-daygrid-day-body-tall', props.fgLiquidHeight ? 'fc-liquid' : 'fc-grow'), ref: this.handleBodyEl },
274
- createElement("div", { className: 'fc-daygrid-day-events', style: { height: props.fgHeight } }, props.fg),
275
- 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 }))))));
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)) })))));
276
300
  }
277
301
  }
278
302
  // Utils
279
303
  // -------------------------------------------------------------------------------------------------
280
304
  function renderTopInner(props) {
281
- return props.dayNumberText || createElement(Fragment, null, "\u00A0");
305
+ return props.text || createElement(Fragment, null, "\u00A0"); // TODO: DRY?
282
306
  }
283
307
  function shouldDisplayMonthStart(date, currentRange, dateEnv) {
284
308
  const { start: currentStart, end: currentEnd } = currentRange;
@@ -295,6 +319,16 @@ function shouldDisplayMonthStart(date, currentRange, dateEnv) {
295
319
  // a month-start that's within the current range?
296
320
  (dateEnv.getDay(date) === 1 && date.valueOf() < currentEnd.valueOf()));
297
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
+ }
298
332
 
299
333
  function computeFgSegVerticals(segs, segHeightMap, cells, maxHeight, strictOrder, allowSlicing = true, dayMaxEvents, dayMaxEventRows) {
300
334
  let maxCoord;
@@ -417,20 +451,19 @@ function compileSegMap(segs, segMap) {
417
451
  return res;
418
452
  }
419
453
 
420
- /*
421
- TODO: move this so @fullcalendar/daygrid
422
- */
423
- function buildDayTableModel(dateProfile, dateProfileGenerator) {
424
- let daySeries = new DaySeriesModel(dateProfile.renderRange, dateProfileGenerator);
425
- 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);
426
459
  }
427
- function computeColWidth(colCnt, colMinWidth, viewportWidth) {
460
+ function computeColWidth(colCount, colMinWidth, viewportWidth) {
428
461
  if (viewportWidth == null) {
429
462
  return [undefined, undefined];
430
463
  }
431
- const colTempWidth = viewportWidth / colCnt;
464
+ const colTempWidth = viewportWidth / colCount;
432
465
  if (colTempWidth < colMinWidth) {
433
- return [colMinWidth * colCnt, colMinWidth];
466
+ return [colMinWidth * colCount, colMinWidth];
434
467
  }
435
468
  return [viewportWidth, undefined];
436
469
  }
@@ -456,29 +489,24 @@ function computeTopFromDate(date, cellRows, rowHeightMap, adjust = 0) {
456
489
  /*
457
490
  FYI, `width` is not dependable for aligning completely to farside
458
491
  */
459
- function computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl) {
492
+ function computeHorizontalsFromSeg(seg, colWidth, colCount) {
460
493
  let fromStart;
461
494
  let fromEnd;
462
495
  if (colWidth != null) {
463
496
  fromStart = seg.start * colWidth;
464
- fromEnd = (colCnt - seg.end) * colWidth;
497
+ fromEnd = (colCount - seg.end) * colWidth;
465
498
  }
466
499
  else {
467
- const colWidthFrac = 1 / colCnt;
500
+ const colWidthFrac = 1 / colCount;
468
501
  fromStart = fracToCssDim(seg.start * colWidthFrac);
469
502
  fromEnd = fracToCssDim(1 - seg.end * colWidthFrac);
470
503
  }
471
- if (isRtl) {
472
- return { right: fromStart, left: fromEnd };
473
- }
474
- else {
475
- return { left: fromStart, right: fromEnd };
476
- }
504
+ return { insetInlineStart: fromStart, insetInlineEnd: fromEnd };
477
505
  }
478
- function computeColFromPosition(positionLeft, elWidth, colWidth, colCnt, isRtl) {
479
- const realColWidth = colWidth != null ? colWidth : elWidth / colCnt;
506
+ function computeColFromPosition(positionLeft, elWidth, colWidth, colCount, isRtl) {
507
+ const realColWidth = colWidth != null ? colWidth : elWidth / colCount;
480
508
  const colFromLeft = Math.floor(positionLeft / realColWidth);
481
- const col = isRtl ? (colCnt - colFromLeft - 1) : colFromLeft;
509
+ const col = isRtl ? (colCount - colFromLeft - 1) : colFromLeft;
482
510
  const left = colFromLeft * realColWidth;
483
511
  const right = left + realColWidth;
484
512
  return { col, left, right };
@@ -501,13 +529,17 @@ function computeRowFromPosition(positionTop, cellRows, rowHeightMap) {
501
529
  // Hit Element
502
530
  // -------------------------------------------------------------------------------------------------
503
531
  function getRowEl(rootEl, row) {
504
- return rootEl.querySelectorAll(':scope > [role=row]')[row];
532
+ return rootEl.querySelectorAll('[role=row]')[row];
505
533
  }
506
534
  function getCellEl(rowEl, col) {
507
- return rowEl.querySelectorAll(':scope > [role=gridcell]')[col];
535
+ return rowEl.querySelectorAll('[role=gridcell]')[col];
508
536
  }
509
537
  // Header Formatting
510
538
  // -------------------------------------------------------------------------------------------------
539
+ const dayMicroWidth = 50;
540
+ const dayHeaderMicroFormat = createFormatter({
541
+ weekday: 'narrow'
542
+ });
511
543
  function createDayHeaderFormatter(explicitFormat, datesRepDistinctDays, dateCnt) {
512
544
  return explicitFormat || computeFallbackHeaderFormat(datesRepDistinctDays, dateCnt);
513
545
  }
@@ -515,13 +547,23 @@ function createDayHeaderFormatter(explicitFormat, datesRepDistinctDays, dateCnt)
515
547
  function computeFallbackHeaderFormat(datesRepDistinctDays, dayCnt) {
516
548
  // if more than one week row, or if there are a lot of columns with not much space,
517
549
  // put just the day numbers will be in each cell
518
- if (!datesRepDistinctDays || dayCnt > 10) {
550
+ if (!datesRepDistinctDays) {
519
551
  return createFormatter({ weekday: 'short' }); // "Sat"
520
552
  }
521
553
  if (dayCnt > 1) {
522
- 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
+ });
523
560
  }
524
- return createFormatter({ weekday: 'long' }); // "Saturday"
561
+ return createFormatter({
562
+ weekday: 'long',
563
+ weekdayJustify: 'start',
564
+ day: 'numeric',
565
+ omitCommas: true,
566
+ });
525
567
  }
526
568
 
527
569
  class DayGridEventHarness extends Component {
@@ -532,7 +574,7 @@ class DayGridEventHarness extends Component {
532
574
  }
533
575
  render() {
534
576
  const { props } = this;
535
- 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));
536
578
  }
537
579
  componentDidMount() {
538
580
  const rootEl = this.rootElRef.current; // TODO: make dynamic with useEffect
@@ -562,6 +604,8 @@ class DayGridRow extends BaseComponent {
562
604
  this.segHeightRefMap = new RefMap(() => {
563
605
  afterSize(this.handleSegPositioning);
564
606
  });
607
+ // memo
608
+ this.buildWeekNumberRenderProps = memoize(buildWeekNumberRenderProps);
565
609
  this.handleRootEl = (rootEl) => {
566
610
  this.rootEl = rootEl;
567
611
  setRef(this.props.rootElRef, rootEl);
@@ -574,7 +618,7 @@ class DayGridRow extends BaseComponent {
574
618
  const { props, context, headerHeightRefMap, mainHeightRefMap } = this;
575
619
  const { cells } = props;
576
620
  const { options } = context;
577
- const weekDate = props.cells[0].date;
621
+ const weekDateMarker = props.cells[0].date;
578
622
  const fgLiquidHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;
579
623
  // TODO: memoize? sort all types of segs?
580
624
  const fgEventSegs = sortEventSegs(props.fgEventSegs, options.eventOrder);
@@ -593,24 +637,29 @@ class DayGridRow extends BaseComponent {
593
637
  }
594
638
  const highlightSegs = this.getHighlightSegs();
595
639
  const mirrorSegs = this.getMirrorSegs();
596
- const forcedInvisibleMap = // TODO: more convenient/DRY
597
- (props.eventDrag && props.eventDrag.affectedInstances) ||
598
- (props.eventResize && props.eventResize.affectedInstances) ||
599
- {};
600
- const isNavLink = options.navLinks;
601
- const fullWeekStr = buildDateStr(context, weekDate, 'week');
640
+ const hasNavLink = options.navLinks;
641
+ const fullWeekStr = buildDateStr(context, weekDateMarker, 'week');
642
+ const weekNumberRenderProps = this.buildWeekNumberRenderProps(weekDateMarker, context, props.cellIsNarrow, hasNavLink);
602
643
  return (createElement("div", { role: props.role /* !!! */, "aria-label": props.role === 'row' // HACK
603
644
  ? fullWeekStr
604
645
  : undefined // can't have label on non-role div
605
- , className: joinClassNames('fc-flex-row fc-rel', props.className), style: {
606
- minHeight: props.minHeight,
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,
607
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 })),
608
656
  this.renderFillSegs(props.businessHourSegs, 'non-business'),
609
657
  this.renderFillSegs(props.bgEventSegs, 'bg-event'),
610
658
  this.renderFillSegs(highlightSegs, 'highlight'),
611
- createElement("div", { className: 'fc-flex-row fc-liquid fc-rel' }, props.cells.map((cell, col) => {
612
- const normalFgNodes = this.renderFgSegs(maxMainTop, renderableSegsByCol[col], segTops, props.todayRange, forcedInvisibleMap);
613
- 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),
614
663
  // content
615
664
  segs: segsByCol[col], hiddenSegs: hiddenSegsByCol[col], fgLiquidHeight: fgLiquidHeight, fg: (createElement(Fragment, null, normalFgNodes)), eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
616
665
  // render hooks
@@ -619,21 +668,16 @@ class DayGridRow extends BaseComponent {
619
668
  fgHeight: heightsByCol[col], width: props.colWidth,
620
669
  // refs
621
670
  headerHeightRef: headerHeightRefMap.createRef(cell.key), mainHeightRef: mainHeightRefMap.createRef(cell.key) }));
622
- })),
623
- props.showWeekNumbers && (createElement(WeekNumberContainer, { tag: 'div', attrs: Object.assign(Object.assign({}, (isNavLink
624
- ? buildNavLinkAttrs(context, weekDate, 'week', fullWeekStr, /* isTabbable = */ false)
625
- : {})), { 'role': undefined, 'aria-hidden': true }), className: 'fc-daygrid-week-number', date: weekDate, defaultFormat: DEFAULT_WEEK_NUM_FORMAT })),
626
- this.renderFgSegs(maxMainTop, mirrorSegs, segTops, props.todayRange, {}, // forcedInvisibleMap
627
- Boolean(props.eventDrag), Boolean(props.eventResize), false)));
628
- }
629
- renderFgSegs(headerHeight, segs, segTops, todayRange, forcedInvisibleMap, isDragging, isResizing, isDateSelecting) {
671
+ }),
672
+ this.renderFgSegs(maxMainTop, mirrorSegs, segTops, props.todayRange,
673
+ /* isMirror = */ true)));
674
+ }
675
+ renderFgSegs(headerHeight, segs, segTops, todayRange, isMirror) {
630
676
  var _a;
631
- const { props, context, segHeightRefMap } = this;
632
- const { isRtl } = context;
633
- const { colWidth, eventSelection } = props;
634
- const colCnt = props.cells.length;
677
+ const { props, segHeightRefMap } = this;
678
+ const { colWidth, eventSelection, cellIsMicro } = props;
679
+ const colCount = props.cells.length;
635
680
  const defaultDisplayEventEnd = props.cells.length === 1;
636
- const isMirror = isDragging || isResizing || isDateSelecting;
637
681
  const nodes = [];
638
682
  for (const seg of segs) {
639
683
  const key = getEventPartKey(seg);
@@ -642,39 +686,43 @@ class DayGridRow extends BaseComponent {
642
686
  if (standinFor) {
643
687
  continue;
644
688
  }
645
- const { left, right } = computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl);
689
+ const { insetInlineStart, insetInlineEnd } = computeHorizontalsFromSeg(seg, colWidth, colCount);
646
690
  const localTop = (_a = segTops.get(standinFor ? getEventPartKey(standinFor) : key)) !== null && _a !== void 0 ? _a : (isMirror ? 0 : undefined);
647
691
  const top = headerHeight != null && localTop != null
648
692
  ? headerHeight + localTop
649
693
  : undefined;
650
- const isInvisible = standinFor || forcedInvisibleMap[instanceId] || top == null;
651
- nodes.push(createElement(DayGridEventHarness, { key: key, className: seg.start ? 'fc-border-transparent fc-border-s' : '', style: {
652
- 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,
653
700
  top,
654
- left,
655
- right,
701
+ insetInlineStart,
702
+ insetInlineEnd,
703
+ zIndex: 0, // container inner z-indexes
656
704
  }, heightRef: (!standinFor && !isMirror)
657
705
  ? segHeightRefMap.createRef(key)
658
- : 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)))));
659
708
  }
660
709
  return nodes;
661
710
  }
662
711
  renderFillSegs(segs, fillType) {
663
712
  const { props, context } = this;
664
- const { isRtl } = context;
665
713
  const { todayRange, colWidth } = props;
666
- const colCnt = props.cells.length;
714
+ const colCount = props.cells.length;
667
715
  const nodes = [];
668
716
  for (const seg of segs) {
669
717
  const key = buildEventRangeKey(seg.eventRange); // TODO: use different type of key than fg!?
670
- const { left, right } = computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl);
718
+ const { insetInlineStart, insetInlineEnd } = computeHorizontalsFromSeg(seg, colWidth, colCount);
671
719
  const isVisible = !seg.standinFor;
672
- nodes.push(createElement("div", { key: key, className: "fc-fill-y", style: {
720
+ nodes.push(createElement("div", { key: key, className: classNames.fillY, style: {
673
721
  visibility: isVisible ? '' : 'hidden',
674
- left,
675
- right,
722
+ insetInlineStart,
723
+ insetInlineEnd,
676
724
  } }, fillType === 'bg-event' ?
677
- 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))));
678
726
  }
679
727
  return createElement(Fragment, {}, ...nodes); // TODO: shouldn't this be an array, so keyed?
680
728
  }
@@ -738,6 +786,22 @@ class DayGridRow extends BaseComponent {
738
786
  return props.dateSelectionSegs;
739
787
  }
740
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
+ }
741
805
 
742
806
  class DayGridRows extends DateComponent {
743
807
  constructor() {
@@ -773,45 +837,36 @@ class DayGridRows extends DateComponent {
773
837
  render() {
774
838
  let { props, context, rowHeightRefMap } = this;
775
839
  let { options } = context;
776
- let rowCnt = props.cellRows.length;
777
- let fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, rowCnt);
778
- let bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, rowCnt);
779
- let businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, rowCnt);
780
- let dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, rowCnt);
781
- let eventDragByRow = this.splitEventDrag(props.eventDrag, rowCnt);
782
- 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);
783
847
  let isHeightAuto = getIsHeightAuto(options);
784
848
  let rowHeightsRedistribute = !props.forPrint && !isHeightAuto;
785
- let [rowMinHeight, isCompact] = computeRowHeight(props.visibleWidth, rowCnt, isHeightAuto, props.forPrint, options);
786
- return (createElement("div", { role: 'rowgroup', className: joinClassNames(
849
+ let rowBasis = computeRowBasis(props.visibleWidth, rowCount, isHeightAuto, options);
850
+ return (createElement("div", { role: 'rowgroup', className: joinClassNames(props.className,
787
851
  // HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
788
852
  // https://stackoverflow.com/a/60256345
789
- !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, role: 'row', dateProfile: props.dateProfile, todayRange: props.todayRange, cells: cells, showDayNumbers: rowCnt > 1, showWeekNumbers: rowCnt > 1 && 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,
790
854
  // if not auto-height, distribute height of container somewhat evently to rows
791
- // (treat all as zero, distribute height, then ensure min-heights -- the inner content height)
792
- className: joinClassNames(rowHeightsRedistribute && 'fc-grow fc-basis0', rowCnt > 1 && 'fc-break-inside-avoid', // don't avoid breaks for single tall row
793
- 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),
794
857
  // content
795
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,
796
859
  // dimensions
797
- colWidth: props.colWidth, minHeight: rowMinHeight,
860
+ colWidth: props.colWidth, basis: rowBasis,
798
861
  // refs
799
862
  heightRef: rowHeightRefMap.createRef(cells[0].key) })))));
800
863
  }
801
- componentDidMount() {
802
- this.disconnectWidth = watchWidth(this.rootEl, (width) => {
803
- this.setState({ width });
804
- });
805
- }
806
- componentWillUnmount() {
807
- this.disconnectWidth();
808
- }
809
864
  // Hit System
810
865
  // -----------------------------------------------------------------------------------------------
811
- queryHit(positionLeft, positionTop, elWidth) {
812
- const { props, context } = this;
813
- const colCnt = props.cellRows[0].length;
814
- 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);
815
870
  const { row, top, bottom } = computeRowFromPosition(positionTop, props.cellRows, this.rowHeightRefMap.current);
816
871
  const cell = props.cellRows[row][col];
817
872
  const cellStartDate = cell.date;
@@ -822,8 +877,7 @@ class DayGridRows extends DateComponent {
822
877
  start: cellStartDate,
823
878
  end: cellEndDate,
824
879
  }, allDay: true }, cell.dateSpanProps),
825
- // HACK. TODO: This is expensive to do every hit-query
826
- dayEl: getCellEl(getRowEl(this.rootEl, row), col),
880
+ getDayEl: () => getCellEl(getRowEl(this.rootEl, row), col),
827
881
  rect: {
828
882
  left,
829
883
  right,
@@ -839,40 +893,41 @@ class DayGridRows extends DateComponent {
839
893
  function isSegAllDay(seg) {
840
894
  return seg.eventRange.def.allDay;
841
895
  }
842
- function computeRowHeight(visibleWidth, // should INCLUDE any scrollbar width to avoid oscillation
843
- 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) {
844
903
  if (visibleWidth != null) {
845
904
  // ensure a consistent row min-height modelled after a month with 6 rows respecting aspectRatio
846
905
  // will result in same minHeight regardless of weekends, dayMinWidth, height:auto
847
- const rowMinHeight = visibleWidth / options.aspectRatio / 6;
848
- return [
849
- forPrint
850
- // special-case for print, which condenses whole-page width without notifying
851
- // this is value that looks natural on paper for portrait/landscape
852
- ? '6em'
853
- // don't give minHeight when single-month non-auto-height
854
- // TODO: better way to detect this with DateProfile?
855
- : (rowCnt > 6 || isHeightAuto)
856
- ? rowMinHeight
857
- : undefined,
858
- // isCompact?: just before most lone +more links hit bottom of cell
859
- rowMinHeight < 70,
860
- ];
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;
861
910
  }
862
- return [undefined, false];
911
+ return 0;
863
912
  }
864
913
 
865
914
  class DayGridHeaderCell extends BaseComponent {
866
915
  constructor() {
867
916
  super(...arguments);
868
917
  this.handleInnerEl = (innerEl) => {
869
- if (this.disconectInnerHeight) {
870
- this.disconectInnerHeight();
871
- this.disconectInnerHeight = undefined;
918
+ if (this.disconnectSize) {
919
+ this.disconnectSize();
920
+ this.disconnectSize = undefined;
872
921
  }
873
922
  if (innerEl) {
874
- this.disconectInnerHeight = watchHeight(innerEl, (height) => {
923
+ this.disconnectSize = watchSize(innerEl, (width, height) => {
875
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
+ }
876
931
  });
877
932
  }
878
933
  else {
@@ -881,18 +936,54 @@ class DayGridHeaderCell extends BaseComponent {
881
936
  };
882
937
  }
883
938
  render() {
884
- const { props } = this;
939
+ const { props, state, context } = this;
885
940
  const { renderConfig, dataConfig } = props;
886
941
  // HACK
887
942
  const isDisabled = dataConfig.renderProps.isDisabled;
888
- return (createElement(ContentContainer, { tag: 'div', attrs: Object.assign({ role: 'columnheader', 'aria-colspan': dataConfig.colSpan }, dataConfig.attrs), className: joinClassNames('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', dataConfig.className), style: {
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: {
889
976
  width: props.colWidth != null
890
977
  ? props.colWidth * (dataConfig.colSpan || 1)
891
978
  : undefined,
892
- }, renderProps: dataConfig.renderProps, generatorName: renderConfig.generatorName, customGenerator: renderConfig.customGenerator, defaultGenerator: renderText, classNameGenerator:
979
+ }, renderProps: finalRenderProps, generatorName: renderConfig.generatorName, customGenerator: renderConfig.customGenerator, defaultGenerator: renderText, classNameGenerator:
893
980
  // don't use custom classNames if disabled
894
981
  // TODO: make DRY with DayCellContainer
895
- isDisabled ? undefined : renderConfig.classNameGenerator, didMount: renderConfig.didMount, willUnmount: renderConfig.willUnmount }, (InnerContainer) => (createElement(InnerContainer, { tag: '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) })))));
896
987
  }
897
988
  }
898
989
 
@@ -916,8 +1007,14 @@ class DayGridHeaderRow extends BaseComponent {
916
1007
  };
917
1008
  }
918
1009
  render() {
919
- const { props } = this;
920
- return (createElement("div", { role: props.role /* !!! */, "aria-rowindex": props.rowIndex != null ? 1 + props.rowIndex : undefined, 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);
921
1018
  }
922
1019
  }
923
1020
 
@@ -927,9 +1024,10 @@ TODO: kill this class in favor of DayGridHeaderRows?
927
1024
  class DayGridHeader extends BaseComponent {
928
1025
  render() {
929
1026
  const { props } = this;
930
- return (createElement("div", { role: 'rowgroup', className: joinClassNames(props.className, 'fc-flex-col', props.width == null && 'fc-liquid'), style: {
931
- width: props.width
932
- } }, props.headerTiers.map((rowConfig, tierNum) => (createElement(DayGridHeaderRow, Object.assign({}, rowConfig, { key: tierNum, role: 'row', 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 }))))));
933
1031
  }
934
1032
  }
935
1033
 
@@ -939,37 +1037,54 @@ class DayGridLayoutNormal extends BaseComponent {
939
1037
  this.handleScroller = (scroller) => {
940
1038
  setRef(this.props.scrollerRef, scroller);
941
1039
  };
1040
+ this.handleTotalWidth = (totalWidth) => {
1041
+ this.setState({ totalWidth });
1042
+ };
942
1043
  this.handleClientWidth = (clientWidth) => {
943
1044
  this.setState({ clientWidth });
944
1045
  };
945
- this.handleEndScrollbarWidth = (endScrollbarWidth) => {
946
- this.setState({ endScrollbarWidth });
947
- };
948
1046
  }
949
1047
  render() {
950
1048
  const { props, state, context } = this;
951
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
+ }
952
1058
  const verticalScrollbars = !props.forPrint && !getIsHeightAuto(options);
953
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);
954
1064
  return (createElement(Fragment, null,
955
- options.dayHeaders && (createElement("div", { className: joinClassNames(props.forPrint ? 'fc-print-header' : 'fc-flex-row', // col for print, row for screen
956
- 'fc-border-b') },
957
- createElement(DayGridHeader, { headerTiers: props.headerTiers, className: joinClassNames('fc-daygrid-header', stickyHeaderDates && 'fc-table-header-sticky') }),
958
- Boolean(state.endScrollbarWidth) && (createElement("div", { className: 'fc-border-s fc-filler', style: { minWidth: state.endScrollbarWidth } })))),
959
- 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,
960
1077
  // HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
961
1078
  // https://stackoverflow.com/a/60256345
962
- !props.forPrint && 'fc-flex-col', verticalScrollbars && 'fc-liquid'), ref: this.handleScroller },
963
- 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,
964
1081
  // content
965
1082
  fgEventSegs: props.fgEventSegs, bgEventSegs: props.bgEventSegs, businessHourSegs: props.businessHourSegs, dateSelectionSegs: props.dateSelectionSegs, eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
966
1083
  // dimensions
967
- visibleWidth: // TODO: DRY
968
- state.clientWidth != null && state.endScrollbarWidth != null
969
- ? state.clientWidth + state.endScrollbarWidth
970
- : undefined,
1084
+ visibleWidth: totalWidth, cellIsNarrow: cellIsNarrow, cellIsMicro: cellIsMicro,
971
1085
  // refs
972
- rowHeightRefMap: props.rowHeightRefMap }))));
1086
+ rowHeightRefMap: props.rowHeightRefMap })),
1087
+ createElement(Ruler, { widthRef: this.handleTotalWidth })));
973
1088
  }
974
1089
  }
975
1090
 
@@ -981,43 +1096,54 @@ class DayGridLayoutPannable extends BaseComponent {
981
1096
  this.footerScrollerRef = createRef();
982
1097
  // Sizing
983
1098
  // -----------------------------------------------------------------------------------------------
1099
+ this.handleTotalWidth = (totalWidth) => {
1100
+ this.setState({ totalWidth });
1101
+ };
984
1102
  this.handleClientWidth = (clientWidth) => {
985
1103
  this.setState({ clientWidth });
986
1104
  };
987
- this.handleEndScrollbarWidth = (endScrollbarWidth) => {
988
- this.setState({ endScrollbarWidth });
989
- };
990
1105
  }
991
1106
  render() {
992
1107
  const { props, state, context } = this;
993
1108
  const { options } = context;
1109
+ const { totalWidth, clientWidth } = state;
1110
+ const endScrollbarWidth = (totalWidth != null && clientWidth != null)
1111
+ ? totalWidth - clientWidth
1112
+ : undefined;
994
1113
  const verticalScrollbars = !props.forPrint && !getIsHeightAuto(options);
995
1114
  const stickyHeaderDates = !props.forPrint && getStickyHeaderDates(options);
996
1115
  const stickyFooterScrollbar = !props.forPrint && getStickyFooterScrollbar(options);
997
- const colCnt = props.cellRows[0].length;
998
- 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);
999
1120
  return (createElement(Fragment, null,
1000
- options.dayHeaders && (createElement("div", { className: 'fc-print-header' },
1001
- 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 },
1002
- createElement(DayGridHeader, { headerTiers: props.headerTiers, colWidth: colWidth, width: canvasWidth }),
1003
- 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
+ }) }))),
1004
1132
  createElement(Scroller, { vertical: verticalScrollbars, horizontal: true, hideScrollbars: stickyFooterScrollbar ||
1005
1133
  props.forPrint // prevents blank space in print-view on Safari
1006
- , className: joinClassNames('fc-daygrid-body',
1134
+ , className: joinArrayishClassNames(options.tableBodyClass, props.borderlessX && classNames.borderlessX, stickyHeaderDates && classNames.borderlessTop, (stickyHeaderDates || props.noEdgeEffects) && classNames.noEdgeEffects,
1007
1135
  // HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
1008
1136
  // https://stackoverflow.com/a/60256345
1009
- !props.forPrint && 'fc-flex-col', verticalScrollbars && 'fc-liquid'), ref: this.bodyScrollerRef, clientWidthRef: this.handleClientWidth, endScrollbarWidthRef: this.handleEndScrollbarWidth },
1010
- 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,
1011
1139
  // content
1012
1140
  fgEventSegs: props.fgEventSegs, bgEventSegs: props.bgEventSegs, businessHourSegs: props.businessHourSegs, dateSelectionSegs: props.dateSelectionSegs, eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
1013
1141
  // dimensions
1014
- colWidth: colWidth, width: canvasWidth, visibleWidth: // TODO: DRY
1015
- state.clientWidth != null && state.endScrollbarWidth != null
1016
- ? state.clientWidth + state.endScrollbarWidth
1017
- : undefined,
1142
+ colWidth: colWidth, width: canvasWidth, visibleWidth: totalWidth, cellIsNarrow: cellIsNarrow, cellIsMicro: cellIsMicro,
1018
1143
  // refs
1019
1144
  rowHeightRefMap: props.rowHeightRefMap })),
1020
- 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 })));
1021
1147
  }
1022
1148
  // Lifecycle
1023
1149
  // -----------------------------------------------------------------------------------------------
@@ -1072,7 +1198,7 @@ class DayGridLayout extends BaseComponent {
1072
1198
  }
1073
1199
  }
1074
1200
  };
1075
- this.handleScrollEnd = ({ isUser }) => {
1201
+ this.handleScrollEnd = (isUser) => {
1076
1202
  if (isUser) {
1077
1203
  this.scrollDate = null;
1078
1204
  }
@@ -1088,7 +1214,8 @@ class DayGridLayout extends BaseComponent {
1088
1214
  'aria-colcount': props.cellRows[0].length,
1089
1215
  'aria-labelledby': props.labelId,
1090
1216
  'aria-label': props.labelStr,
1091
- }, className: joinClassNames(props.className, 'fc-print-root fc-border') }, options.dayMinWidth ? (createElement(DayGridLayoutPannable, Object.assign({}, commonLayoutProps, { dayMinWidth: options.dayMinWidth }))) : (createElement(DayGridLayoutNormal, Object.assign({}, commonLayoutProps)))));
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)))));
1092
1219
  }
1093
1220
  // Lifecycle
1094
1221
  // -----------------------------------------------------------------------------------------------
@@ -1126,18 +1253,19 @@ class DayGridView extends BaseComponent {
1126
1253
  }
1127
1254
  render() {
1128
1255
  const { props, context } = this;
1129
- const { options } = context;
1130
- const dayTableModel = this.buildDayTableModel(props.dateProfile, context.dateProfileGenerator);
1131
- const datesRepDistinctDays = dayTableModel.rowCnt === 1;
1132
- const dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, datesRepDistinctDays, dayTableModel.colCnt);
1133
- 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);
1134
1262
  return (createElement(NowTimer, { unit: "day" }, (nowDate, todayRange) => {
1135
- const headerTiers = this.buildDateRowConfigs(dayTableModel.headerDates, datesRepDistinctDays, props.dateProfile, todayRange, dayHeaderFormat, context);
1136
- return (createElement(DayGridLayout, { labelId: props.labelId, labelStr: props.labelStr, 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,
1137
1265
  // header content
1138
1266
  headerTiers: headerTiers,
1139
1267
  // body content
1140
- 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 }));
1141
1269
  }));
1142
1270
  }
1143
1271
  }
@@ -1173,14 +1301,11 @@ function buildDayTableRenderRange(props) {
1173
1301
  // TODO: instead of these date-math gymnastics (for multimonth view),
1174
1302
  // compute dateprofiles of all months, then use start of first and end of last.
1175
1303
  let lastMonthRenderStart = dateEnv.startOfWeek(dateEnv.startOfMonth(addDays(currentRange.end, -1)));
1176
- let rowCnt = Math.ceil(// could be partial weeks due to hiddenDays
1304
+ let rowCount = Math.ceil(// could be partial weeks due to hiddenDays
1177
1305
  diffWeeks(lastMonthRenderStart, end));
1178
- end = addWeeks(end, 6 - rowCnt);
1306
+ end = addWeeks(end, 6 - rowCount);
1179
1307
  }
1180
1308
  return { start, end };
1181
1309
  }
1182
1310
 
1183
- 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}";
1184
- injectStyles(css_248z);
1185
-
1186
- 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 };