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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/internal.cjs CHANGED
@@ -5,9 +5,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var internal_cjs = require('@fullcalendar/core/internal.cjs');
6
6
  var preact_cjs = require('@fullcalendar/core/preact.cjs');
7
7
 
8
- var css_248z = ":root{--fc-daygrid-event-dot-width:8px}.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;z-index:5}.fc-daygrid-cell.fc-day-today{background-color:var(--fc-today-bg-color)}.fc-daygrid-row-spacious .fc-daygrid-cell-inner{min-height:3em}.fc-daygrid-cell-header{display:flex;flex-direction:row-reverse}.fc-day-other .fc-daygrid-cell-header{opacity:.3}.fc-daygrid-cell-number{padding:4px;position:relative;z-index:4}.fc-daygrid-month-start{font-size:1.1em;font-weight:700}.fc-daygrid-cell-footer{align-items:flex-start;display:flex;flex-direction:column;font-size:.85em;margin:0 2px}.fc-daygrid-row-spacious .fc-daygrid-cell-footer{margin-bottom:1em!important}.fc-daygrid-row-compact .fc-daygrid-cell-footer{align-items:stretch}.fc-daygrid-more-link{border-radius:3px;cursor:pointer;line-height:1;margin-top:1px;max-width:100%;overflow:hidden;padding:2px;position:relative;white-space:nowrap;z-index:4}.fc-daygrid-more-link:hover{background-color:rgba(0,0,0,.1)}.fc-daygrid-row-compact .fc-daygrid-more-link{border:1px solid var(--fc-event-border-color);padding:1px}.fc-daygrid-cell .fc-non-business{z-index:1}.fc-daygrid-cell .fc-bg-event{z-index:2}.fc-daygrid-cell .fc-highlight{z-index:3}.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-top:1px;z-index:6}.fc-daygrid-event.fc-event-mirror{z-index:7}.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}.fc-daygrid-dot-event.fc-event-mirror,.fc-daygrid-dot-event:hover{background:rgba(0,0,0,.1)}.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-width:0}";
9
- internal_cjs.injectStyles(css_248z);
10
-
11
8
  class DayTableSlicer extends internal_cjs.Slicer {
12
9
  constructor() {
13
10
  super(...arguments);
@@ -18,193 +15,110 @@ class DayTableSlicer extends internal_cjs.Slicer {
18
15
  }
19
16
  }
20
17
 
21
- class TableDateProfileGenerator extends internal_cjs.DateProfileGenerator {
22
- // Computes the date range that will be rendered
23
- buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay) {
24
- let renderRange = super.buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay);
25
- let { props } = this;
26
- return buildDayTableRenderRange({
27
- currentRange: renderRange,
28
- snapToWeek: /^(year|month)$/.test(currentRangeUnit),
29
- fixedWeekCount: props.fixedWeekCount,
30
- dateEnv: props.dateEnv,
31
- });
32
- }
33
- }
34
- function buildDayTableRenderRange(props) {
35
- let { dateEnv, currentRange } = props;
36
- let { start, end } = currentRange;
37
- let endOfWeek;
38
- // year and month views should be aligned with weeks. this is already done for week
39
- if (props.snapToWeek) {
40
- start = dateEnv.startOfWeek(start);
41
- // make end-of-week if not already
42
- endOfWeek = dateEnv.startOfWeek(end);
43
- if (endOfWeek.valueOf() !== end.valueOf()) {
44
- end = internal_cjs.addWeeks(endOfWeek, 1);
45
- }
46
- }
47
- // ensure 6 weeks
48
- if (props.fixedWeekCount) {
49
- // TODO: instead of these date-math gymnastics (for multimonth view),
50
- // compute dateprofiles of all months, then use start of first and end of last.
51
- let lastMonthRenderStart = dateEnv.startOfWeek(dateEnv.startOfMonth(internal_cjs.addDays(currentRange.end, -1)));
52
- let rowCnt = Math.ceil(// could be partial weeks due to hiddenDays
53
- internal_cjs.diffWeeks(lastMonthRenderStart, end));
54
- end = internal_cjs.addWeeks(end, 6 - rowCnt);
55
- }
56
- return { start, end };
57
- }
58
-
59
- function renderInner(renderProps) {
60
- return renderProps.text;
61
- }
62
- function buildDayTableModel(dateProfile, dateProfileGenerator) {
63
- let daySeries = new internal_cjs.DaySeriesModel(dateProfile.renderRange, dateProfileGenerator);
64
- return new internal_cjs.DayTableModel(daySeries, /year|month|week/.test(dateProfile.currentRangeUnit));
65
- }
66
- function computeColWidth(colCnt, colMinWidth, viewportWidth) {
67
- if (viewportWidth == null) {
68
- return [undefined, undefined];
69
- }
70
- const colTempWidth = viewportWidth / colCnt;
71
- if (colTempWidth < colMinWidth) {
72
- return [colMinWidth * colCnt, colMinWidth];
73
- }
74
- return [viewportWidth, undefined];
75
- }
76
- function buildHeaderTiers(dates, datesRepDistinctDays) {
77
- return [
78
- datesRepDistinctDays
79
- ? dates.map((date) => ({ colSpan: 1, date }))
80
- : dates.map((date) => ({ colSpan: 1, dow: date.getUTCDay() }))
81
- ];
82
- }
83
- // Positioning
18
+ // TODO: converge types with DayTableCell and DayCellContainer (the component) and refineRenderProps
19
+ // the generation of DayTableCell will be distinct (for the BODY cells)
20
+ // but can share some of the same types/utils
21
+ // Date Cells
84
22
  // -------------------------------------------------------------------------------------------------
85
- function computeTopFromDate(date, cellRows, rowHeightMap, adjust = 0) {
86
- let top = 0;
87
- for (const cells of cellRows) {
88
- const start = cells[0].date;
89
- const end = cells[cells.length - 1].date;
90
- const key = start.toISOString();
91
- if (date >= start && date <= end) {
92
- return top;
93
- }
94
- const rowHeight = rowHeightMap.get(key);
95
- if (rowHeight == null) {
96
- return; // denote unknown
97
- }
98
- top += rowHeight + adjust;
99
- }
100
- return top;
101
- }
102
- function computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl) {
103
- let left;
104
- let right;
105
- let width;
106
- if (colWidth != null) {
107
- width = (seg.lastCol - seg.firstCol + 1) * colWidth;
108
- if (isRtl) {
109
- right = seg.firstCol * colWidth;
110
- }
111
- else {
112
- left = seg.firstCol * colWidth;
113
- }
114
- }
115
- else {
116
- const colWidthFrac = 1 / colCnt;
117
- width = internal_cjs.fracToCssDim((seg.lastCol - seg.firstCol + 1) * colWidthFrac);
118
- if (isRtl) {
119
- right = internal_cjs.fracToCssDim(seg.firstCol * colWidthFrac);
120
- }
121
- else {
122
- left = internal_cjs.fracToCssDim(seg.firstCol * colWidthFrac);
123
- }
124
- }
125
- return { left, right, width };
126
- }
127
- function computeColFromPosition(positionLeft, elWidth, colWidth, colCnt, isRtl) {
128
- const realColWidth = colWidth != null ? colWidth : elWidth / colCnt;
129
- const colFromLeft = Math.floor(positionLeft / realColWidth);
130
- const col = isRtl ? (colCnt - colFromLeft - 1) : colFromLeft;
131
- const left = colFromLeft * realColWidth;
132
- const right = left + realColWidth;
133
- return { col, left, right };
134
- }
135
- function computeRowFromPosition(positionTop, cellRows, rowHeightMap) {
136
- let row = 0;
137
- let top = 0;
138
- let bottom = 0;
139
- for (const cells of cellRows) {
140
- const key = cells[0].key;
141
- top = bottom;
142
- bottom = top + rowHeightMap.get(key);
143
- if (positionTop < bottom) {
144
- break;
145
- }
146
- row++;
147
- }
148
- return { row, top, bottom };
23
+ const WEEKDAY_FORMAT = internal_cjs.createFormatter({ weekday: 'long' });
24
+ const firstSunday = new Date(259200000);
25
+ function buildDateRowConfigs(...args) {
26
+ return [buildDateRowConfig(...args)];
149
27
  }
150
- // Hit Element
151
- // -------------------------------------------------------------------------------------------------
152
- function getRowEl(rootEl, row) {
153
- return rootEl.querySelectorAll(':scope > [role=row]')[row];
28
+ /*
29
+ Should this receive resource data attributes?
30
+ Or ResourceApi object itself?
31
+ */
32
+ function buildDateRowConfig(dates, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, // TODO: rename to dateHeaderFormat?
33
+ context, colSpan) {
34
+ return {
35
+ renderConfig: buildDateRenderConfig(context),
36
+ dataConfigs: buildDateDataConfigs(dates, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, context, colSpan)
37
+ };
154
38
  }
155
- function getCellEl(rowEl, col) {
156
- return rowEl.querySelectorAll(':scope > [role=gridcell]')[col];
39
+ /*
40
+ For header cells: how to connect w/ custom rendering
41
+ Applies to all cells in a row
42
+ */
43
+ function buildDateRenderConfig(context) {
44
+ const { options } = context;
45
+ return {
46
+ generatorName: 'dayHeaderContent',
47
+ customGenerator: options.dayHeaderContent,
48
+ classNameGenerator: options.dayHeaderClassNames,
49
+ didMount: options.dayHeaderDidMount,
50
+ willUnmount: options.dayHeaderWillUnmount,
51
+ };
157
52
  }
158
-
159
- class DateHeaderCell extends internal_cjs.BaseComponent {
160
- constructor() {
161
- super(...arguments);
162
- // ref
163
- this.innerElRef = preact_cjs.createRef();
164
- }
165
- render() {
166
- let { props, context } = this;
167
- let { dateProfile, date, extraRenderProps, extraDataAttrs } = props;
168
- let { dateEnv, options, theme, viewApi } = context;
169
- let dayMeta = internal_cjs.getDateMeta(date, props.todayRange, null, dateProfile);
170
- let text = dateEnv.format(date, props.dayHeaderFormat);
171
- let navLinkAttrs = (!dayMeta.isDisabled && props.navLink)
172
- ? internal_cjs.buildNavLinkAttrs(context, date)
173
- : {};
174
- let renderProps = Object.assign(Object.assign(Object.assign({ date: dateEnv.toDate(date), view: viewApi }, extraRenderProps), { text }), dayMeta);
175
- return (preact_cjs.createElement(internal_cjs.ContentContainer, { elTag: 'div', elClasses: [
176
- ...internal_cjs.getDayClassNames(dayMeta, theme),
177
- ...(props.extraClassNames || []),
178
- 'fc-header-cell',
179
- 'fc-cell',
180
- props.colWidth != null ? '' : 'fc-liquid',
181
- 'fc-flex-column',
182
- 'fc-align-center',
183
- ], elAttrs: Object.assign({ 'data-date': !dayMeta.isDisabled ? internal_cjs.formatDayString(date) : undefined }, extraDataAttrs), elStyle: {
184
- width: props.colWidth != null // TODO: DRY
185
- ? props.colWidth * (props.colSpan || 1)
186
- : undefined,
187
- }, renderProps: renderProps, generatorName: "dayHeaderContent", customGenerator: options.dayHeaderContent, defaultGenerator: renderInner, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount }, (InnerContainer) => (preact_cjs.createElement("div", { ref: this.innerElRef, className: [
188
- 'fc-flex-column',
189
- props.isSticky ? 'fc-sticky-x' : '',
190
- ].join(' ') }, !dayMeta.isDisabled && (preact_cjs.createElement(InnerContainer, { elTag: "a", elAttrs: navLinkAttrs, elClasses: [
191
- 'fc-cell-inner',
192
- 'fc-padding-sm',
193
- ] }))))));
194
- }
195
- componentDidMount() {
196
- const innerEl = this.innerElRef.current; // TODO: make dynamic with useEffect
197
- // TODO: only attach this if refs props present
198
- this.disconectInnerHeight = internal_cjs.watchHeight(innerEl, (height) => {
199
- internal_cjs.setRef(this.props.innerHeightRef, height);
53
+ /*
54
+ For header cells: data
55
+ */
56
+ function buildDateDataConfigs(dates, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, // TODO: rename to dateHeaderFormat?
57
+ context, colSpan = 1, keyPrefix = '') {
58
+ const { dateEnv, viewApi, options } = context;
59
+ return datesRepDistinctDays
60
+ ? dates.map((date) => {
61
+ const dateMeta = internal_cjs.getDateMeta(date, todayRange, null, dateProfile);
62
+ const text = dateEnv.format(date, dayHeaderFormat);
63
+ const renderProps = Object.assign(Object.assign({}, dateMeta), { date: dateEnv.toDate(date), view: viewApi, text });
64
+ const isNavLink = options.navLinks && !dateMeta.isDisabled;
65
+ const fullDateStr = internal_cjs.buildDateStr(context, date);
66
+ // for DayGridHeaderCell
67
+ return {
68
+ key: keyPrefix + date.toUTCString(),
69
+ renderProps,
70
+ attrs: Object.assign(Object.assign({ 'aria-label': fullDateStr }, (dateMeta.isToday ? { 'aria-current': 'date' } : {})), { 'data-date': internal_cjs.formatDayString(date) }),
71
+ // for navlink
72
+ innerAttrs: isNavLink
73
+ ? internal_cjs.buildNavLinkAttrs(context, date, undefined, fullDateStr)
74
+ : { 'aria-hidden': true },
75
+ colSpan,
76
+ isNavLink,
77
+ className: internal_cjs.getDayClassName(dateMeta),
78
+ };
79
+ })
80
+ : dates.map((date) => {
81
+ const dow = date.getUTCDay();
82
+ const normDate = internal_cjs.addDays(firstSunday, dow);
83
+ const dayMeta = {
84
+ dow,
85
+ isDisabled: false,
86
+ isFuture: false,
87
+ isPast: false,
88
+ isToday: false,
89
+ isOther: false,
90
+ };
91
+ const text = dateEnv.format(normDate, dayHeaderFormat);
92
+ const renderProps = Object.assign(Object.assign({}, dayMeta), { date, view: viewApi, text });
93
+ const fullWeekDayStr = dateEnv.format(normDate, WEEKDAY_FORMAT);
94
+ // for DayGridHeaderCell
95
+ return {
96
+ key: keyPrefix + String(dow),
97
+ renderProps,
98
+ attrs: {
99
+ 'aria-label': fullWeekDayStr,
100
+ },
101
+ // for navlink
102
+ innerAttrs: {
103
+ 'aria-hidden': true, // label already on cell
104
+ },
105
+ colSpan,
106
+ className: internal_cjs.getDayClassName(dayMeta),
107
+ };
200
108
  });
201
- }
202
- componentWillUnmount() {
203
- this.disconectInnerHeight();
204
- internal_cjs.setRef(this.props.innerHeightRef, null);
205
- }
206
109
  }
207
110
 
111
+ /*
112
+ We need really specific keys because RefMap::createRef() which is then given to heightRef
113
+ unable to change key! As a result, we cannot reuse elements between normal/slice/standin types,
114
+ but that's okay since they render quite differently
115
+ */
116
+ function getEventPartKey(seg) {
117
+ return internal_cjs.getEventKey(seg) + ':' + seg.start +
118
+ (seg.standinFor ? ':standin' : seg.isSlice ? ':slice' : '');
119
+ }
120
+ // DayGridRange utils (TODO: move)
121
+ // -------------------------------------------------------------------------------------------------
208
122
  function splitSegsByRow(segs, rowCnt) {
209
123
  const byRow = [];
210
124
  for (let row = 0; row < rowCnt; row++) {
@@ -236,20 +150,8 @@ function splitInteractionByRow(ui, rowCnt) {
236
150
  }
237
151
  return byRow;
238
152
  }
239
- function splitSegsByCol(segs, colCnt) {
240
- let byCol = [];
241
- for (let col = 0; col < colCnt; col++) {
242
- byCol.push([]);
243
- }
244
- for (let seg of segs) {
245
- for (let col = seg.firstCol; col <= seg.lastCol; col++) {
246
- if (seg.firstCol !== col) {
247
- seg = Object.assign(Object.assign({}, seg), { firstCol: col, lastCol: col, isStart: false, isEnd: seg.isEnd && seg.lastCol === col, isStandin: true });
248
- }
249
- byCol[col].push(seg);
250
- }
251
- }
252
- return byCol;
153
+ function sliceSegForCol(seg, col) {
154
+ return Object.assign(Object.assign({}, seg), { start: col, end: col + 1, isStart: seg.isStart && seg.start === col, isEnd: seg.isEnd && seg.end - 1 === col, standinFor: seg });
253
155
  }
254
156
 
255
157
  const DEFAULT_TABLE_EVENT_TIME_FORMAT = internal_cjs.createFormatter({
@@ -262,7 +164,7 @@ function hasListItemDisplay(seg) {
262
164
  let { display } = seg.eventRange.ui;
263
165
  return display === 'list-item' || (display === 'auto' &&
264
166
  !seg.eventRange.def.allDay &&
265
- seg.firstCol === seg.lastCol && // can't be multi-day
167
+ (seg.end - seg.start) === 1 && // single-day
266
168
  seg.isStart && // "
267
169
  seg.isEnd // "
268
170
  );
@@ -271,7 +173,7 @@ function hasListItemDisplay(seg) {
271
173
  class DayGridBlockEvent extends internal_cjs.BaseComponent {
272
174
  render() {
273
175
  let { props } = this;
274
- return (preact_cjs.createElement(internal_cjs.StandardEvent, Object.assign({}, props, { elClasses: ['fc-daygrid-event', 'fc-daygrid-block-event', 'fc-h-event'], defaultTimeFormat: DEFAULT_TABLE_EVENT_TIME_FORMAT, defaultDisplayEventEnd: props.defaultDisplayEventEnd, disableResizing: !props.eventRange.def.allDay })));
176
+ return (preact_cjs.createElement(internal_cjs.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 })));
275
177
  }
276
178
  }
277
179
 
@@ -281,8 +183,12 @@ class DayGridListEvent extends internal_cjs.BaseComponent {
281
183
  let { options } = context;
282
184
  let { eventRange } = props;
283
185
  let timeFormat = options.eventTimeFormat || DEFAULT_TABLE_EVENT_TIME_FORMAT;
284
- let timeText = internal_cjs.buildEventRangeTimeText(eventRange, timeFormat, context, true, props.defaultDisplayEventEnd);
285
- return (preact_cjs.createElement(internal_cjs.EventContainer, Object.assign({}, props, { elTag: "a", elClasses: ['fc-daygrid-event', 'fc-daygrid-dot-event'], elAttrs: internal_cjs.getEventRangeAnchorAttrs(eventRange, context), defaultGenerator: renderInnerContent, timeText: timeText, isResizing: false, isDateSelecting: false })));
186
+ let timeText = internal_cjs.buildEventRangeTimeText(timeFormat, eventRange,
187
+ /* slicedStart = */ undefined,
188
+ /* slicedEnd = */ undefined, props.isStart, props.isEnd, context,
189
+ /* defaultDisplayEventTime = */ true, props.defaultDisplayEventEnd);
190
+ let [tag, attrs] = internal_cjs.getEventTagAndAttrs(eventRange, context);
191
+ return (preact_cjs.createElement(internal_cjs.EventContainer, Object.assign({}, props, { tag: tag, attrs: attrs, className: 'fc-daygrid-dot-event fc-daygrid-event', defaultGenerator: renderInnerContent, timeText: timeText, isResizing: false, isDateSelecting: false })));
286
192
  }
287
193
  }
288
194
  function renderInnerContent(renderProps) {
@@ -295,14 +201,16 @@ function renderInnerContent(renderProps) {
295
201
  class DayGridMoreLink extends internal_cjs.BaseComponent {
296
202
  render() {
297
203
  let { props } = this;
298
- return (preact_cjs.createElement(internal_cjs.MoreLinkContainer, { elClasses: ['fc-daygrid-more-link'], dateProfile: props.dateProfile, todayRange: props.todayRange, allDayDate: props.allDayDate, segs: props.segs, hiddenSegs: props.hiddenSegs, alignmentElRef: props.alignmentElRef, alignGridTop: props.alignGridTop, extraDateSpan: props.extraDateSpan, popoverContent: () => {
204
+ return (preact_cjs.createElement(internal_cjs.MoreLinkContainer, { className: internal_cjs.joinClassNames('fc-daygrid-more-link', props.isBlock
205
+ ? 'fc-daygrid-more-link-block'
206
+ : '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: () => {
299
207
  let forcedInvisibleMap = // TODO: more convenient/DRY
300
208
  (props.eventDrag ? props.eventDrag.affectedInstances : null) ||
301
209
  (props.eventResize ? props.eventResize.affectedInstances : null) ||
302
210
  {};
303
211
  return (preact_cjs.createElement(preact_cjs.Fragment, null, props.segs.map((seg) => {
304
212
  let { eventRange } = seg;
305
- let instanceId = eventRange.instance.instanceId;
213
+ let { instanceId } = eventRange.instance;
306
214
  return (preact_cjs.createElement("div", { key: instanceId, style: {
307
215
  visibility: forcedInvisibleMap[instanceId] ? 'hidden' : '',
308
216
  } }, hasListItemDisplay(seg) ? (preact_cjs.createElement(DayGridListEvent, Object.assign({ eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, internal_cjs.getEventRangeMeta(eventRange, props.todayRange)))) : (preact_cjs.createElement(DayGridBlockEvent, Object.assign({ eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, internal_cjs.getEventRangeMeta(eventRange, props.todayRange))))));
@@ -315,8 +223,31 @@ class DayGridCell extends internal_cjs.DateComponent {
315
223
  constructor() {
316
224
  super(...arguments);
317
225
  // ref
318
- this.innerElRef = preact_cjs.createRef();
319
- this.headerWrapElRef = preact_cjs.createRef();
226
+ this.rootElRef = preact_cjs.createRef();
227
+ this.handleBodyEl = (bodyEl) => {
228
+ if (this.disconnectBodyHeight) {
229
+ this.disconnectBodyHeight();
230
+ this.disconnectBodyHeight = undefined;
231
+ internal_cjs.setRef(this.props.headerHeightRef, null);
232
+ internal_cjs.setRef(this.props.mainHeightRef, null);
233
+ }
234
+ if (bodyEl) {
235
+ // we want to fire on ANY size change, because we do more advanced stuff
236
+ this.disconnectBodyHeight = internal_cjs.watchSize(bodyEl, (_bodyWidth, bodyHeight) => {
237
+ const { props } = this;
238
+ const mainRect = bodyEl.getBoundingClientRect();
239
+ const rootRect = this.rootElRef.current.getBoundingClientRect();
240
+ const headerHeight = mainRect.top - rootRect.top;
241
+ if (!internal_cjs.isDimsEqual(this.headerHeight, headerHeight)) {
242
+ this.headerHeight = headerHeight;
243
+ internal_cjs.setRef(props.headerHeightRef, headerHeight);
244
+ }
245
+ if (props.fgLiquidHeight) {
246
+ internal_cjs.setRef(props.mainHeightRef, bodyHeight);
247
+ }
248
+ });
249
+ }
250
+ };
320
251
  }
321
252
  render() {
322
253
  let { props, context } = this;
@@ -324,48 +255,28 @@ class DayGridCell extends internal_cjs.DateComponent {
324
255
  // TODO: memoize this
325
256
  const isMonthStart = props.showDayNumber &&
326
257
  shouldDisplayMonthStart(props.date, props.dateProfile.currentRange, dateEnv);
327
- return (preact_cjs.createElement(internal_cjs.DayCellContainer, { elTag: "div", elClasses: [
328
- 'fc-daygrid-cell',
329
- 'fc-cell',
330
- props.width != null ? '' : 'fc-liquid',
331
- 'fc-flex-column',
332
- ...(props.extraClassNames || []),
333
- ], elAttrs: Object.assign(Object.assign({}, props.extraDataAttrs), { role: 'gridcell' }), elStyle: {
258
+ // TODO: memoize this
259
+ const dateMeta = internal_cjs.getDateMeta(props.date, props.todayRange, null, props.dateProfile);
260
+ const baseClassName = internal_cjs.joinClassNames('fc-daygrid-day', props.borderStart && 'fc-border-s', props.width != null ? '' : 'fc-liquid', 'fc-flex-col');
261
+ if (dateMeta.isDisabled) {
262
+ return (preact_cjs.createElement("div", { role: 'gridcell', "aria-disabled": true, className: internal_cjs.joinClassNames(baseClassName, 'fc-day-disabled'), style: {
263
+ width: props.width
264
+ } }));
265
+ }
266
+ const hasDayNumber = props.showDayNumber || internal_cjs.hasCustomDayCellContent(options);
267
+ const isNavLink = options.navLinks;
268
+ const fullDateStr = internal_cjs.buildDateStr(context, props.date);
269
+ return (preact_cjs.createElement(internal_cjs.DayCellContainer, { tag: "div", className: internal_cjs.joinClassNames(baseClassName, props.className), attrs: Object.assign(Object.assign({}, props.attrs), { role: 'gridcell', 'aria-label': fullDateStr }), style: {
334
270
  width: props.width
335
- }, extraRenderProps: props.extraRenderProps, defaultGenerator: renderTopInner, date: props.date, dateProfile: props.dateProfile, todayRange: props.todayRange, showDayNumber: props.showDayNumber, isMonthStart: isMonthStart }, (InnerContent, renderProps) => (preact_cjs.createElement("div", { ref: this.innerElRef, className: [
336
- 'fc-daygrid-cell-inner',
337
- props.fgLiquidHeight ? 'fc-liquid' : ''
338
- ].join(' ') },
339
- preact_cjs.createElement("div", { ref: this.headerWrapElRef, className: "fc-flex-column" }, !renderProps.isDisabled && (props.showDayNumber || internal_cjs.hasCustomDayCellContent(options)) && (preact_cjs.createElement("div", { className: "fc-daygrid-cell-header" },
340
- preact_cjs.createElement(InnerContent, { elTag: "a", elClasses: [
341
- 'fc-daygrid-cell-number',
342
- isMonthStart && 'fc-daygrid-month-start',
343
- ], elAttrs: internal_cjs.buildNavLinkAttrs(context, props.date) })))),
344
- preact_cjs.createElement("div", { className: "fc-daygrid-cell-main", style: {
345
- height: props.fgLiquidHeight ? '' : props.fgHeight
346
- } }, props.fg),
347
- preact_cjs.createElement("div", { className: "fc-daygrid-cell-footer", style: props.fgLiquidHeight
348
- ? { position: 'relative', top: props.fgHeight }
349
- : {} },
350
- preact_cjs.createElement(DayGridMoreLink, { allDayDate: props.date, segs: props.segs, hiddenSegs: props.hiddenSegs, alignmentElRef: this.innerElRef, alignGridTop: !props.showDayNumber, extraDateSpan: props.extraDateSpan, dateProfile: props.dateProfile, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, todayRange: props.todayRange })),
351
- props.bg))));
352
- }
353
- componentDidMount() {
354
- const innerEl = this.innerElRef.current; // TODO: make dynamic with useEffect
355
- const headerWrapEl = this.headerWrapElRef.current; // "
356
- // TODO: only attach this if refs props present
357
- this.detachInnerHeight = internal_cjs.watchHeight(innerEl, (height) => {
358
- internal_cjs.setRef(this.props.innerHeightRef, height);
359
- });
360
- this.detachHeaderHeight = internal_cjs.watchHeight(headerWrapEl, (height) => {
361
- internal_cjs.setRef(this.props.headerHeightRef, height);
362
- });
363
- }
364
- componentWillUnmount() {
365
- this.detachInnerHeight();
366
- this.detachHeaderHeight();
367
- internal_cjs.setRef(this.props.innerHeightRef, null);
368
- internal_cjs.setRef(this.props.headerHeightRef, null);
271
+ }, elRef: this.rootElRef, renderProps: props.renderProps, defaultGenerator: renderTopInner, date: props.date, dateMeta: dateMeta, showDayNumber: props.showDayNumber, isMonthStart: isMonthStart }, (InnerContent) => (preact_cjs.createElement(preact_cjs.Fragment, null,
272
+ hasDayNumber && (preact_cjs.createElement("div", { className: "fc-daygrid-day-header" },
273
+ preact_cjs.createElement(InnerContent, { tag: 'div', attrs: isNavLink
274
+ ? internal_cjs.buildNavLinkAttrs(context, props.date, undefined, fullDateStr)
275
+ : { 'aria-hidden': true } // label already on cell
276
+ , className: internal_cjs.joinClassNames('fc-daygrid-day-number', isMonthStart && 'fc-daygrid-month-start') }))),
277
+ preact_cjs.createElement("div", { className: internal_cjs.joinClassNames('fc-daygrid-day-body', props.isTall && 'fc-daygrid-day-body-tall', props.fgLiquidHeight ? 'fc-liquid' : 'fc-grow'), ref: this.handleBodyEl },
278
+ preact_cjs.createElement("div", { className: 'fc-daygrid-day-events', style: { height: props.fgHeight } }, props.fg),
279
+ preact_cjs.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 }))))));
369
280
  }
370
281
  }
371
282
  // Utils
@@ -389,121 +300,232 @@ function shouldDisplayMonthStart(date, currentRange, dateEnv) {
389
300
  (dateEnv.getDay(date) === 1 && date.valueOf() < currentEnd.valueOf()));
390
301
  }
391
302
 
303
+ function computeFgSegVerticals(segs, segHeightMap, cells, maxHeight, strictOrder, allowSlicing = true, dayMaxEvents, dayMaxEventRows) {
304
+ let maxCoord;
305
+ let maxDepth;
306
+ let hiddenConsumes;
307
+ if (dayMaxEvents === true || dayMaxEventRows === true) {
308
+ maxCoord = maxHeight;
309
+ hiddenConsumes = true;
310
+ }
311
+ else if (typeof dayMaxEvents === 'number') {
312
+ maxDepth = dayMaxEvents;
313
+ hiddenConsumes = false;
314
+ }
315
+ else if (typeof dayMaxEventRows === 'number') {
316
+ maxDepth = dayMaxEventRows;
317
+ hiddenConsumes = true;
318
+ }
319
+ // NOTE: visibleSegsMap and hiddenSegMap map NEVER overlap for a given event
320
+ // once a seg has a height, the combined potentially-sliced segs will comprise the entire span of the seg
321
+ // if a seg does not have a height yet, it won't be inserted into either visibleSegsMap/hiddenSegMap
322
+ const visibleSegMap = new Map();
323
+ const hiddenSegMap = new Map();
324
+ const segTops = new Map();
325
+ const isSlicedMap = new Map();
326
+ let hierarchy = new internal_cjs.SegHierarchy(segs, (seg) => segHeightMap.get(getEventPartKey(seg)), strictOrder, maxCoord, maxDepth, hiddenConsumes, allowSlicing);
327
+ hierarchy.traverseSegs((seg, segTop) => {
328
+ addToSegMap(visibleSegMap, seg);
329
+ segTops.set(getEventPartKey(seg), segTop);
330
+ if (seg.isSlice) {
331
+ isSlicedMap.set(seg.eventRange, true);
332
+ }
333
+ });
334
+ for (const hiddenSeg of hierarchy.hiddenSegs) {
335
+ addToSegMap(hiddenSegMap, hiddenSeg); // hidden main segs
336
+ }
337
+ // recompute tops while considering slices
338
+ // portions of these slices might be added to hiddenSegMap
339
+ if (isSlicedMap.size) {
340
+ segTops.clear();
341
+ hierarchy = new internal_cjs.SegHierarchy(compileSegMap(segs, visibleSegMap), (seg) => segHeightMap.get(getEventPartKey(seg)), strictOrder, maxCoord, maxDepth, hiddenConsumes);
342
+ hierarchy.traverseSegs((seg, segTop) => {
343
+ segTops.set(getEventPartKey(seg), segTop); // newly-hidden main segs and slices
344
+ });
345
+ for (const hiddenSeg of hierarchy.hiddenSegs) {
346
+ addToSegMap(hiddenSegMap, hiddenSeg);
347
+ }
348
+ }
349
+ const segsByCol = [];
350
+ const hiddenSegsByCol = [];
351
+ const renderableSegsByCol = [];
352
+ const heightsByCol = [];
353
+ for (let col = 0; col < cells.length; col++) {
354
+ segsByCol.push([]);
355
+ hiddenSegsByCol.push([]);
356
+ renderableSegsByCol.push([]);
357
+ heightsByCol.push(0);
358
+ }
359
+ for (const seg of segs) {
360
+ const { eventRange } = seg;
361
+ const visibleSegs = visibleSegMap.get(eventRange) || [];
362
+ const hiddenSegs = hiddenSegMap.get(eventRange) || [];
363
+ const isSliced = isSlicedMap.get(eventRange) || false;
364
+ // add orig to renderable
365
+ renderableSegsByCol[seg.start].push(seg);
366
+ // add slices to renderable
367
+ if (isSliced) {
368
+ for (const visibleSeg of visibleSegs) {
369
+ renderableSegsByCol[visibleSeg.start].push(visibleSeg);
370
+ }
371
+ }
372
+ // accumulate segsByCol/heightsByCol for visible segs
373
+ for (const visibleSeg of visibleSegs) {
374
+ for (let col = visibleSeg.start; col < visibleSeg.end; col++) {
375
+ const slice = sliceSegForCol(visibleSeg, col);
376
+ segsByCol[col].push(slice);
377
+ }
378
+ const segKey = getEventPartKey(visibleSeg);
379
+ const segTop = segTops.get(segKey);
380
+ if (segTop != null) { // positioned?
381
+ const segHeight = segHeightMap.get(segKey);
382
+ for (let col = visibleSeg.start; col < visibleSeg.end; col++) {
383
+ heightsByCol[col] = Math.max(heightsByCol[col], segTop + segHeight);
384
+ }
385
+ }
386
+ }
387
+ // accumulate segsByCol/hiddenSegsByCol for hidden segs
388
+ for (const hiddenSeg of hiddenSegs) {
389
+ for (let col = hiddenSeg.start; col < hiddenSeg.end; col++) {
390
+ const slice = sliceSegForCol(hiddenSeg, col);
391
+ segsByCol[col].push(slice);
392
+ hiddenSegsByCol[col].push(slice);
393
+ }
394
+ }
395
+ }
396
+ return [
397
+ segsByCol,
398
+ hiddenSegsByCol,
399
+ renderableSegsByCol,
400
+ segTops,
401
+ heightsByCol,
402
+ ];
403
+ }
404
+ // Utils
405
+ // -------------------------------------------------------------------------------------------------
406
+ function addToSegMap(map, seg) {
407
+ let list = map.get(seg.eventRange);
408
+ if (!list) {
409
+ map.set(seg.eventRange, list = []);
410
+ }
411
+ list.push(seg);
412
+ }
392
413
  /*
393
- Unique per-START-column, good for cataloging by top
414
+ Ensures relative order of DayRowEventRange stays consistent with segs
394
415
  */
395
- function getSegStartId(seg) {
396
- return seg.eventRange.instance.instanceId + ':' + seg.firstCol;
416
+ function compileSegMap(segs, segMap) {
417
+ const res = [];
418
+ for (const seg of segs) {
419
+ res.push(...(segMap.get(seg.eventRange) || []));
420
+ }
421
+ return res;
397
422
  }
423
+
398
424
  /*
399
- Unique per-START-and-END-column, good for cataloging by width/height
425
+ TODO: move this so @fullcalendar/daygrid
400
426
  */
401
- function getSegSpanId(seg) {
402
- return getSegStartId(seg) + ':' + seg.lastCol;
427
+ function buildDayTableModel(dateProfile, dateProfileGenerator) {
428
+ let daySeries = new internal_cjs.DaySeriesModel(dateProfile.renderRange, dateProfileGenerator);
429
+ return new internal_cjs.DayTableModel(daySeries, /year|month|week/.test(dateProfile.currentRangeUnit));
403
430
  }
404
- function computeFgSegVerticals(segs, segHeightMap, // keyed by segSpanId
405
- cells, topOrigin, maxHeight, strictOrder, dayMaxEvents, dayMaxEventRows) {
406
- // initialize column-based arrays
407
- const colCnt = cells.length;
408
- const hiddenSegsByCol = [];
409
- const heightsByCol = [];
410
- for (let col = 0; col < colCnt; col++) {
411
- hiddenSegsByCol.push([]);
412
- heightsByCol.push(0);
413
- }
414
- // create entries to be given to DayGridSegHierarchy
415
- const segEntries = segs.map((seg, index) => ({
416
- index: index,
417
- seg,
418
- span: {
419
- start: seg.firstCol,
420
- end: seg.lastCol + 1,
421
- },
422
- }));
423
- // configure hierarchy position-generator
424
- let hierarchy = new DayGridSegHierarchy((segEntry) => (segHeightMap.get(getSegSpanId(segs[segEntry.index]))));
425
- hierarchy.allowReslicing = false;
426
- hierarchy.strictOrder = strictOrder;
427
- if (dayMaxEvents === true || dayMaxEventRows === true) {
428
- hierarchy.maxCoord = maxHeight;
429
- hierarchy.hiddenConsumes = true;
431
+ function computeColWidth(colCnt, colMinWidth, viewportWidth) {
432
+ if (viewportWidth == null) {
433
+ return [undefined, undefined];
430
434
  }
431
- else if (typeof dayMaxEvents === 'number') {
432
- hierarchy.maxStackCnt = dayMaxEvents;
435
+ const colTempWidth = viewportWidth / colCnt;
436
+ if (colTempWidth < colMinWidth) {
437
+ return [colMinWidth * colCnt, colMinWidth];
433
438
  }
434
- else if (typeof dayMaxEventRows === 'number') {
435
- hierarchy.maxStackCnt = dayMaxEventRows;
436
- hierarchy.hiddenConsumes = true;
437
- }
438
- // compile segTops & heightsByCol
439
- const hiddenSegEntries = hierarchy.addSegs(segEntries);
440
- const segRects = hierarchy.toRects();
441
- const segTops = {};
442
- for (const segRect of segRects) {
443
- const seg = segs[segRect.index];
444
- segTops[getSegStartId(seg)] = topOrigin + segRect.levelCoord;
445
- let { start: col, end: endCol } = segRect.span;
446
- for (; col < endCol; col++) {
447
- heightsByCol[col] = Math.max(heightsByCol[col], segRect.levelCoord + segRect.thickness);
439
+ return [viewportWidth, undefined];
440
+ }
441
+ // Positioning
442
+ // -------------------------------------------------------------------------------------------------
443
+ function computeTopFromDate(date, cellRows, rowHeightMap, adjust = 0) {
444
+ let top = 0;
445
+ for (const cells of cellRows) {
446
+ const start = cells[0].date;
447
+ const end = cells[cells.length - 1].date;
448
+ const key = start.toISOString();
449
+ if (date >= start && date <= end) {
450
+ return top;
451
+ }
452
+ const rowHeight = rowHeightMap.get(key);
453
+ if (rowHeight == null) {
454
+ return; // denote unknown
448
455
  }
456
+ top += rowHeight + adjust;
449
457
  }
450
- // compile # of invisible segs per-column
451
- for (const hiddenSegEntry of hiddenSegEntries) {
452
- const { span } = hiddenSegEntry;
453
- const hiddenSeg = segs[hiddenSegEntry.index];
454
- for (let col = span.start; col < span.end; col++) {
455
- hiddenSegsByCol[col].push(hiddenSeg);
458
+ return top;
459
+ }
460
+ /*
461
+ FYI, `width` is not dependable for aligning completely to farside
462
+ */
463
+ function computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl) {
464
+ let fromStart;
465
+ let fromEnd;
466
+ if (colWidth != null) {
467
+ fromStart = seg.start * colWidth;
468
+ fromEnd = (colCnt - seg.end) * colWidth;
469
+ }
470
+ else {
471
+ const colWidthFrac = 1 / colCnt;
472
+ fromStart = internal_cjs.fracToCssDim(seg.start * colWidthFrac);
473
+ fromEnd = internal_cjs.fracToCssDim(1 - seg.end * colWidthFrac);
474
+ }
475
+ if (isRtl) {
476
+ return { right: fromStart, left: fromEnd };
477
+ }
478
+ else {
479
+ return { left: fromStart, right: fromEnd };
480
+ }
481
+ }
482
+ function computeColFromPosition(positionLeft, elWidth, colWidth, colCnt, isRtl) {
483
+ const realColWidth = colWidth != null ? colWidth : elWidth / colCnt;
484
+ const colFromLeft = Math.floor(positionLeft / realColWidth);
485
+ const col = isRtl ? (colCnt - colFromLeft - 1) : colFromLeft;
486
+ const left = colFromLeft * realColWidth;
487
+ const right = left + realColWidth;
488
+ return { col, left, right };
489
+ }
490
+ function computeRowFromPosition(positionTop, cellRows, rowHeightMap) {
491
+ let row = 0;
492
+ let top = 0;
493
+ let bottom = 0;
494
+ for (const cells of cellRows) {
495
+ const key = cells[0].key;
496
+ top = bottom;
497
+ bottom = top + rowHeightMap.get(key);
498
+ if (positionTop < bottom) {
499
+ break;
456
500
  }
501
+ row++;
457
502
  }
458
- return [segTops, heightsByCol, hiddenSegsByCol];
503
+ return { row, top, bottom };
459
504
  }
460
- // DayGridSegHierarchy
505
+ // Hit Element
461
506
  // -------------------------------------------------------------------------------------------------
462
- class DayGridSegHierarchy extends internal_cjs.SegHierarchy {
463
- constructor() {
464
- super(...arguments);
465
- // config
466
- this.hiddenConsumes = false;
467
- // allows us to keep hidden entries in the hierarchy so they take up space
468
- this.forceHidden = {};
469
- }
470
- addSegs(segInputs) {
471
- const hiddenSegs = super.addSegs(segInputs);
472
- const { entriesByLevel } = this;
473
- const excludeHidden = (entry) => !this.forceHidden[internal_cjs.buildEntryKey(entry)];
474
- // remove the forced-hidden segs
475
- for (let level = 0; level < entriesByLevel.length; level += 1) {
476
- entriesByLevel[level] = entriesByLevel[level].filter(excludeHidden);
477
- }
478
- return hiddenSegs;
479
- }
480
- handleInvalidInsertion(insertion, entry, hiddenEntries) {
481
- const { entriesByLevel, forceHidden } = this;
482
- const { touchingEntry, touchingLevel, touchingLateral } = insertion;
483
- // the entry that the new insertion is touching must be hidden
484
- if (this.hiddenConsumes && touchingEntry) {
485
- const touchingEntryId = internal_cjs.buildEntryKey(touchingEntry);
486
- if (!forceHidden[touchingEntryId]) {
487
- if (this.allowReslicing) {
488
- // split up the touchingEntry, reinsert it
489
- const hiddenEntry = Object.assign(Object.assign({}, touchingEntry), { span: internal_cjs.intersectSpans(touchingEntry.span, entry.span) });
490
- // reinsert the area that turned into a "more" link (so no other entries try to
491
- // occupy the space) but mark it forced-hidden
492
- const hiddenEntryId = internal_cjs.buildEntryKey(hiddenEntry);
493
- forceHidden[hiddenEntryId] = true;
494
- entriesByLevel[touchingLevel][touchingLateral] = hiddenEntry;
495
- hiddenEntries.push(hiddenEntry);
496
- this.splitEntry(touchingEntry, entry, hiddenEntries);
497
- }
498
- else {
499
- forceHidden[touchingEntryId] = true;
500
- hiddenEntries.push(touchingEntry);
501
- }
502
- }
503
- }
504
- // will try to reslice...
505
- super.handleInvalidInsertion(insertion, entry, hiddenEntries);
507
+ function getRowEl(rootEl, row) {
508
+ return rootEl.querySelectorAll(':scope > [role=row]')[row];
509
+ }
510
+ function getCellEl(rowEl, col) {
511
+ return rowEl.querySelectorAll(':scope > [role=gridcell]')[col];
512
+ }
513
+ // Header Formatting
514
+ // -------------------------------------------------------------------------------------------------
515
+ function createDayHeaderFormatter(explicitFormat, datesRepDistinctDays, dateCnt) {
516
+ return explicitFormat || computeFallbackHeaderFormat(datesRepDistinctDays, dateCnt);
517
+ }
518
+ // Computes a default column header formatting string if `colFormat` is not explicitly defined
519
+ function computeFallbackHeaderFormat(datesRepDistinctDays, dayCnt) {
520
+ // if more than one week row, or if there are a lot of columns with not much space,
521
+ // put just the day numbers will be in each cell
522
+ if (!datesRepDistinctDays || dayCnt > 10) {
523
+ return internal_cjs.createFormatter({ weekday: 'short' }); // "Sat"
524
+ }
525
+ if (dayCnt > 1) {
526
+ return internal_cjs.createFormatter({ weekday: 'short', month: 'numeric', day: 'numeric', omitCommas: true }); // "Sat 11/12"
506
527
  }
528
+ return internal_cjs.createFormatter({ weekday: 'long' }); // "Saturday"
507
529
  }
508
530
 
509
531
  class DayGridEventHarness extends preact_cjs.Component {
@@ -514,129 +536,102 @@ class DayGridEventHarness extends preact_cjs.Component {
514
536
  }
515
537
  render() {
516
538
  const { props } = this;
517
- return (preact_cjs.createElement("div", { className: "fc-abs", style: props.style, ref: this.rootElRef }, props.children));
539
+ return (preact_cjs.createElement("div", { className: internal_cjs.joinClassNames(props.className, 'fc-abs'), style: props.style, ref: this.rootElRef }, props.children));
518
540
  }
519
541
  componentDidMount() {
520
542
  const rootEl = this.rootElRef.current; // TODO: make dynamic with useEffect
521
- this.detachHeight = internal_cjs.watchHeight(rootEl, (height) => {
543
+ this.disconnectHeight = internal_cjs.watchHeight(rootEl, (height) => {
522
544
  internal_cjs.setRef(this.props.heightRef, height);
523
545
  });
524
546
  }
525
547
  componentWillUnmount() {
526
- this.detachHeight();
548
+ this.disconnectHeight();
527
549
  internal_cjs.setRef(this.props.heightRef, null);
528
550
  }
529
551
  }
530
552
 
531
553
  const DEFAULT_WEEK_NUM_FORMAT = internal_cjs.createFormatter({ week: 'narrow' });
532
- const COMPACT_CELL_WIDTH = 80;
533
554
  class DayGridRow extends internal_cjs.BaseComponent {
534
555
  constructor() {
535
556
  super(...arguments);
536
- this.cellInnerHeightRefMap = new internal_cjs.RefMap(() => {
537
- internal_cjs.afterSize(this.handleInnerHeights);
557
+ this.headerHeightRefMap = new internal_cjs.RefMap(() => {
558
+ internal_cjs.afterSize(this.handleSegPositioning);
538
559
  });
539
- this.cellHeaderHeightRefMap = new internal_cjs.RefMap(() => {
540
- internal_cjs.afterSize(this.handleHeaderHeights);
560
+ this.mainHeightRefMap = new internal_cjs.RefMap(() => {
561
+ const fgLiquidHeight = this.props.dayMaxEvents === true || this.props.dayMaxEventRows === true;
562
+ if (fgLiquidHeight) {
563
+ internal_cjs.afterSize(this.handleSegPositioning);
564
+ }
541
565
  });
542
566
  this.segHeightRefMap = new internal_cjs.RefMap(() => {
543
- internal_cjs.afterSize(this.handleSegHeights);
567
+ internal_cjs.afterSize(this.handleSegPositioning);
544
568
  });
545
569
  this.handleRootEl = (rootEl) => {
546
570
  this.rootEl = rootEl;
547
571
  internal_cjs.setRef(this.props.rootElRef, rootEl);
548
572
  };
549
- // Sizing
550
- // -----------------------------------------------------------------------------------------------
551
- this.handleHeaderHeights = () => {
552
- const cellHeaderHeightMap = this.cellHeaderHeightRefMap.current;
553
- let max = 0;
554
- for (const height of cellHeaderHeightMap.values()) {
555
- max = Math.max(max, height);
556
- }
557
- if (this.state.headerHeight !== max) {
558
- this.setState({ headerHeight: max });
559
- }
560
- };
561
- this.handleInnerHeights = () => {
562
- const { props } = this;
563
- const fgLiquidHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;
564
- const cellInnerHeightMap = this.cellInnerHeightRefMap.current;
565
- let max = 0;
566
- for (const height of cellInnerHeightMap.values()) {
567
- max = Math.max(max, height);
568
- }
569
- if (fgLiquidHeight) {
570
- if (this.state.innerHeight !== max) {
571
- this.setState({ innerHeight: max }); // will trigger event rerender
572
- }
573
- }
574
- else {
575
- internal_cjs.setRef(props.innerHeightRef, max);
576
- }
577
- };
578
- this.handleSegHeights = () => {
579
- this.setState({ segHeightRev: this.segHeightRefMap.rev }); // will trigger event rerender
573
+ this.handleSegPositioning = () => {
574
+ this.forceUpdate();
580
575
  };
581
576
  }
582
577
  render() {
583
- const { props, state, context, cellInnerHeightRefMap, cellHeaderHeightRefMap } = this;
578
+ const { props, context, headerHeightRefMap, mainHeightRefMap } = this;
584
579
  const { cells } = props;
585
580
  const { options } = context;
586
581
  const weekDate = props.cells[0].date;
587
- const colCnt = props.cells.length;
588
582
  const fgLiquidHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;
589
583
  // TODO: memoize? sort all types of segs?
590
584
  const fgEventSegs = internal_cjs.sortEventSegs(props.fgEventSegs, options.eventOrder);
591
585
  // TODO: memoize?
592
- const fgEventSegsByCol = splitSegsByCol(fgEventSegs, colCnt);
593
- const bgEventSegsByCol = splitSegsByCol(props.bgEventSegs, colCnt);
594
- const businessHoursByCol = splitSegsByCol(props.businessHourSegs, colCnt);
595
- const highlightSegsByCol = splitSegsByCol(this.getHighlightSegs(), colCnt); // TODO: doesn't need standins
596
- const mirrorSegsByCol = splitSegsByCol(this.getMirrorSegs(), colCnt); // TODO: doesn't need standins
597
- // TODO: memoize?
598
- const [segTops, heightsByCol, hiddenSegsByCol] = computeFgSegVerticals(fgEventSegs, this.segHeightRefMap.current, cells, state.headerHeight, (fgLiquidHeight && state.innerHeight != null && state.headerHeight != null)
599
- ? state.innerHeight - state.headerHeight
600
- : undefined, options.eventOrderStrict, props.dayMaxEvents, props.dayMaxEventRows);
586
+ const [maxMainTop, minMainHeight] = this.computeFgDims(); // uses headerHeightRefMap/mainHeightRefMap
587
+ const [segsByCol, hiddenSegsByCol, renderableSegsByCol, segTops, simpleHeightsByCol] = computeFgSegVerticals(fgEventSegs, this.segHeightRefMap.current, cells, fgLiquidHeight ? minMainHeight : undefined, // if not defined in first run, will unlimited!?
588
+ options.eventOrderStrict, options.eventSlicing, props.dayMaxEvents, props.dayMaxEventRows);
589
+ const heightsByCol = [];
590
+ if (maxMainTop != null) {
591
+ let col = 0;
592
+ for (const cell of cells) { // uses headerHeightRefMap/maxMainTop/simpleHeightsByCol
593
+ const cellHeaderHeight = headerHeightRefMap.current.get(cell.key);
594
+ const extraFgHeight = maxMainTop - cellHeaderHeight;
595
+ heightsByCol.push(simpleHeightsByCol[col++] + extraFgHeight);
596
+ }
597
+ }
598
+ const highlightSegs = this.getHighlightSegs();
599
+ const mirrorSegs = this.getMirrorSegs();
601
600
  const forcedInvisibleMap = // TODO: more convenient/DRY
602
601
  (props.eventDrag && props.eventDrag.affectedInstances) ||
603
602
  (props.eventResize && props.eventResize.affectedInstances) ||
604
603
  {};
605
- return (preact_cjs.createElement("div", { role: props.cellGroup ? undefined : 'row', className: [
606
- 'fc-daygrid-row',
607
- props.forceVSpacing
608
- ? 'fc-daygrid-row-spacious'
609
- : props.compact
610
- ? 'fc-daygrid-row-compact'
611
- : '',
612
- props.cellGroup ? 'fc-flex-row' : 'fc-row',
613
- 'fc-rel',
614
- props.className || '',
615
- ].join(' '), style: {
604
+ const isNavLink = options.navLinks;
605
+ const fullWeekStr = internal_cjs.buildDateStr(context, weekDate, 'week');
606
+ return (preact_cjs.createElement("div", { role: props.role /* !!! */, "aria-label": props.role === 'row' // HACK
607
+ ? fullWeekStr
608
+ : undefined // can't have label on non-role div
609
+ , className: internal_cjs.joinClassNames('fc-flex-row fc-rel', props.className), style: {
616
610
  minHeight: props.minHeight,
617
611
  }, ref: this.handleRootEl },
618
- props.cells.map((cell, col) => {
619
- const normalFgNodes = this.renderFgSegs(fgEventSegsByCol[col], segTops, props.todayRange, forcedInvisibleMap);
620
- const mirrorFgNodes = this.renderFgSegs(mirrorSegsByCol[col], segTops, props.todayRange, {}, // forcedInvisibleMap
621
- Boolean(props.eventDrag), Boolean(props.eventResize), false);
622
- return (preact_cjs.createElement(DayGridCell, { key: cell.key, dateProfile: props.dateProfile, todayRange: props.todayRange, date: cell.date, showDayNumber: props.showDayNumbers,
612
+ this.renderFillSegs(props.businessHourSegs, 'non-business'),
613
+ this.renderFillSegs(props.bgEventSegs, 'bg-event'),
614
+ this.renderFillSegs(highlightSegs, 'highlight'),
615
+ preact_cjs.createElement("div", { className: 'fc-flex-row fc-liquid fc-rel' }, props.cells.map((cell, col) => {
616
+ const normalFgNodes = this.renderFgSegs(maxMainTop, renderableSegsByCol[col], segTops, props.todayRange, forcedInvisibleMap);
617
+ return (preact_cjs.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),
623
618
  // content
624
- segs: fgEventSegsByCol[col], hiddenSegs: hiddenSegsByCol[col], fgLiquidHeight: fgLiquidHeight, fg: (preact_cjs.createElement(preact_cjs.Fragment, null,
625
- preact_cjs.createElement(preact_cjs.Fragment, null, normalFgNodes),
626
- preact_cjs.createElement(preact_cjs.Fragment, null, mirrorFgNodes))), bg: (preact_cjs.createElement(preact_cjs.Fragment, null,
627
- this.renderFillSegs(highlightSegsByCol[col], 'highlight'),
628
- this.renderFillSegs(businessHoursByCol[col], 'non-business'),
629
- this.renderFillSegs(bgEventSegsByCol[col], 'bg-event'))), eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
619
+ segs: segsByCol[col], hiddenSegs: hiddenSegsByCol[col], fgLiquidHeight: fgLiquidHeight, fg: (preact_cjs.createElement(preact_cjs.Fragment, null, normalFgNodes)), eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
630
620
  // render hooks
631
- extraRenderProps: cell.extraRenderProps, extraDateSpan: cell.extraDateSpan, extraDataAttrs: cell.extraDataAttrs, extraClassNames: cell.extraClassNames,
621
+ renderProps: cell.renderProps, dateSpanProps: cell.dateSpanProps, attrs: cell.attrs, className: cell.className,
632
622
  // dimensions
633
623
  fgHeight: heightsByCol[col], width: props.colWidth,
634
624
  // refs
635
- innerHeightRef: cellInnerHeightRefMap.createRef(cell.key), headerHeightRef: cellHeaderHeightRefMap.createRef(cell.key) }));
636
- }),
637
- props.showWeekNumbers && (preact_cjs.createElement(internal_cjs.WeekNumberContainer, { elTag: "a", elClasses: ['fc-daygrid-week-number'], elAttrs: internal_cjs.buildNavLinkAttrs(context, weekDate, 'week'), date: weekDate, defaultFormat: DEFAULT_WEEK_NUM_FORMAT }))));
638
- }
639
- renderFgSegs(segs, segTops, todayRange, forcedInvisibleMap, isDragging, isResizing, isDateSelecting) {
625
+ headerHeightRef: headerHeightRefMap.createRef(cell.key), mainHeightRef: mainHeightRefMap.createRef(cell.key) }));
626
+ })),
627
+ props.showWeekNumbers && (preact_cjs.createElement(internal_cjs.WeekNumberContainer, { tag: 'div', attrs: Object.assign(Object.assign({}, (isNavLink
628
+ ? internal_cjs.buildNavLinkAttrs(context, weekDate, 'week', fullWeekStr, /* isTabbable = */ false)
629
+ : {})), { 'role': undefined, 'aria-hidden': true }), className: 'fc-daygrid-week-number', date: weekDate, defaultFormat: DEFAULT_WEEK_NUM_FORMAT })),
630
+ this.renderFgSegs(maxMainTop, mirrorSegs, segTops, props.todayRange, {}, // forcedInvisibleMap
631
+ Boolean(props.eventDrag), Boolean(props.eventResize), false)));
632
+ }
633
+ renderFgSegs(headerHeight, segs, segTops, todayRange, forcedInvisibleMap, isDragging, isResizing, isDateSelecting) {
634
+ var _a;
640
635
  const { props, context, segHeightRefMap } = this;
641
636
  const { isRtl } = context;
642
637
  const { colWidth, eventSelection } = props;
@@ -645,30 +640,26 @@ class DayGridRow extends internal_cjs.BaseComponent {
645
640
  const isMirror = isDragging || isResizing || isDateSelecting;
646
641
  const nodes = [];
647
642
  for (const seg of segs) {
648
- const { left, right, width } = computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl);
649
- // TODO: optimize ID creation? all related
650
- const { eventRange } = seg;
643
+ const key = getEventPartKey(seg);
644
+ const { standinFor, eventRange } = seg;
651
645
  const { instanceId } = eventRange.instance;
652
- const segSpanId = getSegSpanId(seg);
653
- const segStartId = getSegStartId(seg);
654
- const top = segTops[segStartId];
655
- const isVisible = !seg.isStandin &&
656
- top != null &&
657
- !forcedInvisibleMap[instanceId];
658
- /*
659
- TODO: is this comment still relevant? vvvvvvvv
660
- known bug: events that are force to be list-item but span multiple days still take up space in later columns
661
- todo: in print view, for multi-day events, don't display title within non-start/end segs
662
- */
663
- nodes.push(preact_cjs.createElement(DayGridEventHarness, { key: segSpanId, style: {
664
- visibility: isVisible ? '' : 'hidden',
646
+ if (standinFor) {
647
+ continue;
648
+ }
649
+ const { left, right } = computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl);
650
+ const localTop = (_a = segTops.get(standinFor ? getEventPartKey(standinFor) : key)) !== null && _a !== void 0 ? _a : (isMirror ? 0 : undefined);
651
+ const top = headerHeight != null && localTop != null
652
+ ? headerHeight + localTop
653
+ : undefined;
654
+ const isInvisible = standinFor || forcedInvisibleMap[instanceId] || top == null;
655
+ nodes.push(preact_cjs.createElement(DayGridEventHarness, { key: key, className: seg.start ? 'fc-border-transparent fc-border-s' : '', style: {
656
+ visibility: isInvisible ? 'hidden' : '',
665
657
  top,
666
658
  left,
667
659
  right,
668
- width,
669
- }, heightRef: (isMirror || seg.isStandin)
670
- ? null
671
- : segHeightRefMap.createRef(segSpanId) }, hasListItemDisplay(seg) ? (preact_cjs.createElement(DayGridListEvent, Object.assign({ eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: isDragging, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, internal_cjs.getEventRangeMeta(eventRange, todayRange)))) : (preact_cjs.createElement(DayGridBlockEvent, Object.assign({ eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, internal_cjs.getEventRangeMeta(eventRange, todayRange))))));
660
+ }, heightRef: (!standinFor && !isMirror)
661
+ ? segHeightRefMap.createRef(key)
662
+ : null }, hasListItemDisplay(seg) ? (preact_cjs.createElement(DayGridListEvent, Object.assign({ eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: isDragging, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, internal_cjs.getEventRangeMeta(eventRange, todayRange)))) : (preact_cjs.createElement(DayGridBlockEvent, Object.assign({ eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, internal_cjs.getEventRangeMeta(eventRange, todayRange))))));
672
663
  }
673
664
  return nodes;
674
665
  }
@@ -679,17 +670,17 @@ class DayGridRow extends internal_cjs.BaseComponent {
679
670
  const colCnt = props.cells.length;
680
671
  const nodes = [];
681
672
  for (const seg of segs) {
682
- const { left, right, width } = computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl);
683
- const isVisible = !seg.isStandin;
684
- nodes.push(preact_cjs.createElement("div", { key: internal_cjs.buildEventRangeKey(seg.eventRange), className: "fc-fill-y", style: {
673
+ const key = internal_cjs.buildEventRangeKey(seg.eventRange); // TODO: use different type of key than fg!?
674
+ const { left, right } = computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl);
675
+ const isVisible = !seg.standinFor;
676
+ nodes.push(preact_cjs.createElement("div", { key: key, className: "fc-fill-y", style: {
685
677
  visibility: isVisible ? '' : 'hidden',
686
678
  left,
687
679
  right,
688
- width,
689
680
  } }, fillType === 'bg-event' ?
690
681
  preact_cjs.createElement(internal_cjs.BgEvent, Object.assign({ eventRange: seg.eventRange, isStart: seg.isStart, isEnd: seg.isEnd }, internal_cjs.getEventRangeMeta(seg.eventRange, todayRange))) : (internal_cjs.renderFill(fillType))));
691
682
  }
692
- return preact_cjs.createElement(preact_cjs.Fragment, {}, ...nodes);
683
+ return preact_cjs.createElement(preact_cjs.Fragment, {}, ...nodes); // TODO: shouldn't this be an array, so keyed?
693
684
  }
694
685
  // Sizing
695
686
  // -----------------------------------------------------------------------------------------------
@@ -702,9 +693,36 @@ class DayGridRow extends internal_cjs.BaseComponent {
702
693
  componentWillUnmount() {
703
694
  this.disconnectHeight();
704
695
  internal_cjs.setRef(this.props.heightRef, null);
705
- internal_cjs.setRef(this.props.innerHeightRef, null);
706
696
  }
707
- // Utils
697
+ computeFgDims() {
698
+ const { cells } = this.props;
699
+ const headerHeightMap = this.headerHeightRefMap.current;
700
+ const mainHeightMap = this.mainHeightRefMap.current;
701
+ let maxMainTop;
702
+ let minMainBottom;
703
+ for (const cell of cells) {
704
+ const mainTop = headerHeightMap.get(cell.key);
705
+ const mainHeight = mainHeightMap.get(cell.key);
706
+ if (mainTop != null) {
707
+ if (maxMainTop === undefined || mainTop > maxMainTop) {
708
+ maxMainTop = mainTop;
709
+ }
710
+ if (mainHeight != null) {
711
+ const mainBottom = mainTop + mainHeight;
712
+ if (minMainBottom === undefined || mainBottom < minMainBottom) {
713
+ minMainBottom = mainBottom;
714
+ }
715
+ }
716
+ }
717
+ }
718
+ return [
719
+ maxMainTop,
720
+ minMainBottom != null && maxMainTop != null
721
+ ? minMainBottom - maxMainTop
722
+ : undefined,
723
+ ];
724
+ }
725
+ // Internal Utils
708
726
  // -----------------------------------------------------------------------------------------------
709
727
  getMirrorSegs() {
710
728
  let { props } = this;
@@ -757,7 +775,7 @@ class DayGridRows extends internal_cjs.DateComponent {
757
775
  };
758
776
  }
759
777
  render() {
760
- let { props, state, context, rowHeightRefMap } = this;
778
+ let { props, context, rowHeightRefMap } = this;
761
779
  let { options } = context;
762
780
  let rowCnt = props.cellRows.length;
763
781
  let fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, rowCnt);
@@ -766,31 +784,31 @@ class DayGridRows extends internal_cjs.DateComponent {
766
784
  let dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, rowCnt);
767
785
  let eventDragByRow = this.splitEventDrag(props.eventDrag, rowCnt);
768
786
  let eventResizeByRow = this.splitEventResize(props.eventResize, rowCnt);
769
- // whether the ROW should expand in height
770
- // (not to be confused with whether the fg events within the row should be molded by height of row)
771
787
  let isHeightAuto = internal_cjs.getIsHeightAuto(options);
772
- // maintain at least aspectRatio for cells?
773
- let rowMinHeight = (state.width != null && (rowCnt >= 7 || // TODO: better way to infer if across single-month boundary
774
- isHeightAuto)) ? state.width / context.options.aspectRatio / 6 // okay to hardcode 6 (weeks) ?
775
- : null;
776
- return (preact_cjs.createElement("div", { className: 'fc-grow fc-flex-column', style: { width: props.width }, ref: this.handleRootEl }, props.cellRows.map((cells, row) => (preact_cjs.createElement(DayGridRow, { key: cells[0].key, dateProfile: props.dateProfile, todayRange: props.todayRange, cells: cells, showDayNumbers: rowCnt > 1, showWeekNumbers: options.weekNumbers, forPrint: props.forPrint, compact: state.width != null && (state.width / cells.length) < COMPACT_CELL_WIDTH,
788
+ let rowHeightsRedistribute = !props.forPrint && !isHeightAuto;
789
+ let [rowMinHeight, isCompact] = computeRowHeight(props.visibleWidth, rowCnt, isHeightAuto, props.forPrint, options);
790
+ return (preact_cjs.createElement("div", { role: 'rowgroup', className: internal_cjs.joinClassNames(
791
+ // HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
792
+ // https://stackoverflow.com/a/60256345
793
+ !props.forPrint && 'fc-flex-col', props.className), style: { width: props.width }, ref: this.handleRootEl }, props.cellRows.map((cells, row) => (preact_cjs.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,
777
794
  // if not auto-height, distribute height of container somewhat evently to rows
778
795
  // (treat all as zero, distribute height, then ensure min-heights -- the inner content height)
779
- className: isHeightAuto ? '' : 'fc-grow fc-basis0',
796
+ className: internal_cjs.joinClassNames(rowHeightsRedistribute && 'fc-grow fc-basis0', rowCnt > 1 && 'fc-break-inside-avoid', // don't avoid breaks for single tall row
797
+ row < rowCnt - 1 && 'fc-border-b'),
780
798
  // content
781
- 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: options.dayMaxEvents, dayMaxEventRows: options.dayMaxEventRows,
799
+ 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,
782
800
  // dimensions
783
801
  colWidth: props.colWidth, minHeight: rowMinHeight,
784
802
  // refs
785
803
  heightRef: rowHeightRefMap.createRef(cells[0].key) })))));
786
804
  }
787
805
  componentDidMount() {
788
- this.detachWidth = internal_cjs.watchWidth(this.rootEl, (width) => {
806
+ this.disconnectWidth = internal_cjs.watchWidth(this.rootEl, (width) => {
789
807
  this.setState({ width });
790
808
  });
791
809
  }
792
810
  componentWillUnmount() {
793
- this.detachWidth();
811
+ this.disconnectWidth();
794
812
  }
795
813
  // Hit System
796
814
  // -----------------------------------------------------------------------------------------------
@@ -807,7 +825,7 @@ class DayGridRows extends internal_cjs.DateComponent {
807
825
  dateSpan: Object.assign({ range: {
808
826
  start: cellStartDate,
809
827
  end: cellEndDate,
810
- }, allDay: true }, cell.extraDateSpan),
828
+ }, allDay: true }, cell.dateSpanProps),
811
829
  // HACK. TODO: This is expensive to do every hit-query
812
830
  dayEl: getCellEl(getRowEl(this.rootEl, row), col),
813
831
  rect: {
@@ -825,28 +843,98 @@ class DayGridRows extends internal_cjs.DateComponent {
825
843
  function isSegAllDay(seg) {
826
844
  return seg.eventRange.def.allDay;
827
845
  }
846
+ function computeRowHeight(visibleWidth, // should INCLUDE any scrollbar width to avoid oscillation
847
+ rowCnt, isHeightAuto, forPrint, options) {
848
+ if (visibleWidth != null) {
849
+ // ensure a consistent row min-height modelled after a month with 6 rows respecting aspectRatio
850
+ // will result in same minHeight regardless of weekends, dayMinWidth, height:auto
851
+ const rowMinHeight = visibleWidth / options.aspectRatio / 6;
852
+ return [
853
+ forPrint
854
+ // special-case for print, which condenses whole-page width without notifying
855
+ // this is value that looks natural on paper for portrait/landscape
856
+ ? '6em'
857
+ // don't give minHeight when single-month non-auto-height
858
+ // TODO: better way to detect this with DateProfile?
859
+ : (rowCnt > 6 || isHeightAuto)
860
+ ? rowMinHeight
861
+ : undefined,
862
+ // isCompact?: just before most lone +more links hit bottom of cell
863
+ rowMinHeight < 70,
864
+ ];
865
+ }
866
+ return [undefined, false];
867
+ }
868
+
869
+ class DayGridHeaderCell extends internal_cjs.BaseComponent {
870
+ constructor() {
871
+ super(...arguments);
872
+ this.handleInnerEl = (innerEl) => {
873
+ if (this.disconectInnerHeight) {
874
+ this.disconectInnerHeight();
875
+ this.disconectInnerHeight = undefined;
876
+ }
877
+ if (innerEl) {
878
+ this.disconectInnerHeight = internal_cjs.watchHeight(innerEl, (height) => {
879
+ internal_cjs.setRef(this.props.innerHeightRef, height);
880
+ });
881
+ }
882
+ else {
883
+ internal_cjs.setRef(this.props.innerHeightRef, null);
884
+ }
885
+ };
886
+ }
887
+ render() {
888
+ const { props } = this;
889
+ const { renderConfig, dataConfig } = props;
890
+ // HACK
891
+ const isDisabled = dataConfig.renderProps.isDisabled;
892
+ return (preact_cjs.createElement(internal_cjs.ContentContainer, { tag: 'div', attrs: Object.assign({ role: 'columnheader', 'aria-colspan': dataConfig.colSpan }, dataConfig.attrs), className: internal_cjs.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: {
893
+ width: props.colWidth != null
894
+ ? props.colWidth * (dataConfig.colSpan || 1)
895
+ : undefined,
896
+ }, renderProps: dataConfig.renderProps, generatorName: renderConfig.generatorName, customGenerator: renderConfig.customGenerator, defaultGenerator: internal_cjs.renderText, classNameGenerator:
897
+ // don't use custom classNames if disabled
898
+ // TODO: make DRY with DayCellContainer
899
+ isDisabled ? undefined : renderConfig.classNameGenerator, didMount: renderConfig.didMount, willUnmount: renderConfig.willUnmount }, (InnerContainer) => (preact_cjs.createElement(InnerContainer, { tag: 'div', attrs: dataConfig.innerAttrs, className: internal_cjs.joinClassNames('fc-cell-inner fc-flex-col fc-padding-sm', props.isSticky && 'fc-sticky-s'), elRef: this.handleInnerEl }))));
900
+ }
901
+ }
828
902
 
829
- class HeaderRow extends internal_cjs.BaseComponent {
903
+ class DayGridHeaderRow extends internal_cjs.BaseComponent {
904
+ constructor() {
905
+ super(...arguments);
906
+ // ref
907
+ this.innerHeightRefMap = new internal_cjs.RefMap(() => {
908
+ internal_cjs.afterSize(this.handleInnerHeights);
909
+ });
910
+ this.handleInnerHeights = () => {
911
+ const innerHeightMap = this.innerHeightRefMap.current;
912
+ let max = 0;
913
+ for (const innerHeight of innerHeightMap.values()) {
914
+ max = Math.max(max, innerHeight);
915
+ }
916
+ if (this.currentInnerHeight !== max) {
917
+ this.currentInnerHeight = max;
918
+ internal_cjs.setRef(this.props.innerHeightRef, max);
919
+ }
920
+ };
921
+ }
830
922
  render() {
831
923
  const { props } = this;
832
- return (preact_cjs.createElement("div", { role: props.cellGroup ? undefined : 'row', className: [
833
- props.cellGroup ? 'fc-flex-row' : 'fc-row',
834
- props.className || '',
835
- ].join(' ') }, props.cells.map((cell) => (preact_cjs.createElement(preact_cjs.Fragment, { key: props.getHeaderModelKey(cell) }, props.renderHeaderContent(cell, props.tierNum, undefined, // innerHeightRef
836
- props.colWidth))))));
924
+ return (preact_cjs.createElement("div", { role: props.role /* !!! */, "aria-rowindex": props.rowIndex != null ? 1 + props.rowIndex : undefined, className: internal_cjs.joinClassNames('fc-flex-row fc-content-box', props.className), style: { height: props.height } }, props.dataConfigs.map((dataConfig, cellI) => (preact_cjs.createElement(DayGridHeaderCell, { key: dataConfig.key, renderConfig: props.renderConfig, dataConfig: dataConfig, isSticky: props.isSticky, borderStart: Boolean(cellI), colWidth: props.colWidth, innerHeightRef: props.innerHeightRef })))));
837
925
  }
838
926
  }
839
927
 
840
- function DayGridHeader(props) {
841
- return (preact_cjs.createElement("div", { className: [
842
- 'fc-rowgroup',
843
- 'fc-content-box',
844
- ...(props.extraClassNames || []),
845
- ].join(' '), style: {
846
- width: props.width,
847
- paddingLeft: props.paddingLeft,
848
- paddingRight: props.paddingRight,
849
- } }, props.headerTiers.map((cells, tierNum) => (preact_cjs.createElement(HeaderRow, { key: tierNum, tierNum: tierNum, cells: cells, renderHeaderContent: props.renderHeaderContent, getHeaderModelKey: props.getHeaderModelKey, colWidth: props.colWidth })))));
928
+ /*
929
+ TODO: kill this class in favor of DayGridHeaderRows?
930
+ */
931
+ class DayGridHeader extends internal_cjs.BaseComponent {
932
+ render() {
933
+ const { props } = this;
934
+ return (preact_cjs.createElement("div", { role: 'rowgroup', className: internal_cjs.joinClassNames(props.className, 'fc-flex-col', props.width == null && 'fc-liquid'), style: {
935
+ width: props.width
936
+ } }, props.headerTiers.map((rowConfig, tierNum) => (preact_cjs.createElement(DayGridHeaderRow, Object.assign({}, rowConfig, { key: tierNum, role: 'row', className: tierNum ? 'fc-border-t' : '', colWidth: props.colWidth }))))));
937
+ }
850
938
  }
851
939
 
852
940
  class DayGridLayoutNormal extends internal_cjs.BaseComponent {
@@ -855,11 +943,11 @@ class DayGridLayoutNormal extends internal_cjs.BaseComponent {
855
943
  this.handleScroller = (scroller) => {
856
944
  internal_cjs.setRef(this.props.scrollerRef, scroller);
857
945
  };
858
- this.handleLeftScrollbarWidth = (leftScrollbarWidth) => {
859
- this.setState({ leftScrollbarWidth });
946
+ this.handleClientWidth = (clientWidth) => {
947
+ this.setState({ clientWidth });
860
948
  };
861
- this.handleRightScrollbarWidth = (rightScrollbarWidth) => {
862
- this.setState({ rightScrollbarWidth });
949
+ this.handleEndScrollbarWidth = (endScrollbarWidth) => {
950
+ this.setState({ endScrollbarWidth });
863
951
  };
864
952
  }
865
953
  render() {
@@ -868,24 +956,22 @@ class DayGridLayoutNormal extends internal_cjs.BaseComponent {
868
956
  const verticalScrollbars = !props.forPrint && !internal_cjs.getIsHeightAuto(options);
869
957
  const stickyHeaderDates = !props.forPrint && internal_cjs.getStickyHeaderDates(options);
870
958
  return (preact_cjs.createElement(preact_cjs.Fragment, null,
871
- options.dayHeaders && (preact_cjs.createElement(DayGridHeader, { headerTiers: props.headerTiers, renderHeaderContent: props.renderHeaderContent, getHeaderModelKey: props.getHeaderModelKey,
872
- // render hooks
873
- extraClassNames: [
874
- 'fc-daygrid-header',
875
- stickyHeaderDates ? 'fc-sticky-header' : '',
876
- ],
877
- // dimensions
878
- paddingLeft: state.leftScrollbarWidth, paddingRight: state.rightScrollbarWidth })),
879
- preact_cjs.createElement(internal_cjs.Scroller, { vertical: verticalScrollbars, leftScrollbarWidthRef: this.handleLeftScrollbarWidth, rightScrollbarWidthRef: this.handleRightScrollbarWidth, elClassNames: [
880
- 'fc-daygrid-body',
881
- 'fc-rowgroup',
882
- 'fc-flex-column',
883
- verticalScrollbars ? 'fc-liquid' : '',
884
- ], ref: this.handleScroller },
885
- preact_cjs.createElement(DayGridRows // .fc-grow
886
- , { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: props.cellRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed,
959
+ options.dayHeaders && (preact_cjs.createElement("div", { className: internal_cjs.joinClassNames(props.forPrint ? 'fc-print-header' : 'fc-flex-row', // col for print, row for screen
960
+ 'fc-border-b') },
961
+ preact_cjs.createElement(DayGridHeader, { headerTiers: props.headerTiers, className: internal_cjs.joinClassNames('fc-daygrid-header', stickyHeaderDates && 'fc-table-header-sticky') }),
962
+ Boolean(state.endScrollbarWidth) && (preact_cjs.createElement("div", { className: 'fc-border-s fc-filler', style: { minWidth: state.endScrollbarWidth } })))),
963
+ preact_cjs.createElement(internal_cjs.Scroller, { vertical: verticalScrollbars, clientWidthRef: this.handleClientWidth, endScrollbarWidthRef: this.handleEndScrollbarWidth, className: internal_cjs.joinClassNames('fc-daygrid-body',
964
+ // HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
965
+ // https://stackoverflow.com/a/60256345
966
+ !props.forPrint && 'fc-flex-col', verticalScrollbars && 'fc-liquid'), ref: this.handleScroller },
967
+ preact_cjs.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,
887
968
  // content
888
969
  fgEventSegs: props.fgEventSegs, bgEventSegs: props.bgEventSegs, businessHourSegs: props.businessHourSegs, dateSelectionSegs: props.dateSelectionSegs, eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
970
+ // dimensions
971
+ visibleWidth: // TODO: DRY
972
+ state.clientWidth != null && state.endScrollbarWidth != null
973
+ ? state.clientWidth + state.endScrollbarWidth
974
+ : undefined,
889
975
  // refs
890
976
  rowHeightRefMap: props.rowHeightRefMap }))));
891
977
  }
@@ -899,14 +985,11 @@ class DayGridLayoutPannable extends internal_cjs.BaseComponent {
899
985
  this.footerScrollerRef = preact_cjs.createRef();
900
986
  // Sizing
901
987
  // -----------------------------------------------------------------------------------------------
902
- this.handleWidth = (width) => {
903
- this.setState({ width });
988
+ this.handleClientWidth = (clientWidth) => {
989
+ this.setState({ clientWidth });
904
990
  };
905
- this.handleLeftScrollbarWidth = (leftScrollbarWidth) => {
906
- this.setState({ leftScrollbarWidth });
907
- };
908
- this.handleRightScrollbarWidth = (rightScrollbarWidth) => {
909
- this.setState({ rightScrollbarWidth });
991
+ this.handleEndScrollbarWidth = (endScrollbarWidth) => {
992
+ this.setState({ endScrollbarWidth });
910
993
  };
911
994
  }
912
995
  render() {
@@ -916,37 +999,29 @@ class DayGridLayoutPannable extends internal_cjs.BaseComponent {
916
999
  const stickyHeaderDates = !props.forPrint && internal_cjs.getStickyHeaderDates(options);
917
1000
  const stickyFooterScrollbar = !props.forPrint && internal_cjs.getStickyFooterScrollbar(options);
918
1001
  const colCnt = props.cellRows[0].length;
919
- const [canvasWidth, colWidth] = computeColWidth(colCnt, props.dayMinWidth, state.width);
1002
+ const [canvasWidth, colWidth] = computeColWidth(colCnt, props.dayMinWidth, state.clientWidth);
920
1003
  return (preact_cjs.createElement(preact_cjs.Fragment, null,
921
- options.dayHeaders && (preact_cjs.createElement(internal_cjs.Scroller, { horizontal: true, hideScrollbars: true, elClassNames: [
922
- 'fc-daygrid-header',
923
- 'fc-rowgroup',
924
- stickyHeaderDates ? 'fc-sticky-header' : ''
925
- ], ref: this.headerScrollerRef },
926
- preact_cjs.createElement(DayGridHeader, { headerTiers: props.headerTiers, renderHeaderContent: props.renderHeaderContent, getHeaderModelKey: props.getHeaderModelKey,
927
- // dimensions
928
- colWidth: colWidth, width: canvasWidth, paddingLeft: state.leftScrollbarWidth, paddingRight: state.rightScrollbarWidth }))),
929
- preact_cjs.createElement(internal_cjs.Scroller, { vertical: verticalScrollbars, horizontal: true, hideScrollbars: stickyFooterScrollbar, widthRef: this.handleWidth, leftScrollbarWidthRef: this.handleLeftScrollbarWidth, rightScrollbarWidthRef: this.handleRightScrollbarWidth, elClassNames: [
930
- 'fc-daygrid-body',
931
- 'fc-rowgroup',
932
- 'fc-flex-column',
933
- verticalScrollbars ? 'fc-liquid' : '',
934
- ], ref: this.bodyScrollerRef },
935
- preact_cjs.createElement(DayGridRows // .fc-grow
936
- , { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: props.cellRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed,
1004
+ options.dayHeaders && (preact_cjs.createElement("div", { className: 'fc-print-header' },
1005
+ preact_cjs.createElement(internal_cjs.Scroller, { horizontal: true, hideScrollbars: true, className: internal_cjs.joinClassNames('fc-daygrid-header fc-flex-row fc-border-b', stickyHeaderDates && 'fc-table-header-sticky'), ref: this.headerScrollerRef },
1006
+ preact_cjs.createElement(DayGridHeader, { headerTiers: props.headerTiers, colWidth: colWidth, width: canvasWidth }),
1007
+ Boolean(state.endScrollbarWidth) && (preact_cjs.createElement("div", { className: 'fc-border-s fc-filler', style: { minWidth: state.endScrollbarWidth } }))))),
1008
+ preact_cjs.createElement(internal_cjs.Scroller, { vertical: verticalScrollbars, horizontal: true, hideScrollbars: stickyFooterScrollbar ||
1009
+ props.forPrint // prevents blank space in print-view on Safari
1010
+ , className: internal_cjs.joinClassNames('fc-daygrid-body',
1011
+ // HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
1012
+ // https://stackoverflow.com/a/60256345
1013
+ !props.forPrint && 'fc-flex-col', verticalScrollbars && 'fc-liquid'), ref: this.bodyScrollerRef, clientWidthRef: this.handleClientWidth, endScrollbarWidthRef: this.handleEndScrollbarWidth },
1014
+ preact_cjs.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,
937
1015
  // content
938
1016
  fgEventSegs: props.fgEventSegs, bgEventSegs: props.bgEventSegs, businessHourSegs: props.businessHourSegs, dateSelectionSegs: props.dateSelectionSegs, eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
939
1017
  // dimensions
940
- colWidth: colWidth, width: canvasWidth,
1018
+ colWidth: colWidth, width: canvasWidth, visibleWidth: // TODO: DRY
1019
+ state.clientWidth != null && state.endScrollbarWidth != null
1020
+ ? state.clientWidth + state.endScrollbarWidth
1021
+ : undefined,
941
1022
  // refs
942
1023
  rowHeightRefMap: props.rowHeightRefMap })),
943
- Boolean(stickyFooterScrollbar) && (preact_cjs.createElement(internal_cjs.Scroller, { ref: this.footerScrollerRef, horizontal: true, elClassNames: ['fc-sticky-footer'], elStyle: {
944
- marginTop: '-1px', // HACK
945
- } },
946
- preact_cjs.createElement("div", { style: {
947
- width: canvasWidth,
948
- height: '1px', // HACK
949
- } })))));
1024
+ Boolean(stickyFooterScrollbar) && (preact_cjs.createElement(internal_cjs.StickyFooterScrollbar, { canvasWidth: canvasWidth, scrollerRef: this.footerScrollerRef }))));
950
1025
  }
951
1026
  // Lifecycle
952
1027
  // -----------------------------------------------------------------------------------------------
@@ -1001,21 +1076,29 @@ class DayGridLayout extends internal_cjs.BaseComponent {
1001
1076
  }
1002
1077
  }
1003
1078
  };
1004
- this.clearScroll = () => {
1005
- this.scrollDate = null;
1079
+ this.handleScrollEnd = ({ isUser }) => {
1080
+ if (isUser) {
1081
+ this.scrollDate = null;
1082
+ }
1006
1083
  };
1007
1084
  }
1008
1085
  render() {
1009
1086
  const { props, context } = this;
1010
1087
  const { options } = context;
1011
1088
  const commonLayoutProps = Object.assign(Object.assign({}, props), { scrollerRef: this.scrollerRef, rowHeightRefMap: this.rowHeightRefMap });
1012
- return (preact_cjs.createElement(internal_cjs.ViewContainer, { viewSpec: context.viewSpec, elClasses: [props.className, 'fc-flex-column', 'fc-border'] }, options.dayMinWidth ? (preact_cjs.createElement(DayGridLayoutPannable, Object.assign({}, commonLayoutProps, { dayMinWidth: options.dayMinWidth }))) : (preact_cjs.createElement(DayGridLayoutNormal, Object.assign({}, commonLayoutProps)))));
1089
+ return (preact_cjs.createElement(internal_cjs.ViewContainer, { viewSpec: context.viewSpec, attrs: {
1090
+ role: 'grid',
1091
+ 'aria-rowcount': props.headerTiers.length + props.cellRows.length,
1092
+ 'aria-colcount': props.cellRows[0].length,
1093
+ 'aria-labelledby': props.labelId,
1094
+ 'aria-label': props.labelStr,
1095
+ }, className: internal_cjs.joinClassNames(props.className, 'fc-print-root fc-border') }, options.dayMinWidth ? (preact_cjs.createElement(DayGridLayoutPannable, Object.assign({}, commonLayoutProps, { dayMinWidth: options.dayMinWidth }))) : (preact_cjs.createElement(DayGridLayoutNormal, Object.assign({}, commonLayoutProps)))));
1013
1096
  }
1014
1097
  // Lifecycle
1015
1098
  // -----------------------------------------------------------------------------------------------
1016
1099
  componentDidMount() {
1017
1100
  this.resetScroll();
1018
- this.scrollerRef.current.addScrollEndListener(this.clearScroll);
1101
+ this.scrollerRef.current.addScrollEndListener(this.handleScrollEnd);
1019
1102
  }
1020
1103
  componentDidUpdate(prevProps) {
1021
1104
  if (prevProps.dateProfile !== this.props.dateProfile && this.context.options.scrollTimeReset) {
@@ -1023,98 +1106,24 @@ class DayGridLayout extends internal_cjs.BaseComponent {
1023
1106
  }
1024
1107
  }
1025
1108
  componentWillUnmount() {
1026
- this.scrollerRef.current.removeScrollEndListener(this.clearScroll);
1109
+ this.scrollerRef.current.removeScrollEndListener(this.handleScrollEnd);
1027
1110
  }
1028
1111
  // Scrolling
1029
1112
  // -----------------------------------------------------------------------------------------------
1030
1113
  resetScroll() {
1031
1114
  this.scrollDate = this.props.dateProfile.currentDate;
1032
1115
  this.updateScrollY();
1033
- // updateScrollX
1034
1116
  const scroller = this.scrollerRef.current;
1035
1117
  scroller.scrollTo({ x: 0 });
1036
1118
  }
1037
1119
  }
1038
1120
 
1039
- const WEEKDAY_FORMAT = internal_cjs.createFormatter({ weekday: 'long' });
1040
- class DayOfWeekHeaderCell extends internal_cjs.BaseComponent {
1041
- constructor() {
1042
- super(...arguments);
1043
- // ref
1044
- this.innerElRef = preact_cjs.createRef();
1045
- }
1046
- render() {
1047
- let { props, context } = this;
1048
- let { dateEnv, theme, viewApi, options } = context;
1049
- let date = internal_cjs.addDays(new Date(259200000), props.dow); // start with Sun, 04 Jan 1970 00:00:00 GMT
1050
- let dateMeta = {
1051
- dow: props.dow,
1052
- isDisabled: false,
1053
- isFuture: false,
1054
- isPast: false,
1055
- isToday: false,
1056
- isOther: false,
1057
- };
1058
- let text = dateEnv.format(date, props.dayHeaderFormat);
1059
- let renderProps = Object.assign(Object.assign(Object.assign(Object.assign({ date }, dateMeta), { view: viewApi }), props.extraRenderProps), { text });
1060
- return (preact_cjs.createElement(internal_cjs.ContentContainer, { elTag: 'div', elClasses: [
1061
- ...internal_cjs.getDayClassNames(dateMeta, theme),
1062
- ...(props.extraClassNames || []),
1063
- 'fc-header-cell',
1064
- 'fc-cell',
1065
- props.colWidth != null ? '' : 'fc-liquid',
1066
- 'fc-flex-column',
1067
- 'fc-align-center',
1068
- ], elAttrs: props.extraDataAttrs, elStyle: {
1069
- width: props.colWidth != null // TODO: DRY
1070
- ? props.colWidth * (props.colSpan || 1)
1071
- : undefined,
1072
- }, renderProps: renderProps, generatorName: "dayHeaderContent", customGenerator: options.dayHeaderContent, defaultGenerator: renderInner, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount }, (InnerContent) => (preact_cjs.createElement("div", { ref: this.innerElRef, className: [
1073
- 'fc-flex-column',
1074
- props.isSticky ? 'fc-sticky-x' : '',
1075
- ].join(' ') },
1076
- preact_cjs.createElement(InnerContent, { elTag: "a", elClasses: [
1077
- 'fc-cell-inner',
1078
- 'fc-padding-sm',
1079
- ], elAttrs: {
1080
- 'aria-label': dateEnv.format(date, WEEKDAY_FORMAT),
1081
- } })))));
1082
- }
1083
- componentDidMount() {
1084
- const innerEl = this.innerElRef.current; // TODO: make dynamic with useEffect
1085
- // TODO: only attach this if refs props present
1086
- this.disconectInnerHeight = internal_cjs.watchHeight(innerEl, (height) => {
1087
- internal_cjs.setRef(this.props.innerHeightRef, height);
1088
- });
1089
- }
1090
- componentWillUnmount() {
1091
- this.disconectInnerHeight();
1092
- internal_cjs.setRef(this.props.innerHeightRef, null);
1093
- }
1094
- }
1095
-
1096
- function createDayHeaderFormatter(explicitFormat, datesRepDistinctDays, dateCnt) {
1097
- return explicitFormat || computeFallbackHeaderFormat(datesRepDistinctDays, dateCnt);
1098
- }
1099
- // Computes a default column header formatting string if `colFormat` is not explicitly defined
1100
- function computeFallbackHeaderFormat(datesRepDistinctDays, dayCnt) {
1101
- // if more than one week row, or if there are a lot of columns with not much space,
1102
- // put just the day numbers will be in each cell
1103
- if (!datesRepDistinctDays || dayCnt > 10) {
1104
- return internal_cjs.createFormatter({ weekday: 'short' }); // "Sat"
1105
- }
1106
- if (dayCnt > 1) {
1107
- return internal_cjs.createFormatter({ weekday: 'short', month: 'numeric', day: 'numeric', omitCommas: true }); // "Sat 11/12"
1108
- }
1109
- return internal_cjs.createFormatter({ weekday: 'long' }); // "Saturday"
1110
- }
1111
-
1112
1121
  class DayGridView extends internal_cjs.BaseComponent {
1113
1122
  constructor() {
1114
1123
  super(...arguments);
1115
1124
  // memo
1116
1125
  this.buildDayTableModel = internal_cjs.memoize(buildDayTableModel);
1117
- this.buildHeaderTiers = internal_cjs.memoize(buildHeaderTiers);
1126
+ this.buildDateRowConfigs = internal_cjs.memoize(buildDateRowConfigs);
1118
1127
  this.createDayHeaderFormatter = internal_cjs.memoize(createDayHeaderFormatter);
1119
1128
  // internal
1120
1129
  this.slicer = new DayTableSlicer();
@@ -1124,77 +1133,76 @@ class DayGridView extends internal_cjs.BaseComponent {
1124
1133
  const { options } = context;
1125
1134
  const dayTableModel = this.buildDayTableModel(props.dateProfile, context.dateProfileGenerator);
1126
1135
  const datesRepDistinctDays = dayTableModel.rowCnt === 1;
1127
- const headerTiers = this.buildHeaderTiers(dayTableModel.headerDates, datesRepDistinctDays);
1128
- const slicedProps = this.slicer.sliceProps(props, props.dateProfile, options.nextDayThreshold, context, dayTableModel);
1129
1136
  const dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, datesRepDistinctDays, dayTableModel.colCnt);
1130
- return (preact_cjs.createElement(internal_cjs.NowTimer, { unit: "day" }, (nowDate, todayRange) => (preact_cjs.createElement(DayGridLayout, { dateProfile: props.dateProfile, todayRange: todayRange, cellRows: dayTableModel.cellRows, forPrint: props.forPrint, className: 'fc-daygrid-view',
1131
- // header content
1132
- headerTiers: headerTiers, renderHeaderContent: (model, tier, innerHeightRef, colWidth) => {
1133
- if (model.date) {
1134
- return (preact_cjs.createElement(DateHeaderCell, Object.assign({}, model, { dateProfile: props.dateProfile, todayRange: todayRange, navLink: dayTableModel.colCnt > 1, dayHeaderFormat: dayHeaderFormat, colSpan: model.colSpan, colWidth: colWidth })));
1135
- }
1136
- else {
1137
- return (preact_cjs.createElement(DayOfWeekHeaderCell, Object.assign({}, model, { dayHeaderFormat: dayHeaderFormat, colSpan: model.colSpan, colWidth: colWidth })));
1138
- }
1139
- }, getHeaderModelKey: (model) => {
1140
- // can use model.key???
1141
- if (model.date) {
1142
- return model.date.toUTCString();
1143
- }
1144
- return model.dow;
1145
- },
1146
- // body content
1147
- fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection }))));
1137
+ const slicedProps = this.slicer.sliceProps(props, props.dateProfile, options.nextDayThreshold, context, dayTableModel);
1138
+ return (preact_cjs.createElement(internal_cjs.NowTimer, { unit: "day" }, (nowDate, todayRange) => {
1139
+ const headerTiers = this.buildDateRowConfigs(dayTableModel.headerDates, datesRepDistinctDays, props.dateProfile, todayRange, dayHeaderFormat, context);
1140
+ return (preact_cjs.createElement(DayGridLayout, { labelId: props.labelId, labelStr: props.labelStr, dateProfile: props.dateProfile, todayRange: todayRange, cellRows: dayTableModel.cellRows, forPrint: props.forPrint, className: 'fc-daygrid',
1141
+ // header content
1142
+ headerTiers: headerTiers,
1143
+ // body content
1144
+ fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection }));
1145
+ }));
1148
1146
  }
1149
1147
  }
1150
1148
 
1151
- /*
1152
- TODO: is it even worth doing this "advanced" version?
1153
- */
1154
- class HeaderRowAdvanced extends internal_cjs.BaseComponent {
1155
- constructor() {
1156
- super(...arguments);
1157
- // ref
1158
- this.innerHeightRefMap = new internal_cjs.RefMap(() => {
1159
- internal_cjs.afterSize(this.handleInnerHeights);
1149
+ class TableDateProfileGenerator extends internal_cjs.DateProfileGenerator {
1150
+ // Computes the date range that will be rendered
1151
+ buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay) {
1152
+ let renderRange = super.buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay);
1153
+ let { props } = this;
1154
+ return buildDayTableRenderRange({
1155
+ currentRange: renderRange,
1156
+ snapToWeek: /^(year|month)$/.test(currentRangeUnit),
1157
+ fixedWeekCount: props.fixedWeekCount,
1158
+ dateEnv: props.dateEnv,
1160
1159
  });
1161
- this.handleInnerHeights = () => {
1162
- const innerHeightMap = this.innerHeightRefMap.current;
1163
- let max = 0;
1164
- for (const innerHeight of innerHeightMap.values()) {
1165
- max = Math.max(max, innerHeight);
1166
- }
1167
- if (this.currentInnerHeight !== max) {
1168
- this.currentInnerHeight = max;
1169
- internal_cjs.setRef(this.props.innerHeightRef, max);
1170
- }
1171
- };
1172
1160
  }
1173
- render() {
1174
- const { props } = this;
1175
- return (preact_cjs.createElement("div", { role: 'row', className: 'fc-row', style: { height: props.height } }, props.cells.map((cell) => {
1176
- const key = props.getHeaderModelKey(cell);
1177
- return (preact_cjs.createElement(preact_cjs.Fragment, { key: props.getHeaderModelKey(cell) }, props.renderHeaderContent(cell, props.tierNum, this.innerHeightRefMap.createRef(key), // innerHeightRef
1178
- props.colWidth)));
1179
- })));
1161
+ }
1162
+ function buildDayTableRenderRange(props) {
1163
+ let { dateEnv, currentRange } = props;
1164
+ let { start, end } = currentRange;
1165
+ let endOfWeek;
1166
+ // year and month views should be aligned with weeks. this is already done for week
1167
+ if (props.snapToWeek) {
1168
+ start = dateEnv.startOfWeek(start);
1169
+ // make end-of-week if not already
1170
+ endOfWeek = dateEnv.startOfWeek(end);
1171
+ if (endOfWeek.valueOf() !== end.valueOf()) {
1172
+ end = internal_cjs.addWeeks(endOfWeek, 1);
1173
+ }
1174
+ }
1175
+ // ensure 6 weeks
1176
+ if (props.fixedWeekCount) {
1177
+ // TODO: instead of these date-math gymnastics (for multimonth view),
1178
+ // compute dateprofiles of all months, then use start of first and end of last.
1179
+ let lastMonthRenderStart = dateEnv.startOfWeek(dateEnv.startOfMonth(internal_cjs.addDays(currentRange.end, -1)));
1180
+ let rowCnt = Math.ceil(// could be partial weeks due to hiddenDays
1181
+ internal_cjs.diffWeeks(lastMonthRenderStart, end));
1182
+ end = internal_cjs.addWeeks(end, 6 - rowCnt);
1180
1183
  }
1184
+ return { start, end };
1181
1185
  }
1182
1186
 
1183
- exports.COMPACT_CELL_WIDTH = COMPACT_CELL_WIDTH;
1184
- exports.DateHeaderCell = DateHeaderCell;
1187
+ 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}";
1188
+ internal_cjs.injectStyles(css_248z);
1189
+
1190
+ exports.DayGridHeaderRow = DayGridHeaderRow;
1185
1191
  exports.DayGridLayout = DayGridLayout;
1186
1192
  exports.DayGridRow = DayGridRow;
1187
1193
  exports.DayGridRows = DayGridRows;
1188
1194
  exports.DayGridView = DayGridView;
1189
- exports.DayOfWeekHeaderCell = DayOfWeekHeaderCell;
1190
1195
  exports.DayTableSlicer = DayTableSlicer;
1191
- exports.HeaderRow = HeaderRow;
1192
- exports.HeaderRowAdvanced = HeaderRowAdvanced;
1193
1196
  exports.TableDateProfileGenerator = TableDateProfileGenerator;
1197
+ exports.buildDateDataConfigs = buildDateDataConfigs;
1198
+ exports.buildDateRenderConfig = buildDateRenderConfig;
1199
+ exports.buildDateRowConfig = buildDateRowConfig;
1200
+ exports.buildDateRowConfigs = buildDateRowConfigs;
1194
1201
  exports.buildDayTableModel = buildDayTableModel;
1195
1202
  exports.buildDayTableRenderRange = buildDayTableRenderRange;
1196
1203
  exports.computeColFromPosition = computeColFromPosition;
1197
1204
  exports.computeColWidth = computeColWidth;
1205
+ exports.computeRowHeight = computeRowHeight;
1198
1206
  exports.createDayHeaderFormatter = createDayHeaderFormatter;
1199
1207
  exports.getCellEl = getCellEl;
1200
1208
  exports.getRowEl = getRowEl;