@fullcalendar/daygrid 6.1.14 → 7.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/internal.cjs CHANGED
@@ -5,128 +5,251 @@ 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
- /* An abstract class for the daygrid views, as well as month view. Renders one or more rows of day cells.
9
- ----------------------------------------------------------------------------------------------------------------------*/
10
- // It is a manager for a Table subcomponent, which does most of the heavy lifting.
11
- // It is responsible for managing width/height.
12
- class TableView extends internal_cjs.DateComponent {
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
+ class DayTableSlicer extends internal_cjs.Slicer {
13
12
  constructor() {
14
13
  super(...arguments);
15
- this.headerElRef = preact_cjs.createRef();
14
+ this.forceDayIfListItem = true;
16
15
  }
17
- renderSimpleLayout(headerRowContent, bodyContent) {
18
- let { props, context } = this;
19
- let sections = [];
20
- let stickyHeaderDates = internal_cjs.getStickyHeaderDates(context.options);
21
- if (headerRowContent) {
22
- sections.push({
23
- type: 'header',
24
- key: 'header',
25
- isSticky: stickyHeaderDates,
26
- chunk: {
27
- elRef: this.headerElRef,
28
- tableClassName: 'fc-col-header',
29
- rowContent: headerRowContent,
30
- },
31
- });
32
- }
33
- sections.push({
34
- type: 'body',
35
- key: 'body',
36
- liquid: true,
37
- chunk: { content: bodyContent },
16
+ sliceRange(dateRange, dayTableModel) {
17
+ return dayTableModel.sliceRange(dateRange);
18
+ }
19
+ }
20
+
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,
38
31
  });
39
- return (preact_cjs.createElement(internal_cjs.ViewContainer, { elClasses: ['fc-daygrid'], viewSpec: context.viewSpec },
40
- preact_cjs.createElement(internal_cjs.SimpleScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: props.forPrint, cols: [] /* TODO: make optional? */, sections: sections })));
41
32
  }
42
- renderHScrollLayout(headerRowContent, bodyContent, colCnt, dayMinWidth) {
43
- let ScrollGrid = this.context.pluginHooks.scrollGridImpl;
44
- if (!ScrollGrid) {
45
- throw new Error('No ScrollGrid implementation');
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);
46
45
  }
47
- let { props, context } = this;
48
- let stickyHeaderDates = !props.forPrint && internal_cjs.getStickyHeaderDates(context.options);
49
- let stickyFooterScrollbar = !props.forPrint && internal_cjs.getStickyFooterScrollbar(context.options);
50
- let sections = [];
51
- if (headerRowContent) {
52
- sections.push({
53
- type: 'header',
54
- key: 'header',
55
- isSticky: stickyHeaderDates,
56
- chunks: [{
57
- key: 'main',
58
- elRef: this.headerElRef,
59
- tableClassName: 'fc-col-header',
60
- rowContent: headerRowContent,
61
- }],
62
- });
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
84
+ // -------------------------------------------------------------------------------------------------
85
+ function computeTopFromDate(date, cellRows, rowHeightMap) {
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;
63
93
  }
64
- sections.push({
65
- type: 'body',
66
- key: 'body',
67
- liquid: true,
68
- chunks: [{
69
- key: 'main',
70
- content: bodyContent,
71
- }],
72
- });
73
- if (stickyFooterScrollbar) {
74
- sections.push({
75
- type: 'footer',
76
- key: 'footer',
77
- isSticky: true,
78
- chunks: [{
79
- key: 'main',
80
- content: internal_cjs.renderScrollShim,
81
- }],
82
- });
94
+ const rowHeight = rowHeightMap.get(key);
95
+ if (rowHeight == null) {
96
+ return; // denote unknown
97
+ }
98
+ top += rowHeight;
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);
83
123
  }
84
- return (preact_cjs.createElement(internal_cjs.ViewContainer, { elClasses: ['fc-daygrid'], viewSpec: context.viewSpec },
85
- preact_cjs.createElement(ScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, forPrint: props.forPrint, collapsibleWidth: props.forPrint, colGroups: [{ cols: [{ span: colCnt, minWidth: dayMinWidth }] }], sections: sections })));
86
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 };
149
+ }
150
+ // Hit Element
151
+ // -------------------------------------------------------------------------------------------------
152
+ function getRowEl(rootEl, row) {
153
+ return rootEl.querySelectorAll(':scope > [role=row]')[row];
154
+ }
155
+ function getCellEl(rowEl, col) {
156
+ return rowEl.querySelectorAll(':scope > [role=gridcell]')[col];
87
157
  }
88
158
 
89
- function splitSegsByRow(segs, rowCnt) {
90
- let byRow = [];
91
- for (let i = 0; i < rowCnt; i += 1) {
92
- byRow[i] = [];
159
+ class DateHeaderCell extends internal_cjs.BaseComponent {
160
+ constructor() {
161
+ super(...arguments);
162
+ // ref
163
+ this.innerElRef = preact_cjs.createRef();
93
164
  }
94
- for (let seg of segs) {
95
- byRow[seg.row].push(seg);
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);
200
+ });
201
+ }
202
+ componentWillUnmount() {
203
+ this.disconectInnerHeight();
96
204
  }
97
- return byRow;
98
205
  }
99
- function splitSegsByFirstCol(segs, colCnt) {
100
- let byCol = [];
101
- for (let i = 0; i < colCnt; i += 1) {
102
- byCol[i] = [];
206
+
207
+ function splitSegsByRow(segs, rowCnt) {
208
+ const byRow = [];
209
+ for (let row = 0; row < rowCnt; row++) {
210
+ byRow[row] = [];
103
211
  }
104
- for (let seg of segs) {
105
- byCol[seg.firstCol].push(seg);
212
+ for (const seg of segs) {
213
+ byRow[seg.row].push(seg);
106
214
  }
107
- return byCol;
215
+ return byRow;
108
216
  }
109
217
  function splitInteractionByRow(ui, rowCnt) {
110
- let byRow = [];
218
+ const byRow = [];
111
219
  if (!ui) {
112
- for (let i = 0; i < rowCnt; i += 1) {
113
- byRow[i] = null;
220
+ for (let row = 0; row < rowCnt; row++) {
221
+ byRow[row] = null;
114
222
  }
115
223
  }
116
224
  else {
117
- for (let i = 0; i < rowCnt; i += 1) {
118
- byRow[i] = {
225
+ for (let row = 0; row < rowCnt; row++) {
226
+ byRow[row] = {
119
227
  affectedInstances: ui.affectedInstances,
120
228
  isEvent: ui.isEvent,
121
229
  segs: [],
122
230
  };
123
231
  }
124
- for (let seg of ui.segs) {
232
+ for (const seg of ui.segs) {
125
233
  byRow[seg.row].segs.push(seg);
126
234
  }
127
235
  }
128
236
  return byRow;
129
237
  }
238
+ function splitSegsByCol(segs, colCnt) {
239
+ let byCol = [];
240
+ for (let col = 0; col < colCnt; col++) {
241
+ byCol.push([]);
242
+ }
243
+ for (let seg of segs) {
244
+ for (let col = seg.firstCol; col <= seg.lastCol; col++) {
245
+ if (seg.firstCol !== col) {
246
+ seg = Object.assign(Object.assign({}, seg), { firstCol: col, lastCol: col, isStart: false, isEnd: seg.isEnd && seg.lastCol === col, isStandin: true });
247
+ }
248
+ byCol[col].push(seg);
249
+ }
250
+ }
251
+ return byCol;
252
+ }
130
253
 
131
254
  const DEFAULT_TABLE_EVENT_TIME_FORMAT = internal_cjs.createFormatter({
132
255
  hour: 'numeric',
@@ -144,14 +267,14 @@ function hasListItemDisplay(seg) {
144
267
  );
145
268
  }
146
269
 
147
- class TableBlockEvent extends internal_cjs.BaseComponent {
270
+ class DayGridBlockEvent extends internal_cjs.BaseComponent {
148
271
  render() {
149
272
  let { props } = this;
150
273
  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.seg.eventRange.def.allDay })));
151
274
  }
152
275
  }
153
276
 
154
- class TableListItemEvent extends internal_cjs.BaseComponent {
277
+ class DayGridListEvent extends internal_cjs.BaseComponent {
155
278
  render() {
156
279
  let { props, context } = this;
157
280
  let { options } = context;
@@ -168,80 +291,83 @@ function renderInnerContent(renderProps) {
168
291
  preact_cjs.createElement("div", { className: "fc-event-title" }, renderProps.event.title || preact_cjs.createElement(preact_cjs.Fragment, null, "\u00A0"))));
169
292
  }
170
293
 
171
- class TableCellMoreLink extends internal_cjs.BaseComponent {
172
- constructor() {
173
- super(...arguments);
174
- this.compileSegs = internal_cjs.memoize(compileSegs);
175
- }
294
+ class DayGridMoreLink extends internal_cjs.BaseComponent {
176
295
  render() {
177
296
  let { props } = this;
178
- let { allSegs, invisibleSegs } = this.compileSegs(props.singlePlacements);
179
- return (preact_cjs.createElement(internal_cjs.MoreLinkContainer, { elClasses: ['fc-daygrid-more-link'], dateProfile: props.dateProfile, todayRange: props.todayRange, allDayDate: props.allDayDate, moreCnt: props.moreCnt, allSegs: allSegs, hiddenSegs: invisibleSegs, alignmentElRef: props.alignmentElRef, alignGridTop: props.alignGridTop, extraDateSpan: props.extraDateSpan, popoverContent: () => {
180
- let isForcedInvisible = (props.eventDrag ? props.eventDrag.affectedInstances : null) ||
297
+ 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: () => {
298
+ let forcedInvisibleMap = // TODO: more convenient/DRY
299
+ (props.eventDrag ? props.eventDrag.affectedInstances : null) ||
181
300
  (props.eventResize ? props.eventResize.affectedInstances : null) ||
182
301
  {};
183
- return (preact_cjs.createElement(preact_cjs.Fragment, null, allSegs.map((seg) => {
302
+ return (preact_cjs.createElement(preact_cjs.Fragment, null, props.segs.map((seg) => {
184
303
  let instanceId = seg.eventRange.instance.instanceId;
185
- return (preact_cjs.createElement("div", { className: "fc-daygrid-event-harness", key: instanceId, style: {
186
- visibility: isForcedInvisible[instanceId] ? 'hidden' : '',
187
- } }, hasListItemDisplay(seg) ? (preact_cjs.createElement(TableListItemEvent, Object.assign({ seg: seg, isDragging: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, internal_cjs.getSegMeta(seg, props.todayRange)))) : (preact_cjs.createElement(TableBlockEvent, Object.assign({ seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, internal_cjs.getSegMeta(seg, props.todayRange))))));
304
+ return (preact_cjs.createElement("div", { key: instanceId, style: {
305
+ visibility: forcedInvisibleMap[instanceId] ? 'hidden' : '',
306
+ } }, hasListItemDisplay(seg) ? (preact_cjs.createElement(DayGridListEvent, Object.assign({ seg: seg, isDragging: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, internal_cjs.getSegMeta(seg, props.todayRange)))) : (preact_cjs.createElement(DayGridBlockEvent, Object.assign({ seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, internal_cjs.getSegMeta(seg, props.todayRange))))));
188
307
  })));
189
308
  } }));
190
309
  }
191
310
  }
192
- function compileSegs(singlePlacements) {
193
- let allSegs = [];
194
- let invisibleSegs = [];
195
- for (let placement of singlePlacements) {
196
- allSegs.push(placement.seg);
197
- if (!placement.isVisible) {
198
- invisibleSegs.push(placement.seg);
199
- }
200
- }
201
- return { allSegs, invisibleSegs };
202
- }
203
311
 
204
- const DEFAULT_WEEK_NUM_FORMAT = internal_cjs.createFormatter({ week: 'narrow' });
205
- class TableCell extends internal_cjs.DateComponent {
312
+ class DayGridCell extends internal_cjs.DateComponent {
206
313
  constructor() {
207
314
  super(...arguments);
208
- this.rootElRef = preact_cjs.createRef();
209
- this.state = {
210
- dayNumberId: internal_cjs.getUniqueDomId(),
211
- };
212
- this.handleRootEl = (el) => {
213
- internal_cjs.setRef(this.rootElRef, el);
214
- internal_cjs.setRef(this.props.elRef, el);
215
- };
315
+ // ref
316
+ this.innerElRef = preact_cjs.createRef();
317
+ this.headerWrapElRef = preact_cjs.createRef();
216
318
  }
217
319
  render() {
218
- let { context, props, state, rootElRef } = this;
320
+ let { props, context } = this;
219
321
  let { options, dateEnv } = context;
220
- let { date, dateProfile } = props;
221
- // TODO: memoize this?
322
+ // TODO: memoize this
222
323
  const isMonthStart = props.showDayNumber &&
223
- shouldDisplayMonthStart(date, dateProfile.currentRange, dateEnv);
224
- return (preact_cjs.createElement(internal_cjs.DayCellContainer, { elTag: "td", elRef: this.handleRootEl, elClasses: [
225
- 'fc-daygrid-day',
324
+ shouldDisplayMonthStart(props.date, props.dateProfile.currentRange, dateEnv);
325
+ return (preact_cjs.createElement(internal_cjs.DayCellContainer, { elTag: "div", elClasses: [
326
+ 'fc-daygrid-cell',
327
+ 'fc-cell',
328
+ props.width != null ? '' : 'fc-liquid',
329
+ 'fc-flex-column',
226
330
  ...(props.extraClassNames || []),
227
- ], elAttrs: Object.assign(Object.assign(Object.assign({}, props.extraDataAttrs), (props.showDayNumber ? { 'aria-labelledby': state.dayNumberId } : {})), { role: 'gridcell' }), defaultGenerator: renderTopInner, date: date, dateProfile: dateProfile, todayRange: props.todayRange, showDayNumber: props.showDayNumber, isMonthStart: isMonthStart, extraRenderProps: props.extraRenderProps }, (InnerContent, renderProps) => (preact_cjs.createElement("div", { ref: props.innerElRef, className: "fc-daygrid-day-frame fc-scrollgrid-sync-inner", style: { minHeight: props.minHeight } },
228
- props.showWeekNumber && (preact_cjs.createElement(internal_cjs.WeekNumberContainer, { elTag: "a", elClasses: ['fc-daygrid-week-number'], elAttrs: internal_cjs.buildNavLinkAttrs(context, date, 'week'), date: date, defaultFormat: DEFAULT_WEEK_NUM_FORMAT })),
229
- !renderProps.isDisabled &&
230
- (props.showDayNumber || internal_cjs.hasCustomDayCellContent(options) || props.forceDayTop) ? (preact_cjs.createElement("div", { className: "fc-daygrid-day-top" },
331
+ ], elAttrs: Object.assign(Object.assign({}, props.extraDataAttrs), { role: 'gridcell' }), elStyle: {
332
+ width: props.width
333
+ }, 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: [
334
+ 'fc-daygrid-cell-inner',
335
+ props.fgLiquidHeight ? 'fc-liquid' : ''
336
+ ].join(' ') },
337
+ 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" },
231
338
  preact_cjs.createElement(InnerContent, { elTag: "a", elClasses: [
232
- 'fc-daygrid-day-number',
339
+ 'fc-daygrid-cell-number',
233
340
  isMonthStart && 'fc-daygrid-month-start',
234
- ], elAttrs: Object.assign(Object.assign({}, internal_cjs.buildNavLinkAttrs(context, date)), { id: state.dayNumberId }) }))) : props.showDayNumber ? (
235
- // for creating correct amount of space (see issue #7162)
236
- preact_cjs.createElement("div", { className: "fc-daygrid-day-top", style: { visibility: 'hidden' } },
237
- preact_cjs.createElement("a", { className: "fc-daygrid-day-number" }, "\u00A0"))) : undefined,
238
- preact_cjs.createElement("div", { className: "fc-daygrid-day-events", ref: props.fgContentElRef },
239
- props.fgContent,
240
- preact_cjs.createElement("div", { className: "fc-daygrid-day-bottom", style: { marginTop: props.moreMarginTop } },
241
- preact_cjs.createElement(TableCellMoreLink, { allDayDate: date, singlePlacements: props.singlePlacements, moreCnt: props.moreCnt, alignmentElRef: rootElRef, alignGridTop: !props.showDayNumber, extraDateSpan: props.extraDateSpan, dateProfile: props.dateProfile, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, todayRange: props.todayRange }))),
242
- preact_cjs.createElement("div", { className: "fc-daygrid-day-bg" }, props.bgContent)))));
341
+ ], elAttrs: internal_cjs.buildNavLinkAttrs(context, props.date) })))),
342
+ preact_cjs.createElement("div", { className: "fc-daygrid-cell-main", style: {
343
+ height: props.fgLiquidHeight ? '' : props.fgHeight
344
+ } }, props.fg),
345
+ preact_cjs.createElement("div", { className: "fc-daygrid-cell-footer", style: props.fgLiquidHeight
346
+ ? { position: 'relative', top: props.fgHeight }
347
+ : {} },
348
+ 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 })),
349
+ props.bg))));
350
+ }
351
+ componentDidMount() {
352
+ const innerEl = this.innerElRef.current; // TODO: make dynamic with useEffect
353
+ const headerWrapEl = this.headerWrapElRef.current; // "
354
+ // TODO: only attach this if refs props present
355
+ this.detachInnerHeight = internal_cjs.watchHeight(innerEl, (height) => {
356
+ internal_cjs.setRef(this.props.innerHeightRef, height);
357
+ });
358
+ this.detachHeaderHeight = internal_cjs.watchHeight(headerWrapEl, (height) => {
359
+ internal_cjs.setRef(this.props.headerHeightRef, height);
360
+ });
361
+ }
362
+ componentWillUnmount() {
363
+ this.detachInnerHeight();
364
+ this.detachHeaderHeight();
365
+ internal_cjs.setRef(this.props.innerHeightRef, null);
366
+ internal_cjs.setRef(this.props.headerHeightRef, null);
243
367
  }
244
368
  }
369
+ // Utils
370
+ // -------------------------------------------------------------------------------------------------
245
371
  function renderTopInner(props) {
246
372
  return props.dayNumberText || preact_cjs.createElement(preact_cjs.Fragment, null, "\u00A0");
247
373
  }
@@ -261,26 +387,43 @@ function shouldDisplayMonthStart(date, currentRange, dateEnv) {
261
387
  (dateEnv.getDay(date) === 1 && date.valueOf() < currentEnd.valueOf()));
262
388
  }
263
389
 
264
- function generateSegKey(seg) {
390
+ /*
391
+ Unique per-START-column, good for cataloging by top
392
+ */
393
+ function getSegStartId(seg) {
265
394
  return seg.eventRange.instance.instanceId + ':' + seg.firstCol;
266
395
  }
267
- function generateSegUid(seg) {
268
- return generateSegKey(seg) + ':' + seg.lastCol;
269
- }
270
- function computeFgSegPlacement(segs, // assumed already sorted
271
- dayMaxEvents, dayMaxEventRows, strictOrder, segHeights, maxContentHeight, cells) {
272
- let hierarchy = new DayGridSegHierarchy((segEntry) => {
273
- // TODO: more DRY with generateSegUid
274
- let segUid = segs[segEntry.index].eventRange.instance.instanceId +
275
- ':' + segEntry.span.start +
276
- ':' + (segEntry.span.end - 1);
277
- // if no thickness known, assume 1 (if 0, so small it always fits)
278
- return segHeights[segUid] || 1;
279
- });
280
- hierarchy.allowReslicing = true;
396
+ /*
397
+ Unique per-START-and-END-column, good for cataloging by width/height
398
+ */
399
+ function getSegSpanId(seg) {
400
+ return getSegStartId(seg) + ':' + seg.lastCol;
401
+ }
402
+ function computeFgSegVerticals(segs, segHeightMap, // keyed by segSpanId
403
+ cells, topOrigin, maxHeight, strictOrder, dayMaxEvents, dayMaxEventRows) {
404
+ // initialize column-based arrays
405
+ const colCnt = cells.length;
406
+ const hiddenSegsByCol = [];
407
+ const heightsByCol = [];
408
+ for (let col = 0; col < colCnt; col++) {
409
+ hiddenSegsByCol.push([]);
410
+ heightsByCol.push(0);
411
+ }
412
+ // create entries to be given to DayGridSegHierarchy
413
+ const segEntries = segs.map((seg, index) => ({
414
+ index: index,
415
+ seg,
416
+ span: {
417
+ start: seg.firstCol,
418
+ end: seg.lastCol + 1,
419
+ },
420
+ }));
421
+ // configure hierarchy position-generator
422
+ let hierarchy = new DayGridSegHierarchy((segEntry) => (segHeightMap.get(getSegSpanId(segs[segEntry.index]))));
423
+ hierarchy.allowReslicing = false;
281
424
  hierarchy.strictOrder = strictOrder;
282
425
  if (dayMaxEvents === true || dayMaxEventRows === true) {
283
- hierarchy.maxCoord = maxContentHeight;
426
+ hierarchy.maxCoord = maxHeight;
284
427
  hierarchy.hiddenConsumes = true;
285
428
  }
286
429
  else if (typeof dayMaxEvents === 'number') {
@@ -290,172 +433,30 @@ dayMaxEvents, dayMaxEventRows, strictOrder, segHeights, maxContentHeight, cells)
290
433
  hierarchy.maxStackCnt = dayMaxEventRows;
291
434
  hierarchy.hiddenConsumes = true;
292
435
  }
293
- // create segInputs only for segs with known heights
294
- let segInputs = [];
295
- let unknownHeightSegs = [];
296
- for (let i = 0; i < segs.length; i += 1) {
297
- let seg = segs[i];
298
- let segUid = generateSegUid(seg);
299
- let eventHeight = segHeights[segUid];
300
- if (eventHeight != null) {
301
- segInputs.push({
302
- index: i,
303
- span: {
304
- start: seg.firstCol,
305
- end: seg.lastCol + 1,
306
- },
307
- });
308
- }
309
- else {
310
- unknownHeightSegs.push(seg);
311
- }
312
- }
313
- let hiddenEntries = hierarchy.addSegs(segInputs);
314
- let segRects = hierarchy.toRects();
315
- let { singleColPlacements, multiColPlacements, leftoverMargins } = placeRects(segRects, segs, cells);
316
- let moreCnts = [];
317
- let moreMarginTops = [];
318
- // add segs with unknown heights
319
- for (let seg of unknownHeightSegs) {
320
- multiColPlacements[seg.firstCol].push({
321
- seg,
322
- isVisible: false,
323
- isAbsolute: true,
324
- absoluteTop: 0,
325
- marginTop: 0,
326
- });
327
- for (let col = seg.firstCol; col <= seg.lastCol; col += 1) {
328
- singleColPlacements[col].push({
329
- seg: resliceSeg(seg, col, col + 1, cells),
330
- isVisible: false,
331
- isAbsolute: false,
332
- absoluteTop: 0,
333
- marginTop: 0,
334
- });
436
+ // compile segTops & heightsByCol
437
+ const hiddenSegEntries = hierarchy.addSegs(segEntries);
438
+ const segRects = hierarchy.toRects();
439
+ const segTops = {};
440
+ for (const segRect of segRects) {
441
+ const seg = segs[segRect.index];
442
+ segTops[getSegStartId(seg)] = topOrigin + segRect.levelCoord;
443
+ let { start: col, end: endCol } = segRect.span;
444
+ for (; col < endCol; col++) {
445
+ heightsByCol[col] = Math.max(heightsByCol[col], segRect.levelCoord + segRect.thickness);
335
446
  }
336
447
  }
337
- // add the hidden entries
338
- for (let col = 0; col < cells.length; col += 1) {
339
- moreCnts.push(0);
340
- }
341
- for (let hiddenEntry of hiddenEntries) {
342
- let seg = segs[hiddenEntry.index];
343
- let hiddenSpan = hiddenEntry.span;
344
- multiColPlacements[hiddenSpan.start].push({
345
- seg: resliceSeg(seg, hiddenSpan.start, hiddenSpan.end, cells),
346
- isVisible: false,
347
- isAbsolute: true,
348
- absoluteTop: 0,
349
- marginTop: 0,
350
- });
351
- for (let col = hiddenSpan.start; col < hiddenSpan.end; col += 1) {
352
- moreCnts[col] += 1;
353
- singleColPlacements[col].push({
354
- seg: resliceSeg(seg, col, col + 1, cells),
355
- isVisible: false,
356
- isAbsolute: false,
357
- absoluteTop: 0,
358
- marginTop: 0,
359
- });
448
+ // compile # of invisible segs per-column
449
+ for (const hiddenSegEntry of hiddenSegEntries) {
450
+ const { span } = hiddenSegEntry;
451
+ const hiddenSeg = segs[hiddenSegEntry.index];
452
+ for (let col = span.start; col < span.end; col++) {
453
+ hiddenSegsByCol[col].push(hiddenSeg);
360
454
  }
361
455
  }
362
- // deal with leftover margins
363
- for (let col = 0; col < cells.length; col += 1) {
364
- moreMarginTops.push(leftoverMargins[col]);
365
- }
366
- return { singleColPlacements, multiColPlacements, moreCnts, moreMarginTops };
367
- }
368
- // rects ordered by top coord, then left
369
- function placeRects(allRects, segs, cells) {
370
- let rectsByEachCol = groupRectsByEachCol(allRects, cells.length);
371
- let singleColPlacements = [];
372
- let multiColPlacements = [];
373
- let leftoverMargins = [];
374
- for (let col = 0; col < cells.length; col += 1) {
375
- let rects = rectsByEachCol[col];
376
- // compute all static segs in singlePlacements
377
- let singlePlacements = [];
378
- let currentHeight = 0;
379
- let currentMarginTop = 0;
380
- for (let rect of rects) {
381
- let seg = segs[rect.index];
382
- singlePlacements.push({
383
- seg: resliceSeg(seg, col, col + 1, cells),
384
- isVisible: true,
385
- isAbsolute: false,
386
- absoluteTop: rect.levelCoord,
387
- marginTop: rect.levelCoord - currentHeight,
388
- });
389
- currentHeight = rect.levelCoord + rect.thickness;
390
- }
391
- // compute mixed static/absolute segs in multiPlacements
392
- let multiPlacements = [];
393
- currentHeight = 0;
394
- currentMarginTop = 0;
395
- for (let rect of rects) {
396
- let seg = segs[rect.index];
397
- let isAbsolute = rect.span.end - rect.span.start > 1; // multi-column?
398
- let isFirstCol = rect.span.start === col;
399
- currentMarginTop += rect.levelCoord - currentHeight; // amount of space since bottom of previous seg
400
- currentHeight = rect.levelCoord + rect.thickness; // height will now be bottom of current seg
401
- if (isAbsolute) {
402
- currentMarginTop += rect.thickness;
403
- if (isFirstCol) {
404
- multiPlacements.push({
405
- seg: resliceSeg(seg, rect.span.start, rect.span.end, cells),
406
- isVisible: true,
407
- isAbsolute: true,
408
- absoluteTop: rect.levelCoord,
409
- marginTop: 0,
410
- });
411
- }
412
- }
413
- else if (isFirstCol) {
414
- multiPlacements.push({
415
- seg: resliceSeg(seg, rect.span.start, rect.span.end, cells),
416
- isVisible: true,
417
- isAbsolute: false,
418
- absoluteTop: rect.levelCoord,
419
- marginTop: currentMarginTop, // claim the margin
420
- });
421
- currentMarginTop = 0;
422
- }
423
- }
424
- singleColPlacements.push(singlePlacements);
425
- multiColPlacements.push(multiPlacements);
426
- leftoverMargins.push(currentMarginTop);
427
- }
428
- return { singleColPlacements, multiColPlacements, leftoverMargins };
429
- }
430
- function groupRectsByEachCol(rects, colCnt) {
431
- let rectsByEachCol = [];
432
- for (let col = 0; col < colCnt; col += 1) {
433
- rectsByEachCol.push([]);
434
- }
435
- for (let rect of rects) {
436
- for (let col = rect.span.start; col < rect.span.end; col += 1) {
437
- rectsByEachCol[col].push(rect);
438
- }
439
- }
440
- return rectsByEachCol;
441
- }
442
- function resliceSeg(seg, spanStart, spanEnd, cells) {
443
- if (seg.firstCol === spanStart && seg.lastCol === spanEnd - 1) {
444
- return seg;
445
- }
446
- let eventRange = seg.eventRange;
447
- let origRange = eventRange.range;
448
- let slicedRange = internal_cjs.intersectRanges(origRange, {
449
- start: cells[spanStart].date,
450
- end: internal_cjs.addDays(cells[spanEnd - 1].date, 1),
451
- });
452
- return Object.assign(Object.assign({}, seg), { firstCol: spanStart, lastCol: spanEnd - 1, eventRange: {
453
- def: eventRange.def,
454
- ui: Object.assign(Object.assign({}, eventRange.ui), { durationEditable: false }),
455
- instance: eventRange.instance,
456
- range: slicedRange,
457
- }, isStart: seg.isStart && slicedRange.start.valueOf() === origRange.start.valueOf(), isEnd: seg.isEnd && slicedRange.end.valueOf() === origRange.end.valueOf() });
456
+ return [segTops, heightsByCol, hiddenSegsByCol];
458
457
  }
458
+ // DayGridSegHierarchy
459
+ // -------------------------------------------------------------------------------------------------
459
460
  class DayGridSegHierarchy extends internal_cjs.SegHierarchy {
460
461
  constructor() {
461
462
  super(...arguments);
@@ -503,74 +504,205 @@ class DayGridSegHierarchy extends internal_cjs.SegHierarchy {
503
504
  }
504
505
  }
505
506
 
506
- class TableRow extends internal_cjs.DateComponent {
507
+ class DayGridEventHarness extends preact_cjs.Component {
507
508
  constructor() {
508
509
  super(...arguments);
509
- this.cellElRefs = new internal_cjs.RefMap(); // the <td>
510
- this.frameElRefs = new internal_cjs.RefMap(); // the fc-daygrid-day-frame
511
- this.fgElRefs = new internal_cjs.RefMap(); // the fc-daygrid-day-events
512
- this.segHarnessRefs = new internal_cjs.RefMap(); // indexed by "instanceId:firstCol"
510
+ // ref
513
511
  this.rootElRef = preact_cjs.createRef();
514
- this.state = {
515
- framePositions: null,
516
- maxContentHeight: null,
517
- segHeights: {},
512
+ }
513
+ render() {
514
+ const { props } = this;
515
+ return (preact_cjs.createElement("div", { className: "fc-abs", style: props.style, ref: this.rootElRef }, props.children));
516
+ }
517
+ componentDidMount() {
518
+ const rootEl = this.rootElRef.current; // TODO: make dynamic with useEffect
519
+ this.detachHeight = internal_cjs.watchHeight(rootEl, (height) => {
520
+ internal_cjs.setRef(this.props.heightRef, height);
521
+ });
522
+ }
523
+ componentWillUnmount() {
524
+ this.detachHeight();
525
+ }
526
+ }
527
+
528
+ const DEFAULT_WEEK_NUM_FORMAT = internal_cjs.createFormatter({ week: 'narrow' });
529
+ const COMPACT_CELL_WIDTH = 80;
530
+ class DayGridRow extends internal_cjs.BaseComponent {
531
+ constructor() {
532
+ super(...arguments);
533
+ this.cellInnerHeightRefMap = new internal_cjs.RefMap(() => {
534
+ internal_cjs.afterSize(this.handleInnerHeights);
535
+ });
536
+ this.cellHeaderHeightRefMap = new internal_cjs.RefMap(() => {
537
+ internal_cjs.afterSize(this.handleHeaderHeights);
538
+ });
539
+ this.segHeightRefMap = new internal_cjs.RefMap(() => {
540
+ internal_cjs.afterSize(this.handleSegHeights);
541
+ });
542
+ this.handleRootEl = (rootEl) => {
543
+ this.rootEl = rootEl;
544
+ internal_cjs.setRef(this.props.rootElRef, rootEl);
545
+ };
546
+ // Sizing
547
+ // -----------------------------------------------------------------------------------------------
548
+ this.handleHeaderHeights = () => {
549
+ const cellHeaderHeightMap = this.cellHeaderHeightRefMap.current;
550
+ let max = 0;
551
+ for (const height of cellHeaderHeightMap.values()) {
552
+ max = Math.max(max, height);
553
+ }
554
+ if (this.state.headerHeight !== max) {
555
+ this.setState({ headerHeight: max });
556
+ }
518
557
  };
519
- this.handleResize = (isForced) => {
520
- if (isForced) {
521
- this.updateSizing(true); // isExternal=true
558
+ this.handleInnerHeights = () => {
559
+ const { props } = this;
560
+ const fgLiquidHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;
561
+ const cellInnerHeightMap = this.cellInnerHeightRefMap.current;
562
+ let max = 0;
563
+ for (const height of cellInnerHeightMap.values()) {
564
+ max = Math.max(max, height);
565
+ }
566
+ if (fgLiquidHeight) {
567
+ if (this.state.innerHeight !== max) {
568
+ this.setState({ innerHeight: max }); // will trigger event rerender
569
+ }
570
+ }
571
+ else {
572
+ internal_cjs.setRef(props.innerHeightRef, max);
522
573
  }
523
574
  };
575
+ this.handleSegHeights = () => {
576
+ this.setState({ segHeightRev: this.segHeightRefMap.rev }); // will trigger event rerender
577
+ };
524
578
  }
525
579
  render() {
526
- let { props, state, context } = this;
527
- let { options } = context;
528
- let colCnt = props.cells.length;
529
- let businessHoursByCol = splitSegsByFirstCol(props.businessHourSegs, colCnt);
530
- let bgEventSegsByCol = splitSegsByFirstCol(props.bgEventSegs, colCnt);
531
- let highlightSegsByCol = splitSegsByFirstCol(this.getHighlightSegs(), colCnt);
532
- let mirrorSegsByCol = splitSegsByFirstCol(this.getMirrorSegs(), colCnt);
533
- let { singleColPlacements, multiColPlacements, moreCnts, moreMarginTops } = computeFgSegPlacement(internal_cjs.sortEventSegs(props.fgEventSegs, options.eventOrder), props.dayMaxEvents, props.dayMaxEventRows, options.eventOrderStrict, state.segHeights, state.maxContentHeight, props.cells);
534
- let isForcedInvisible = // TODO: messy way to compute this
580
+ const { props, state, context, cellInnerHeightRefMap, cellHeaderHeightRefMap } = this;
581
+ const { cells } = props;
582
+ const { options } = context;
583
+ const weekDate = props.cells[0].date;
584
+ const colCnt = props.cells.length;
585
+ const fgLiquidHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;
586
+ // TODO: memoize? sort all types of segs?
587
+ const fgEventSegs = internal_cjs.sortEventSegs(props.fgEventSegs, options.eventOrder);
588
+ // TODO: memoize?
589
+ const fgEventSegsByCol = splitSegsByCol(fgEventSegs, colCnt);
590
+ const bgEventSegsByCol = splitSegsByCol(props.bgEventSegs, colCnt);
591
+ const businessHoursByCol = splitSegsByCol(props.businessHourSegs, colCnt);
592
+ const highlightSegsByCol = splitSegsByCol(this.getHighlightSegs(), colCnt); // TODO: doesn't need standins
593
+ const mirrorSegsByCol = splitSegsByCol(this.getMirrorSegs(), colCnt); // TODO: doesn't need standins
594
+ // TODO: memoize?
595
+ const [segTops, heightsByCol, hiddenSegsByCol] = computeFgSegVerticals(fgEventSegs, this.segHeightRefMap.current, cells, state.headerHeight, (fgLiquidHeight && state.innerHeight != null && state.headerHeight != null)
596
+ ? state.innerHeight - state.headerHeight
597
+ : undefined, options.eventOrderStrict, props.dayMaxEvents, props.dayMaxEventRows);
598
+ const forcedInvisibleMap = // TODO: more convenient/DRY
535
599
  (props.eventDrag && props.eventDrag.affectedInstances) ||
536
600
  (props.eventResize && props.eventResize.affectedInstances) ||
537
601
  {};
538
- return (preact_cjs.createElement("tr", { ref: this.rootElRef, role: "row" },
539
- props.renderIntro && props.renderIntro(),
602
+ return (preact_cjs.createElement("div", { role: props.cellGroup ? undefined : 'row', className: [
603
+ 'fc-daygrid-row',
604
+ props.forceVSpacing
605
+ ? 'fc-daygrid-row-spacious'
606
+ : props.compact
607
+ ? 'fc-daygrid-row-compact'
608
+ : '',
609
+ props.cellGroup ? 'fc-flex-row' : 'fc-row',
610
+ 'fc-rel',
611
+ props.className || '',
612
+ ].join(' '), style: {
613
+ minHeight: props.minHeight,
614
+ }, ref: this.handleRootEl },
540
615
  props.cells.map((cell, col) => {
541
- let normalFgNodes = this.renderFgSegs(col, props.forPrint ? singleColPlacements[col] : multiColPlacements[col], props.todayRange, isForcedInvisible);
542
- let mirrorFgNodes = this.renderFgSegs(col, buildMirrorPlacements(mirrorSegsByCol[col], multiColPlacements), props.todayRange, {}, Boolean(props.eventDrag), Boolean(props.eventResize), false);
543
- return (preact_cjs.createElement(TableCell, { key: cell.key, elRef: this.cellElRefs.createRef(cell.key), innerElRef: this.frameElRefs.createRef(cell.key) /* FF <td> problem, but okay to use for left/right. TODO: rename prop */, dateProfile: props.dateProfile, date: cell.date, showDayNumber: props.showDayNumbers, showWeekNumber: props.showWeekNumbers && col === 0, forceDayTop: props.showWeekNumbers /* even displaying weeknum for row, not necessarily day */, todayRange: props.todayRange, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, extraRenderProps: cell.extraRenderProps, extraDataAttrs: cell.extraDataAttrs, extraClassNames: cell.extraClassNames, extraDateSpan: cell.extraDateSpan, moreCnt: moreCnts[col], moreMarginTop: moreMarginTops[col], singlePlacements: singleColPlacements[col], fgContentElRef: this.fgElRefs.createRef(cell.key), fgContent: ( // Fragment scopes the keys
544
- preact_cjs.createElement(preact_cjs.Fragment, null,
616
+ const normalFgNodes = this.renderFgSegs(fgEventSegsByCol[col], segTops, props.todayRange, forcedInvisibleMap);
617
+ const mirrorFgNodes = this.renderFgSegs(mirrorSegsByCol[col], segTops, props.todayRange, {}, // forcedInvisibleMap
618
+ Boolean(props.eventDrag), Boolean(props.eventResize), false);
619
+ return (preact_cjs.createElement(DayGridCell, { key: cell.key, dateProfile: props.dateProfile, todayRange: props.todayRange, date: cell.date, showDayNumber: props.showDayNumbers,
620
+ // content
621
+ segs: fgEventSegsByCol[col], hiddenSegs: hiddenSegsByCol[col], fgLiquidHeight: fgLiquidHeight, fg: (preact_cjs.createElement(preact_cjs.Fragment, null,
545
622
  preact_cjs.createElement(preact_cjs.Fragment, null, normalFgNodes),
546
- preact_cjs.createElement(preact_cjs.Fragment, null, mirrorFgNodes))), bgContent: ( // Fragment scopes the keys
547
- preact_cjs.createElement(preact_cjs.Fragment, null,
623
+ preact_cjs.createElement(preact_cjs.Fragment, null, mirrorFgNodes))), bg: (preact_cjs.createElement(preact_cjs.Fragment, null,
548
624
  this.renderFillSegs(highlightSegsByCol[col], 'highlight'),
549
625
  this.renderFillSegs(businessHoursByCol[col], 'non-business'),
550
- this.renderFillSegs(bgEventSegsByCol[col], 'bg-event'))), minHeight: props.cellMinHeight }));
551
- })));
626
+ this.renderFillSegs(bgEventSegsByCol[col], 'bg-event'))), eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
627
+ // render hooks
628
+ extraRenderProps: cell.extraRenderProps, extraDateSpan: cell.extraDateSpan, extraDataAttrs: cell.extraDataAttrs, extraClassNames: cell.extraClassNames,
629
+ // dimensions
630
+ fgHeight: heightsByCol[col], width: props.colWidth,
631
+ // refs
632
+ innerHeightRef: cellInnerHeightRefMap.createRef(cell.key), headerHeightRef: cellHeaderHeightRefMap.createRef(cell.key) }));
633
+ }),
634
+ 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 }))));
635
+ }
636
+ renderFgSegs(segs, segTops, todayRange, forcedInvisibleMap, isDragging, isResizing, isDateSelecting) {
637
+ const { props, context, segHeightRefMap } = this;
638
+ const { isRtl } = context;
639
+ const { colWidth, eventSelection } = props;
640
+ const colCnt = props.cells.length;
641
+ const defaultDisplayEventEnd = props.cells.length === 1;
642
+ const isMirror = isDragging || isResizing || isDateSelecting;
643
+ const nodes = [];
644
+ for (const seg of segs) {
645
+ const { left, right, width } = computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl);
646
+ // TODO: optimize ID creation? all related
647
+ const { instanceId } = seg.eventRange.instance;
648
+ const segSpanId = getSegSpanId(seg);
649
+ const segStartId = getSegStartId(seg);
650
+ const top = segTops[segStartId];
651
+ const isVisible = !seg.isStandin &&
652
+ top != null &&
653
+ !forcedInvisibleMap[instanceId];
654
+ /*
655
+ TODO: is this comment still relevant? vvvvvvvv
656
+ known bug: events that are force to be list-item but span multiple days still take up space in later columns
657
+ todo: in print view, for multi-day events, don't display title within non-start/end segs
658
+ */
659
+ nodes.push(preact_cjs.createElement(DayGridEventHarness, { key: segSpanId, style: {
660
+ visibility: isVisible ? '' : 'hidden',
661
+ top,
662
+ left,
663
+ right,
664
+ width,
665
+ }, heightRef: (isMirror || seg.isStandin)
666
+ ? null
667
+ : segHeightRefMap.createRef(segSpanId) }, hasListItemDisplay(seg) ? (preact_cjs.createElement(DayGridListEvent, Object.assign({ seg: seg, isDragging: isDragging, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, internal_cjs.getSegMeta(seg, todayRange)))) : (preact_cjs.createElement(DayGridBlockEvent, Object.assign({ seg: seg, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, internal_cjs.getSegMeta(seg, todayRange))))));
668
+ }
669
+ return nodes;
552
670
  }
553
- componentDidMount() {
554
- this.updateSizing(true);
555
- this.context.addResizeHandler(this.handleResize);
671
+ renderFillSegs(segs, fillType) {
672
+ const { props, context } = this;
673
+ const { isRtl } = context;
674
+ const { todayRange, colWidth } = props;
675
+ const colCnt = props.cells.length;
676
+ const nodes = [];
677
+ for (const seg of segs) {
678
+ const { left, right, width } = computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl);
679
+ const isVisible = !seg.isStandin;
680
+ nodes.push(preact_cjs.createElement("div", { key: internal_cjs.buildEventRangeKey(seg.eventRange), className: "fc-fill-y", style: {
681
+ visibility: isVisible ? '' : 'hidden',
682
+ left,
683
+ right,
684
+ width,
685
+ } }, fillType === 'bg-event' ?
686
+ preact_cjs.createElement(internal_cjs.BgEvent, Object.assign({ seg: seg }, internal_cjs.getSegMeta(seg, todayRange))) :
687
+ internal_cjs.renderFill(fillType)));
688
+ }
689
+ return preact_cjs.createElement(preact_cjs.Fragment, {}, ...nodes);
556
690
  }
557
- componentDidUpdate(prevProps, prevState) {
558
- let currentProps = this.props;
559
- this.updateSizing(!internal_cjs.isPropsEqual(prevProps, currentProps));
691
+ // Sizing
692
+ // -----------------------------------------------------------------------------------------------
693
+ componentDidMount() {
694
+ const { rootEl } = this; // TODO: make dynamic with useEffect
695
+ this.disconnectHeight = internal_cjs.watchHeight(rootEl, (contentHeight) => {
696
+ internal_cjs.setRef(this.props.heightRef, contentHeight);
697
+ });
560
698
  }
561
699
  componentWillUnmount() {
562
- this.context.removeResizeHandler(this.handleResize);
563
- }
564
- getHighlightSegs() {
565
- let { props } = this;
566
- if (props.eventDrag && props.eventDrag.segs.length) { // messy check
567
- return props.eventDrag.segs;
568
- }
569
- if (props.eventResize && props.eventResize.segs.length) { // messy check
570
- return props.eventResize.segs;
571
- }
572
- return props.dateSelectionSegs;
700
+ this.disconnectHeight();
701
+ internal_cjs.setRef(this.props.heightRef, null);
702
+ internal_cjs.setRef(this.props.innerHeightRef, null);
573
703
  }
704
+ // Utils
705
+ // -----------------------------------------------------------------------------------------------
574
706
  getMirrorSegs() {
575
707
  let { props } = this;
576
708
  if (props.eventResize && props.eventResize.segs.length) { // messy check
@@ -578,420 +710,476 @@ class TableRow extends internal_cjs.DateComponent {
578
710
  }
579
711
  return [];
580
712
  }
581
- renderFgSegs(col, segPlacements, todayRange, isForcedInvisible, isDragging, isResizing, isDateSelecting) {
582
- let { context } = this;
583
- let { eventSelection } = this.props;
584
- let { framePositions } = this.state;
585
- let defaultDisplayEventEnd = this.props.cells.length === 1; // colCnt === 1
586
- let isMirror = isDragging || isResizing || isDateSelecting;
587
- let nodes = [];
588
- if (framePositions) {
589
- for (let placement of segPlacements) {
590
- let { seg } = placement;
591
- let { instanceId } = seg.eventRange.instance;
592
- let isVisible = placement.isVisible && !isForcedInvisible[instanceId];
593
- let isAbsolute = placement.isAbsolute;
594
- let left = '';
595
- let right = '';
596
- if (isAbsolute) {
597
- if (context.isRtl) {
598
- right = 0;
599
- left = framePositions.lefts[seg.lastCol] - framePositions.lefts[seg.firstCol];
600
- }
601
- else {
602
- left = 0;
603
- right = framePositions.rights[seg.firstCol] - framePositions.rights[seg.lastCol];
604
- }
605
- }
606
- /*
607
- known bug: events that are force to be list-item but span multiple days still take up space in later columns
608
- todo: in print view, for multi-day events, don't display title within non-start/end segs
609
- */
610
- nodes.push(preact_cjs.createElement("div", { className: 'fc-daygrid-event-harness' + (isAbsolute ? ' fc-daygrid-event-harness-abs' : ''), key: generateSegKey(seg), ref: isMirror ? null : this.segHarnessRefs.createRef(generateSegUid(seg)), style: {
611
- visibility: isVisible ? '' : 'hidden',
612
- marginTop: isAbsolute ? '' : placement.marginTop,
613
- top: isAbsolute ? placement.absoluteTop : '',
614
- left,
615
- right,
616
- } }, hasListItemDisplay(seg) ? (preact_cjs.createElement(TableListItemEvent, Object.assign({ seg: seg, isDragging: isDragging, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, internal_cjs.getSegMeta(seg, todayRange)))) : (preact_cjs.createElement(TableBlockEvent, Object.assign({ seg: seg, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, internal_cjs.getSegMeta(seg, todayRange))))));
617
- }
618
- }
619
- return nodes;
620
- }
621
- renderFillSegs(segs, fillType) {
622
- let { isRtl } = this.context;
623
- let { todayRange } = this.props;
624
- let { framePositions } = this.state;
625
- let nodes = [];
626
- if (framePositions) {
627
- for (let seg of segs) {
628
- let leftRightCss = isRtl ? {
629
- right: 0,
630
- left: framePositions.lefts[seg.lastCol] - framePositions.lefts[seg.firstCol],
631
- } : {
632
- left: 0,
633
- right: framePositions.rights[seg.firstCol] - framePositions.rights[seg.lastCol],
634
- };
635
- nodes.push(preact_cjs.createElement("div", { key: internal_cjs.buildEventRangeKey(seg.eventRange), className: "fc-daygrid-bg-harness", style: leftRightCss }, fillType === 'bg-event' ?
636
- preact_cjs.createElement(internal_cjs.BgEvent, Object.assign({ seg: seg }, internal_cjs.getSegMeta(seg, todayRange))) :
637
- internal_cjs.renderFill(fillType)));
638
- }
639
- }
640
- return preact_cjs.createElement(preact_cjs.Fragment, {}, ...nodes);
641
- }
642
- updateSizing(isExternalSizingChange) {
643
- let { props, state, frameElRefs } = this;
644
- if (!props.forPrint &&
645
- props.clientWidth !== null // positioning ready?
646
- ) {
647
- if (isExternalSizingChange) {
648
- let frameEls = props.cells.map((cell) => frameElRefs.currentMap[cell.key]);
649
- if (frameEls.length) {
650
- let originEl = this.rootElRef.current;
651
- let newPositionCache = new internal_cjs.PositionCache(originEl, frameEls, true, // isHorizontal
652
- false);
653
- if (!state.framePositions || !state.framePositions.similarTo(newPositionCache)) {
654
- this.setState({
655
- framePositions: new internal_cjs.PositionCache(originEl, frameEls, true, // isHorizontal
656
- false),
657
- });
658
- }
659
- }
660
- }
661
- const oldSegHeights = this.state.segHeights;
662
- const newSegHeights = this.querySegHeights();
663
- const limitByContentHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;
664
- this.safeSetState({
665
- // HACK to prevent oscillations of events being shown/hidden from max-event-rows
666
- // Essentially, once you compute an element's height, never null-out.
667
- // TODO: always display all events, as visibility:hidden?
668
- segHeights: Object.assign(Object.assign({}, oldSegHeights), newSegHeights),
669
- maxContentHeight: limitByContentHeight ? this.computeMaxContentHeight() : null,
670
- });
671
- }
672
- }
673
- querySegHeights() {
674
- let segElMap = this.segHarnessRefs.currentMap;
675
- let segHeights = {};
676
- // get the max height amongst instance segs
677
- for (let segUid in segElMap) {
678
- let height = Math.round(segElMap[segUid].getBoundingClientRect().height);
679
- segHeights[segUid] = Math.max(segHeights[segUid] || 0, height);
713
+ getHighlightSegs() {
714
+ let { props } = this;
715
+ if (props.eventDrag && props.eventDrag.segs.length) { // messy check
716
+ return props.eventDrag.segs;
680
717
  }
681
- return segHeights;
682
- }
683
- computeMaxContentHeight() {
684
- let firstKey = this.props.cells[0].key;
685
- let cellEl = this.cellElRefs.currentMap[firstKey];
686
- let fcContainerEl = this.fgElRefs.currentMap[firstKey];
687
- return cellEl.getBoundingClientRect().bottom - fcContainerEl.getBoundingClientRect().top;
688
- }
689
- getCellEls() {
690
- let elMap = this.cellElRefs.currentMap;
691
- return this.props.cells.map((cell) => elMap[cell.key]);
692
- }
693
- }
694
- TableRow.addStateEquality({
695
- segHeights: internal_cjs.isPropsEqual,
696
- });
697
- function buildMirrorPlacements(mirrorSegs, colPlacements) {
698
- if (!mirrorSegs.length) {
699
- return [];
700
- }
701
- let topsByInstanceId = buildAbsoluteTopHash(colPlacements); // TODO: cache this at first render?
702
- return mirrorSegs.map((seg) => ({
703
- seg,
704
- isVisible: true,
705
- isAbsolute: true,
706
- absoluteTop: topsByInstanceId[seg.eventRange.instance.instanceId],
707
- marginTop: 0,
708
- }));
709
- }
710
- function buildAbsoluteTopHash(colPlacements) {
711
- let topsByInstanceId = {};
712
- for (let placements of colPlacements) {
713
- for (let placement of placements) {
714
- topsByInstanceId[placement.seg.eventRange.instance.instanceId] = placement.absoluteTop;
718
+ if (props.eventResize && props.eventResize.segs.length) { // messy check
719
+ return props.eventResize.segs;
715
720
  }
721
+ return props.dateSelectionSegs;
716
722
  }
717
- return topsByInstanceId;
718
723
  }
719
724
 
720
- class TableRows extends internal_cjs.DateComponent {
725
+ class DayGridRows extends internal_cjs.DateComponent {
721
726
  constructor() {
722
727
  super(...arguments);
728
+ // memo
723
729
  this.splitBusinessHourSegs = internal_cjs.memoize(splitSegsByRow);
724
730
  this.splitBgEventSegs = internal_cjs.memoize(splitSegsByRow);
725
731
  this.splitFgEventSegs = internal_cjs.memoize(splitSegsByRow);
726
732
  this.splitDateSelectionSegs = internal_cjs.memoize(splitSegsByRow);
727
733
  this.splitEventDrag = internal_cjs.memoize(splitInteractionByRow);
728
734
  this.splitEventResize = internal_cjs.memoize(splitInteractionByRow);
729
- this.rowRefs = new internal_cjs.RefMap();
735
+ // internal
736
+ this.rowHeightRefMap = new internal_cjs.RefMap((height, key) => {
737
+ // HACKy way of syncing RefMap results with prop
738
+ const { rowHeightRefMap } = this.props;
739
+ if (rowHeightRefMap) {
740
+ rowHeightRefMap.handleValue(height, key);
741
+ }
742
+ });
743
+ this.handleRootEl = (rootEl) => {
744
+ this.rootEl = rootEl;
745
+ if (rootEl) {
746
+ this.context.registerInteractiveComponent(this, {
747
+ el: rootEl,
748
+ isHitComboAllowed: this.props.isHitComboAllowed,
749
+ });
750
+ }
751
+ else {
752
+ this.context.unregisterInteractiveComponent(this);
753
+ }
754
+ };
730
755
  }
731
756
  render() {
732
- let { props, context } = this;
733
- let rowCnt = props.cells.length;
734
- let businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, rowCnt);
735
- let bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, rowCnt);
757
+ let { props, state, context, rowHeightRefMap } = this;
758
+ let { options } = context;
759
+ let rowCnt = props.cellRows.length;
736
760
  let fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, rowCnt);
761
+ let bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, rowCnt);
762
+ let businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, rowCnt);
737
763
  let dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, rowCnt);
738
764
  let eventDragByRow = this.splitEventDrag(props.eventDrag, rowCnt);
739
765
  let eventResizeByRow = this.splitEventResize(props.eventResize, rowCnt);
740
- // for DayGrid view with many rows, force a min-height on cells so doesn't appear squished
741
- // choose 7 because a month view will have max 6 rows
742
- let cellMinHeight = (rowCnt >= 7 && props.clientWidth) ?
743
- props.clientWidth / context.options.aspectRatio / 6 :
744
- null;
745
- return (preact_cjs.createElement(internal_cjs.NowTimer, { unit: "day" }, (nowDate, todayRange) => (preact_cjs.createElement(preact_cjs.Fragment, null, props.cells.map((cells, row) => (preact_cjs.createElement(TableRow, { ref: this.rowRefs.createRef(row), key: cells.length
746
- ? cells[0].date.toISOString() /* best? or put key on cell? or use diff formatter? */
747
- : row // in case there are no cells (like when resource view is loading)
748
- , showDayNumbers: rowCnt > 1, showWeekNumbers: props.showWeekNumbers, todayRange: todayRange, dateProfile: props.dateProfile, cells: cells, renderIntro: props.renderRowIntro, businessHourSegs: businessHourSegsByRow[row], eventSelection: props.eventSelection, bgEventSegs: bgEventSegsByRow[row].filter(isSegAllDay) /* hack */, fgEventSegs: fgEventSegsByRow[row], dateSelectionSegs: dateSelectionSegsByRow[row], eventDrag: eventDragByRow[row], eventResize: eventResizeByRow[row], dayMaxEvents: props.dayMaxEvents, dayMaxEventRows: props.dayMaxEventRows, clientWidth: props.clientWidth, clientHeight: props.clientHeight, cellMinHeight: cellMinHeight, forPrint: props.forPrint })))))));
766
+ // whether the ROW should expand in height
767
+ // (not to be confused with whether the fg events within the row should be molded by height of row)
768
+ let isHeightAuto = internal_cjs.getIsHeightAuto(options);
769
+ // maintain at least aspectRatio for cells?
770
+ let rowMinHeight = (state.width != null && (rowCnt >= 7 || // TODO: better way to infer if across single-month boundary
771
+ isHeightAuto)) ? state.width / context.options.aspectRatio / 6 // okay to hardcode 6 (weeks) ?
772
+ : null;
773
+ 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,
774
+ // if not auto-height, distribute height of container somewhat evently to rows
775
+ // (treat all as zero, distribute height, then ensure min-heights -- the inner content height)
776
+ className: isHeightAuto ? '' : 'fc-grow fc-basis0',
777
+ // content
778
+ 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,
779
+ // dimensions
780
+ colWidth: props.colWidth, minHeight: rowMinHeight,
781
+ // refs
782
+ heightRef: rowHeightRefMap.createRef(cells[0].key) })))));
749
783
  }
750
784
  componentDidMount() {
751
- this.registerInteractiveComponent();
752
- }
753
- componentDidUpdate() {
754
- // for if started with zero cells
755
- this.registerInteractiveComponent();
756
- }
757
- registerInteractiveComponent() {
758
- if (!this.rootEl) {
759
- // HACK: need a daygrid wrapper parent to do positioning
760
- // NOTE: a daygrid resource view w/o resources can have zero cells
761
- const firstCellEl = this.rowRefs.currentMap[0].getCellEls()[0];
762
- const rootEl = firstCellEl ? firstCellEl.closest('.fc-daygrid-body') : null;
763
- if (rootEl) {
764
- this.rootEl = rootEl;
765
- this.context.registerInteractiveComponent(this, {
766
- el: rootEl,
767
- isHitComboAllowed: this.props.isHitComboAllowed,
768
- });
769
- }
770
- }
785
+ this.unwatchWidth = internal_cjs.watchWidth(this.rootEl, (width) => {
786
+ this.setState({ width });
787
+ });
771
788
  }
772
789
  componentWillUnmount() {
773
- if (this.rootEl) {
774
- this.context.unregisterInteractiveComponent(this);
775
- this.rootEl = null;
776
- }
790
+ this.unwatchWidth();
777
791
  }
778
792
  // Hit System
779
- // ----------------------------------------------------------------------------------------------------
780
- prepareHits() {
781
- this.rowPositions = new internal_cjs.PositionCache(this.rootEl, this.rowRefs.collect().map((rowObj) => rowObj.getCellEls()[0]), // first cell el in each row. TODO: not optimal
782
- false, true);
783
- this.colPositions = new internal_cjs.PositionCache(this.rootEl, this.rowRefs.currentMap[0].getCellEls(), // cell els in first row
784
- true, // horizontal
785
- false);
786
- }
787
- queryHit(positionLeft, positionTop) {
788
- let { colPositions, rowPositions } = this;
789
- let col = colPositions.leftToIndex(positionLeft);
790
- let row = rowPositions.topToIndex(positionTop);
791
- if (row != null && col != null) {
792
- let cell = this.props.cells[row][col];
793
- return {
794
- dateProfile: this.props.dateProfile,
795
- dateSpan: Object.assign({ range: this.getCellRange(row, col), allDay: true }, cell.extraDateSpan),
796
- dayEl: this.getCellEl(row, col),
797
- rect: {
798
- left: colPositions.lefts[col],
799
- right: colPositions.rights[col],
800
- top: rowPositions.tops[row],
801
- bottom: rowPositions.bottoms[row],
802
- },
803
- layer: 0,
804
- };
805
- }
806
- return null;
807
- }
808
- getCellEl(row, col) {
809
- return this.rowRefs.currentMap[row].getCellEls()[col]; // TODO: not optimal
810
- }
811
- getCellRange(row, col) {
812
- let start = this.props.cells[row][col].date;
813
- let end = internal_cjs.addDays(start, 1);
814
- return { start, end };
793
+ // -----------------------------------------------------------------------------------------------
794
+ queryHit(positionLeft, positionTop, elWidth) {
795
+ const { props, context } = this;
796
+ const colCnt = props.cellRows[0].length;
797
+ const { col, left, right } = computeColFromPosition(positionLeft, elWidth, props.colWidth, colCnt, context.isRtl);
798
+ const { row, top, bottom } = computeRowFromPosition(positionTop, props.cellRows, this.rowHeightRefMap.current);
799
+ const cell = props.cellRows[row][col];
800
+ const cellStartDate = cell.date;
801
+ const cellEndDate = internal_cjs.addDays(cellStartDate, 1);
802
+ return {
803
+ dateProfile: props.dateProfile,
804
+ dateSpan: Object.assign({ range: {
805
+ start: cellStartDate,
806
+ end: cellEndDate,
807
+ }, allDay: true }, cell.extraDateSpan),
808
+ // HACK. TODO: This is expensive to do every hit-query
809
+ dayEl: getCellEl(getRowEl(this.rootEl, row), col),
810
+ rect: {
811
+ left,
812
+ right,
813
+ top,
814
+ bottom,
815
+ },
816
+ layer: 0,
817
+ };
815
818
  }
816
819
  }
820
+ // Utils
821
+ // -------------------------------------------------------------------------------------------------
817
822
  function isSegAllDay(seg) {
818
823
  return seg.eventRange.def.allDay;
819
824
  }
820
825
 
821
- class Table extends internal_cjs.DateComponent {
826
+ class HeaderRow extends internal_cjs.BaseComponent {
827
+ render() {
828
+ const { props } = this;
829
+ return (preact_cjs.createElement("div", { role: props.cellGroup ? undefined : 'row', className: [
830
+ props.cellGroup ? 'fc-flex-row' : 'fc-row',
831
+ props.className || '',
832
+ ].join(' ') }, props.cells.map((cell) => (preact_cjs.createElement(preact_cjs.Fragment, { key: props.getHeaderModelKey(cell) }, props.renderHeaderContent(cell, props.tierNum, undefined, // innerHeightRef
833
+ props.colWidth))))));
834
+ }
835
+ }
836
+
837
+ function DayGridHeader(props) {
838
+ return (preact_cjs.createElement("div", { className: [
839
+ 'fc-rowgroup',
840
+ 'fc-content-box',
841
+ ...(props.extraClassNames || []),
842
+ ].join(' '), style: {
843
+ width: props.width,
844
+ paddingLeft: props.paddingLeft,
845
+ paddingRight: props.paddingRight,
846
+ } }, props.headerTiers.map((cells, tierNum) => (preact_cjs.createElement(HeaderRow, { key: tierNum, tierNum: tierNum, cells: cells, renderHeaderContent: props.renderHeaderContent, getHeaderModelKey: props.getHeaderModelKey, colWidth: props.colWidth })))));
847
+ }
848
+
849
+ class DayGridLayoutNormal extends internal_cjs.BaseComponent {
822
850
  constructor() {
823
851
  super(...arguments);
824
- this.elRef = preact_cjs.createRef();
825
- this.needsScrollReset = false;
852
+ this.handleScroller = (scroller) => {
853
+ internal_cjs.setRef(this.props.scrollerRef, scroller);
854
+ };
855
+ this.handleLeftScrollbarWidth = (leftScrollbarWidth) => {
856
+ this.setState({ leftScrollbarWidth });
857
+ };
858
+ this.handleRightScrollbarWidth = (rightScrollbarWidth) => {
859
+ this.setState({ rightScrollbarWidth });
860
+ };
826
861
  }
827
862
  render() {
828
- let { props } = this;
829
- let { dayMaxEventRows, dayMaxEvents, expandRows } = props;
830
- let limitViaBalanced = dayMaxEvents === true || dayMaxEventRows === true;
831
- // if rows can't expand to fill fixed height, can't do balanced-height event limit
832
- // TODO: best place to normalize these options?
833
- if (limitViaBalanced && !expandRows) {
834
- limitViaBalanced = false;
835
- dayMaxEventRows = null;
836
- dayMaxEvents = null;
837
- }
838
- let classNames = [
839
- 'fc-daygrid-body',
840
- limitViaBalanced ? 'fc-daygrid-body-balanced' : 'fc-daygrid-body-unbalanced',
841
- expandRows ? '' : 'fc-daygrid-body-natural', // will height of one row depend on the others?
842
- ];
843
- return (preact_cjs.createElement("div", { ref: this.elRef, className: classNames.join(' '), style: {
844
- // these props are important to give this wrapper correct dimensions for interactions
845
- // TODO: if we set it here, can we avoid giving to inner tables?
846
- width: props.clientWidth,
847
- minWidth: props.tableMinWidth,
848
- } },
849
- preact_cjs.createElement("table", { role: "presentation", className: "fc-scrollgrid-sync-table", style: {
850
- width: props.clientWidth,
851
- minWidth: props.tableMinWidth,
852
- height: expandRows ? props.clientHeight : '',
853
- } },
854
- props.colGroupNode,
855
- preact_cjs.createElement("tbody", { role: "presentation" },
856
- preact_cjs.createElement(TableRows, { dateProfile: props.dateProfile, cells: props.cells, renderRowIntro: props.renderRowIntro, showWeekNumbers: props.showWeekNumbers, clientWidth: props.clientWidth, clientHeight: props.clientHeight, businessHourSegs: props.businessHourSegs, bgEventSegs: props.bgEventSegs, fgEventSegs: props.fgEventSegs, dateSelectionSegs: props.dateSelectionSegs, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, dayMaxEvents: dayMaxEvents, dayMaxEventRows: dayMaxEventRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed })))));
863
+ const { props, state, context } = this;
864
+ const { options } = context;
865
+ const verticalScrollbars = !props.forPrint && !internal_cjs.getIsHeightAuto(options);
866
+ const stickyHeaderDates = !props.forPrint && internal_cjs.getStickyHeaderDates(options);
867
+ return (preact_cjs.createElement(preact_cjs.Fragment, null,
868
+ options.dayHeaders && (preact_cjs.createElement(DayGridHeader, { headerTiers: props.headerTiers, renderHeaderContent: props.renderHeaderContent, getHeaderModelKey: props.getHeaderModelKey,
869
+ // render hooks
870
+ extraClassNames: [
871
+ 'fc-daygrid-header',
872
+ stickyHeaderDates ? 'fc-sticky-header' : '',
873
+ ],
874
+ // dimensions
875
+ paddingLeft: state.leftScrollbarWidth, paddingRight: state.rightScrollbarWidth })),
876
+ preact_cjs.createElement(internal_cjs.Scroller, { vertical: verticalScrollbars, leftScrollbarWidthRef: this.handleLeftScrollbarWidth, rightScrollbarWidthRef: this.handleRightScrollbarWidth, elClassNames: [
877
+ 'fc-daygrid-body',
878
+ 'fc-rowgroup',
879
+ 'fc-flex-column',
880
+ verticalScrollbars ? 'fc-liquid' : '',
881
+ ], ref: this.handleScroller },
882
+ preact_cjs.createElement(DayGridRows // .fc-grow
883
+ , { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: props.cellRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed,
884
+ // content
885
+ fgEventSegs: props.fgEventSegs, bgEventSegs: props.bgEventSegs, businessHourSegs: props.businessHourSegs, dateSelectionSegs: props.dateSelectionSegs, eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
886
+ // refs
887
+ rowHeightRefMap: props.rowHeightRefMap }))));
857
888
  }
858
- componentDidMount() {
859
- this.requestScrollReset();
889
+ }
890
+
891
+ class DayGridLayoutPannable extends internal_cjs.BaseComponent {
892
+ constructor() {
893
+ super(...arguments);
894
+ this.headerScrollerRef = preact_cjs.createRef();
895
+ this.bodyScrollerRef = preact_cjs.createRef();
896
+ this.footerScrollerRef = preact_cjs.createRef();
897
+ // Sizing
898
+ // -----------------------------------------------------------------------------------------------
899
+ this.handleWidth = (width) => {
900
+ this.setState({ width });
901
+ };
902
+ this.handleLeftScrollbarWidth = (leftScrollbarWidth) => {
903
+ this.setState({ leftScrollbarWidth });
904
+ };
905
+ this.handleRightScrollbarWidth = (rightScrollbarWidth) => {
906
+ this.setState({ rightScrollbarWidth });
907
+ };
860
908
  }
861
- componentDidUpdate(prevProps) {
862
- if (prevProps.dateProfile !== this.props.dateProfile) {
863
- this.requestScrollReset();
864
- }
865
- else {
866
- this.flushScrollReset();
867
- }
909
+ render() {
910
+ const { props, state, context } = this;
911
+ const { options } = context;
912
+ const verticalScrollbars = !props.forPrint && !internal_cjs.getIsHeightAuto(options);
913
+ const stickyHeaderDates = !props.forPrint && internal_cjs.getStickyHeaderDates(options);
914
+ const stickyFooterScrollbar = !props.forPrint && internal_cjs.getStickyFooterScrollbar(options);
915
+ const colCnt = props.cellRows[0].length;
916
+ const [canvasWidth, colWidth] = computeColWidth(colCnt, props.dayMinWidth, state.width);
917
+ return (preact_cjs.createElement(preact_cjs.Fragment, null,
918
+ options.dayHeaders && (preact_cjs.createElement(internal_cjs.Scroller, { horizontal: true, hideScrollbars: true, elClassNames: [
919
+ 'fc-daygrid-header',
920
+ 'fc-rowgroup',
921
+ stickyHeaderDates ? 'fc-sticky-header' : ''
922
+ ], ref: this.headerScrollerRef },
923
+ preact_cjs.createElement(DayGridHeader, { headerTiers: props.headerTiers, renderHeaderContent: props.renderHeaderContent, getHeaderModelKey: props.getHeaderModelKey,
924
+ // dimensions
925
+ colWidth: colWidth, width: canvasWidth, paddingLeft: state.leftScrollbarWidth, paddingRight: state.rightScrollbarWidth }))),
926
+ preact_cjs.createElement(internal_cjs.Scroller, { vertical: verticalScrollbars, horizontal: true, hideScrollbars: stickyFooterScrollbar, widthRef: this.handleWidth, leftScrollbarWidthRef: this.handleLeftScrollbarWidth, rightScrollbarWidthRef: this.handleRightScrollbarWidth, elClassNames: [
927
+ 'fc-daygrid-body',
928
+ 'fc-rowgroup',
929
+ 'fc-flex-column',
930
+ verticalScrollbars ? 'fc-liquid' : '',
931
+ ], ref: this.bodyScrollerRef },
932
+ preact_cjs.createElement(DayGridRows // .fc-grow
933
+ , { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: props.cellRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed,
934
+ // content
935
+ fgEventSegs: props.fgEventSegs, bgEventSegs: props.bgEventSegs, businessHourSegs: props.businessHourSegs, dateSelectionSegs: props.dateSelectionSegs, eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
936
+ // dimensions
937
+ colWidth: colWidth, width: canvasWidth,
938
+ // refs
939
+ rowHeightRefMap: props.rowHeightRefMap })),
940
+ Boolean(stickyFooterScrollbar) && (preact_cjs.createElement(internal_cjs.Scroller, { ref: this.footerScrollerRef, horizontal: true, elClassNames: ['fc-sticky-footer'], elStyle: {
941
+ marginTop: '-1px', // HACK
942
+ } },
943
+ preact_cjs.createElement("div", { style: {
944
+ width: canvasWidth,
945
+ height: '1px', // HACK
946
+ } })))));
868
947
  }
869
- requestScrollReset() {
870
- this.needsScrollReset = true;
871
- this.flushScrollReset();
872
- }
873
- flushScrollReset() {
874
- if (this.needsScrollReset &&
875
- this.props.clientWidth // sizes computed?
876
- ) {
877
- const subjectEl = getScrollSubjectEl(this.elRef.current, this.props.dateProfile);
878
- if (subjectEl) {
879
- const originEl = subjectEl.closest('.fc-daygrid-body');
880
- const scrollEl = originEl.closest('.fc-scroller');
881
- const scrollTop = subjectEl.getBoundingClientRect().top -
882
- originEl.getBoundingClientRect().top;
883
- scrollEl.scrollTop = scrollTop ? (scrollTop + 1) : 0; // overcome border
884
- }
885
- this.needsScrollReset = false;
886
- }
948
+ // Lifecycle
949
+ // -----------------------------------------------------------------------------------------------
950
+ componentDidMount() {
951
+ // scroller
952
+ const ScrollerSyncer = internal_cjs.getScrollerSyncerClass(this.context.pluginHooks);
953
+ this.syncedScroller = new ScrollerSyncer(true); // horizontal=true
954
+ internal_cjs.setRef(this.props.scrollerRef, this.syncedScroller);
955
+ this.updateSyncedScroller();
887
956
  }
888
- }
889
- function getScrollSubjectEl(containerEl, dateProfile) {
890
- let el;
891
- if (dateProfile.currentRangeUnit.match(/year|month/)) {
892
- el = containerEl.querySelector(`[data-date="${internal_cjs.formatIsoMonthStr(dateProfile.currentDate)}-01"]`);
893
- // even if view is month-based, first-of-month might be hidden...
957
+ componentDidUpdate() {
958
+ // scroller
959
+ this.updateSyncedScroller();
894
960
  }
895
- if (!el) {
896
- el = containerEl.querySelector(`[data-date="${internal_cjs.formatDayString(dateProfile.currentDate)}"]`);
897
- // could still be hidden if an interior-view hidden day
961
+ componentWillUnmount() {
962
+ // scroller
963
+ this.syncedScroller.destroy();
964
+ }
965
+ // Scrolling
966
+ // -----------------------------------------------------------------------------------------------
967
+ updateSyncedScroller() {
968
+ const { isRtl } = this.context;
969
+ this.syncedScroller.handleChildren([
970
+ this.headerScrollerRef.current,
971
+ this.bodyScrollerRef.current,
972
+ this.footerScrollerRef.current,
973
+ ], isRtl);
898
974
  }
899
- return el;
900
975
  }
901
976
 
902
- class DayTableSlicer extends internal_cjs.Slicer {
977
+ class DayGridLayout extends internal_cjs.BaseComponent {
903
978
  constructor() {
904
979
  super(...arguments);
905
- this.forceDayIfListItem = true;
980
+ // ref
981
+ this.scrollerRef = preact_cjs.createRef();
982
+ this.rowHeightRefMap = new internal_cjs.RefMap();
983
+ // Scrolling
984
+ // -----------------------------------------------------------------------------------------------
985
+ this.timeScrollResponder = new internal_cjs.ScrollResponder((_time) => {
986
+ // HACK to scroll to day
987
+ const rowHeightMap = this.rowHeightRefMap.current;
988
+ const scroller = this.scrollerRef.current;
989
+ const scrollTop = computeTopFromDate(this.props.dateProfile.currentDate, this.props.cellRows, rowHeightMap);
990
+ if (scrollTop != null) {
991
+ scroller.scrollTo({ y: scrollTop });
992
+ return true;
993
+ }
994
+ return false;
995
+ });
906
996
  }
907
- sliceRange(dateRange, dayTableModel) {
908
- return dayTableModel.sliceRange(dateRange);
997
+ render() {
998
+ const { props, context } = this;
999
+ const { options } = context;
1000
+ const commonLayoutProps = Object.assign(Object.assign({}, props), { scrollerRef: this.scrollerRef, rowHeightRefMap: this.rowHeightRefMap });
1001
+ 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)))));
1002
+ }
1003
+ // Lifecycle
1004
+ // -----------------------------------------------------------------------------------------------
1005
+ componentDidMount() {
1006
+ const { context } = this;
1007
+ const { options } = context;
1008
+ context.emitter.on('_timeScrollRequest', this.timeScrollResponder.handleScroll);
1009
+ this.timeScrollResponder.handleScroll(options.scrollTime);
1010
+ }
1011
+ componentDidUpdate(prevProps) {
1012
+ const { options } = this.context;
1013
+ if (prevProps.dateProfile !== this.props.dateProfile && options.scrollTimeReset) {
1014
+ this.timeScrollResponder.handleScroll(options.scrollTime);
1015
+ }
1016
+ else {
1017
+ this.timeScrollResponder.drain();
1018
+ }
1019
+ }
1020
+ componentWillUnmount() {
1021
+ this.context.emitter.off('_timeScrollRequest', this.timeScrollResponder.handleScroll);
909
1022
  }
910
1023
  }
911
1024
 
912
- class DayTable extends internal_cjs.DateComponent {
1025
+ const WEEKDAY_FORMAT = internal_cjs.createFormatter({ weekday: 'long' });
1026
+ class DayOfWeekHeaderCell extends internal_cjs.BaseComponent {
913
1027
  constructor() {
914
1028
  super(...arguments);
915
- this.slicer = new DayTableSlicer();
916
- this.tableRef = preact_cjs.createRef();
1029
+ // ref
1030
+ this.innerElRef = preact_cjs.createRef();
917
1031
  }
918
1032
  render() {
919
1033
  let { props, context } = this;
920
- return (preact_cjs.createElement(Table, Object.assign({ ref: this.tableRef }, this.slicer.sliceProps(props, props.dateProfile, props.nextDayThreshold, context, props.dayTableModel), { dateProfile: props.dateProfile, cells: props.dayTableModel.cells, colGroupNode: props.colGroupNode, tableMinWidth: props.tableMinWidth, renderRowIntro: props.renderRowIntro, dayMaxEvents: props.dayMaxEvents, dayMaxEventRows: props.dayMaxEventRows, showWeekNumbers: props.showWeekNumbers, expandRows: props.expandRows, headerAlignElRef: props.headerAlignElRef, clientWidth: props.clientWidth, clientHeight: props.clientHeight, forPrint: props.forPrint })));
1034
+ let { dateEnv, theme, viewApi, options } = context;
1035
+ let date = internal_cjs.addDays(new Date(259200000), props.dow); // start with Sun, 04 Jan 1970 00:00:00 GMT
1036
+ let dateMeta = {
1037
+ dow: props.dow,
1038
+ isDisabled: false,
1039
+ isFuture: false,
1040
+ isPast: false,
1041
+ isToday: false,
1042
+ isOther: false,
1043
+ };
1044
+ let text = dateEnv.format(date, props.dayHeaderFormat);
1045
+ let renderProps = Object.assign(Object.assign(Object.assign(Object.assign({ date }, dateMeta), { view: viewApi }), props.extraRenderProps), { text });
1046
+ return (preact_cjs.createElement(internal_cjs.ContentContainer, { elTag: 'div', elClasses: [
1047
+ ...internal_cjs.getDayClassNames(dateMeta, theme),
1048
+ ...(props.extraClassNames || []),
1049
+ 'fc-header-cell',
1050
+ 'fc-cell',
1051
+ props.colWidth != null ? '' : 'fc-liquid',
1052
+ 'fc-flex-column',
1053
+ 'fc-align-center',
1054
+ ], elAttrs: props.extraDataAttrs, elStyle: {
1055
+ width: props.colWidth != null // TODO: DRY
1056
+ ? props.colWidth * (props.colSpan || 1)
1057
+ : undefined,
1058
+ }, 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: [
1059
+ 'fc-flex-column',
1060
+ props.isSticky ? 'fc-sticky-x' : '',
1061
+ ].join(' ') },
1062
+ preact_cjs.createElement(InnerContent, { elTag: "a", elClasses: [
1063
+ 'fc-cell-inner',
1064
+ 'fc-padding-sm',
1065
+ ], elAttrs: {
1066
+ 'aria-label': dateEnv.format(date, WEEKDAY_FORMAT),
1067
+ } })))));
1068
+ }
1069
+ componentDidMount() {
1070
+ const innerEl = this.innerElRef.current; // TODO: make dynamic with useEffect
1071
+ // TODO: only attach this if refs props present
1072
+ this.disconectInnerHeight = internal_cjs.watchHeight(innerEl, (height) => {
1073
+ internal_cjs.setRef(this.props.innerHeightRef, height);
1074
+ });
1075
+ }
1076
+ componentWillUnmount() {
1077
+ this.disconectInnerHeight();
1078
+ }
1079
+ }
1080
+
1081
+ function createDayHeaderFormatter(explicitFormat, datesRepDistinctDays, dateCnt) {
1082
+ return explicitFormat || computeFallbackHeaderFormat(datesRepDistinctDays, dateCnt);
1083
+ }
1084
+ // Computes a default column header formatting string if `colFormat` is not explicitly defined
1085
+ function computeFallbackHeaderFormat(datesRepDistinctDays, dayCnt) {
1086
+ // if more than one week row, or if there are a lot of columns with not much space,
1087
+ // put just the day numbers will be in each cell
1088
+ if (!datesRepDistinctDays || dayCnt > 10) {
1089
+ return internal_cjs.createFormatter({ weekday: 'short' }); // "Sat"
921
1090
  }
1091
+ if (dayCnt > 1) {
1092
+ return internal_cjs.createFormatter({ weekday: 'short', month: 'numeric', day: 'numeric', omitCommas: true }); // "Sat 11/12"
1093
+ }
1094
+ return internal_cjs.createFormatter({ weekday: 'long' }); // "Saturday"
922
1095
  }
923
1096
 
924
- class DayTableView extends TableView {
1097
+ class DayGridView extends internal_cjs.BaseComponent {
925
1098
  constructor() {
926
1099
  super(...arguments);
1100
+ // memo
927
1101
  this.buildDayTableModel = internal_cjs.memoize(buildDayTableModel);
928
- this.headerRef = preact_cjs.createRef();
929
- this.tableRef = preact_cjs.createRef();
930
- // can't override any lifecycle methods from parent
1102
+ this.buildHeaderTiers = internal_cjs.memoize(buildHeaderTiers);
1103
+ this.createDayHeaderFormatter = internal_cjs.memoize(createDayHeaderFormatter);
1104
+ // internal
1105
+ this.slicer = new DayTableSlicer();
931
1106
  }
932
1107
  render() {
933
- let { options, dateProfileGenerator } = this.context;
934
- let { props } = this;
935
- let dayTableModel = this.buildDayTableModel(props.dateProfile, dateProfileGenerator);
936
- let headerContent = options.dayHeaders && (preact_cjs.createElement(internal_cjs.DayHeader, { ref: this.headerRef, dateProfile: props.dateProfile, dates: dayTableModel.headerDates, datesRepDistinctDays: dayTableModel.rowCnt === 1 }));
937
- let bodyContent = (contentArg) => (preact_cjs.createElement(DayTable, { ref: this.tableRef, dateProfile: props.dateProfile, dayTableModel: dayTableModel, businessHours: props.businessHours, dateSelection: props.dateSelection, eventStore: props.eventStore, eventUiBases: props.eventUiBases, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, nextDayThreshold: options.nextDayThreshold, colGroupNode: contentArg.tableColGroupNode, tableMinWidth: contentArg.tableMinWidth, dayMaxEvents: options.dayMaxEvents, dayMaxEventRows: options.dayMaxEventRows, showWeekNumbers: options.weekNumbers, expandRows: !props.isHeightAuto, headerAlignElRef: this.headerElRef, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, forPrint: props.forPrint }));
938
- return options.dayMinWidth
939
- ? this.renderHScrollLayout(headerContent, bodyContent, dayTableModel.colCnt, options.dayMinWidth)
940
- : this.renderSimpleLayout(headerContent, bodyContent);
1108
+ const { props, context } = this;
1109
+ const { options } = context;
1110
+ const dayTableModel = this.buildDayTableModel(props.dateProfile, context.dateProfileGenerator);
1111
+ const datesRepDistinctDays = dayTableModel.rowCnt === 1;
1112
+ const headerTiers = this.buildHeaderTiers(dayTableModel.headerDates, datesRepDistinctDays);
1113
+ const slicedProps = this.slicer.sliceProps(props, props.dateProfile, options.nextDayThreshold, context, dayTableModel);
1114
+ const dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, datesRepDistinctDays, dayTableModel.colCnt);
1115
+ 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',
1116
+ // header content
1117
+ headerTiers: headerTiers, renderHeaderContent: (model, tier, innerHeightRef, colWidth) => {
1118
+ if (model.date) {
1119
+ return (preact_cjs.createElement(DateHeaderCell, Object.assign({}, model, { dateProfile: props.dateProfile, todayRange: todayRange, navLink: dayTableModel.colCnt > 1, dayHeaderFormat: dayHeaderFormat, colSpan: model.colSpan, colWidth: colWidth })));
1120
+ }
1121
+ else {
1122
+ return (preact_cjs.createElement(DayOfWeekHeaderCell, Object.assign({}, model, { dayHeaderFormat: dayHeaderFormat, colSpan: model.colSpan, colWidth: colWidth })));
1123
+ }
1124
+ }, getHeaderModelKey: (model) => {
1125
+ // can use model.key???
1126
+ if (model.date) {
1127
+ return model.date.toUTCString();
1128
+ }
1129
+ return model.dow;
1130
+ },
1131
+ // body content
1132
+ fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection }))));
941
1133
  }
942
1134
  }
943
- function buildDayTableModel(dateProfile, dateProfileGenerator) {
944
- let daySeries = new internal_cjs.DaySeriesModel(dateProfile.renderRange, dateProfileGenerator);
945
- return new internal_cjs.DayTableModel(daySeries, /year|month|week/.test(dateProfile.currentRangeUnit));
946
- }
947
1135
 
948
- class TableDateProfileGenerator extends internal_cjs.DateProfileGenerator {
949
- // Computes the date range that will be rendered
950
- buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay) {
951
- let renderRange = super.buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay);
952
- let { props } = this;
953
- return buildDayTableRenderRange({
954
- currentRange: renderRange,
955
- snapToWeek: /^(year|month)$/.test(currentRangeUnit),
956
- fixedWeekCount: props.fixedWeekCount,
957
- dateEnv: props.dateEnv,
1136
+ /*
1137
+ TODO: is it even worth doing this "advanced" version?
1138
+ */
1139
+ class HeaderRowAdvanced extends internal_cjs.BaseComponent {
1140
+ constructor() {
1141
+ super(...arguments);
1142
+ // ref
1143
+ this.innerHeightRefMap = new internal_cjs.RefMap(() => {
1144
+ internal_cjs.afterSize(this.handleInnerHeights);
958
1145
  });
1146
+ this.handleInnerHeights = () => {
1147
+ const innerHeightMap = this.innerHeightRefMap.current;
1148
+ let max = 0;
1149
+ for (const innerHeight of innerHeightMap.values()) {
1150
+ max = Math.max(max, innerHeight);
1151
+ }
1152
+ if (this.currentInnerHeight !== max) {
1153
+ this.currentInnerHeight = max;
1154
+ internal_cjs.setRef(this.props.innerHeightRef, max);
1155
+ }
1156
+ };
959
1157
  }
960
- }
961
- function buildDayTableRenderRange(props) {
962
- let { dateEnv, currentRange } = props;
963
- let { start, end } = currentRange;
964
- let endOfWeek;
965
- // year and month views should be aligned with weeks. this is already done for week
966
- if (props.snapToWeek) {
967
- start = dateEnv.startOfWeek(start);
968
- // make end-of-week if not already
969
- endOfWeek = dateEnv.startOfWeek(end);
970
- if (endOfWeek.valueOf() !== end.valueOf()) {
971
- end = internal_cjs.addWeeks(endOfWeek, 1);
972
- }
973
- }
974
- // ensure 6 weeks
975
- if (props.fixedWeekCount) {
976
- // TODO: instead of these date-math gymnastics (for multimonth view),
977
- // compute dateprofiles of all months, then use start of first and end of last.
978
- let lastMonthRenderStart = dateEnv.startOfWeek(dateEnv.startOfMonth(internal_cjs.addDays(currentRange.end, -1)));
979
- let rowCnt = Math.ceil(// could be partial weeks due to hiddenDays
980
- internal_cjs.diffWeeks(lastMonthRenderStart, end));
981
- end = internal_cjs.addWeeks(end, 6 - rowCnt);
1158
+ render() {
1159
+ const { props } = this;
1160
+ return (preact_cjs.createElement("div", { role: 'row', className: 'fc-row', style: { height: props.height } }, props.cells.map((cell) => {
1161
+ const key = props.getHeaderModelKey(cell);
1162
+ return (preact_cjs.createElement(preact_cjs.Fragment, { key: props.getHeaderModelKey(cell) }, props.renderHeaderContent(cell, props.tierNum, this.innerHeightRefMap.createRef(key), // innerHeightRef
1163
+ props.colWidth)));
1164
+ })));
982
1165
  }
983
- return { start, end };
984
1166
  }
985
1167
 
986
- var css_248z = ":root{--fc-daygrid-event-dot-width:8px}.fc-daygrid-day-events:after,.fc-daygrid-day-events:before,.fc-daygrid-day-frame:after,.fc-daygrid-day-frame:before,.fc-daygrid-event-harness:after,.fc-daygrid-event-harness:before{clear:both;content:\"\";display:table}.fc .fc-daygrid-body{position:relative;z-index:1}.fc .fc-daygrid-day.fc-day-today{background-color:var(--fc-today-bg-color)}.fc .fc-daygrid-day-frame{min-height:100%;position:relative}.fc .fc-daygrid-day-top{display:flex;flex-direction:row-reverse}.fc .fc-day-other .fc-daygrid-day-top{opacity:.3}.fc .fc-daygrid-day-number{padding:4px;position:relative;z-index:4}.fc .fc-daygrid-month-start{font-size:1.1em;font-weight:700}.fc .fc-daygrid-day-events{margin-top:1px}.fc .fc-daygrid-body-balanced .fc-daygrid-day-events{left:0;position:absolute;right:0}.fc .fc-daygrid-body-unbalanced .fc-daygrid-day-events{min-height:2em;position:relative}.fc .fc-daygrid-body-natural .fc-daygrid-day-events{margin-bottom:1em}.fc .fc-daygrid-event-harness{position:relative}.fc .fc-daygrid-event-harness-abs{left:0;position:absolute;right:0;top:0}.fc .fc-daygrid-bg-harness{bottom:0;position:absolute;top:0}.fc .fc-daygrid-day-bg .fc-non-business{z-index:1}.fc .fc-daygrid-day-bg .fc-bg-event{z-index:2}.fc .fc-daygrid-day-bg .fc-highlight{z-index:3}.fc .fc-daygrid-event{margin-top:1px;z-index:6}.fc .fc-daygrid-event.fc-event-mirror{z-index:7}.fc .fc-daygrid-day-bottom{font-size:.85em;margin:0 2px}.fc .fc-daygrid-day-bottom:after,.fc .fc-daygrid-day-bottom:before{clear:both;content:\"\";display:table}.fc .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 .fc-daygrid-more-link:hover{background-color:rgba(0,0,0,.1)}.fc .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 .fc-more-popover .fc-popover-body{min-width:220px;padding:10px}.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-more-link{float:left}.fc-direction-ltr .fc-daygrid-week-number{border-radius:0 0 3px 0;left:0}.fc-direction-rtl .fc-daygrid-more-link{float:right}.fc-direction-rtl .fc-daygrid-week-number{border-radius:0 0 0 3px;right:0}.fc-liquid-hack .fc-daygrid-day-frame{position:static}.fc-daygrid-event{border-radius:3px;font-size:var(--fc-small-font-size);position:relative;white-space:nowrap}.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;display:flex;padding:2px 0}.fc-daygrid-dot-event .fc-event-title{flex-grow:1;flex-shrink:1;font-weight:700;min-width:0;overflow:hidden}.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-direction-ltr .fc-daygrid-event .fc-event-time{margin-right:3px}.fc-direction-rtl .fc-daygrid-event .fc-event-time{margin-left:3px}";
987
- internal_cjs.injectStyles(css_248z);
988
-
989
- exports.DayGridView = DayTableView;
990
- exports.DayTable = DayTable;
1168
+ exports.COMPACT_CELL_WIDTH = COMPACT_CELL_WIDTH;
1169
+ exports.DateHeaderCell = DateHeaderCell;
1170
+ exports.DayGridLayout = DayGridLayout;
1171
+ exports.DayGridRow = DayGridRow;
1172
+ exports.DayGridRows = DayGridRows;
1173
+ exports.DayGridView = DayGridView;
1174
+ exports.DayOfWeekHeaderCell = DayOfWeekHeaderCell;
991
1175
  exports.DayTableSlicer = DayTableSlicer;
992
- exports.Table = Table;
1176
+ exports.HeaderRow = HeaderRow;
1177
+ exports.HeaderRowAdvanced = HeaderRowAdvanced;
993
1178
  exports.TableDateProfileGenerator = TableDateProfileGenerator;
994
- exports.TableRows = TableRows;
995
- exports.TableView = TableView;
996
1179
  exports.buildDayTableModel = buildDayTableModel;
997
1180
  exports.buildDayTableRenderRange = buildDayTableRenderRange;
1181
+ exports.computeColFromPosition = computeColFromPosition;
1182
+ exports.computeColWidth = computeColWidth;
1183
+ exports.createDayHeaderFormatter = createDayHeaderFormatter;
1184
+ exports.getCellEl = getCellEl;
1185
+ exports.getRowEl = getRowEl;