@fullcalendar/daygrid 6.1.15 → 7.0.0-beta.1

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,252 @@ 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, adjust = 0) {
86
+ let top = 0;
87
+ for (const cells of cellRows) {
88
+ const start = cells[0].date;
89
+ const end = cells[cells.length - 1].date;
90
+ const key = start.toISOString();
91
+ if (date >= start && date <= end) {
92
+ return top;
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
83
97
  }
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 })));
98
+ top += rowHeight + adjust;
86
99
  }
100
+ return top;
101
+ }
102
+ function computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl) {
103
+ let left;
104
+ let right;
105
+ let width;
106
+ if (colWidth != null) {
107
+ width = (seg.lastCol - seg.firstCol + 1) * colWidth;
108
+ if (isRtl) {
109
+ right = seg.firstCol * colWidth;
110
+ }
111
+ else {
112
+ left = seg.firstCol * colWidth;
113
+ }
114
+ }
115
+ else {
116
+ const colWidthFrac = 1 / colCnt;
117
+ width = internal_cjs.fracToCssDim((seg.lastCol - seg.firstCol + 1) * colWidthFrac);
118
+ if (isRtl) {
119
+ right = internal_cjs.fracToCssDim(seg.firstCol * colWidthFrac);
120
+ }
121
+ else {
122
+ left = internal_cjs.fracToCssDim(seg.firstCol * colWidthFrac);
123
+ }
124
+ }
125
+ return { left, right, width };
126
+ }
127
+ function computeColFromPosition(positionLeft, elWidth, colWidth, colCnt, isRtl) {
128
+ const realColWidth = colWidth != null ? colWidth : elWidth / colCnt;
129
+ const colFromLeft = Math.floor(positionLeft / realColWidth);
130
+ const col = isRtl ? (colCnt - colFromLeft - 1) : colFromLeft;
131
+ const left = colFromLeft * realColWidth;
132
+ const right = left + realColWidth;
133
+ return { col, left, right };
134
+ }
135
+ function computeRowFromPosition(positionTop, cellRows, rowHeightMap) {
136
+ let row = 0;
137
+ let top = 0;
138
+ let bottom = 0;
139
+ for (const cells of cellRows) {
140
+ const key = cells[0].key;
141
+ top = bottom;
142
+ bottom = top + rowHeightMap.get(key);
143
+ if (positionTop < bottom) {
144
+ break;
145
+ }
146
+ row++;
147
+ }
148
+ return { row, top, bottom };
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();
204
+ internal_cjs.setRef(this.props.innerHeightRef, null);
96
205
  }
97
- return byRow;
98
206
  }
99
- function splitSegsByFirstCol(segs, colCnt) {
100
- let byCol = [];
101
- for (let i = 0; i < colCnt; i += 1) {
102
- byCol[i] = [];
207
+
208
+ function splitSegsByRow(segs, rowCnt) {
209
+ const byRow = [];
210
+ for (let row = 0; row < rowCnt; row++) {
211
+ byRow[row] = [];
103
212
  }
104
- for (let seg of segs) {
105
- byCol[seg.firstCol].push(seg);
213
+ for (const seg of segs) {
214
+ byRow[seg.row].push(seg);
106
215
  }
107
- return byCol;
216
+ return byRow;
108
217
  }
109
218
  function splitInteractionByRow(ui, rowCnt) {
110
- let byRow = [];
219
+ const byRow = [];
111
220
  if (!ui) {
112
- for (let i = 0; i < rowCnt; i += 1) {
113
- byRow[i] = null;
221
+ for (let row = 0; row < rowCnt; row++) {
222
+ byRow[row] = null;
114
223
  }
115
224
  }
116
225
  else {
117
- for (let i = 0; i < rowCnt; i += 1) {
118
- byRow[i] = {
226
+ for (let row = 0; row < rowCnt; row++) {
227
+ byRow[row] = {
119
228
  affectedInstances: ui.affectedInstances,
120
229
  isEvent: ui.isEvent,
121
230
  segs: [],
122
231
  };
123
232
  }
124
- for (let seg of ui.segs) {
233
+ for (const seg of ui.segs) {
125
234
  byRow[seg.row].segs.push(seg);
126
235
  }
127
236
  }
128
237
  return byRow;
129
238
  }
239
+ function splitSegsByCol(segs, colCnt) {
240
+ let byCol = [];
241
+ for (let col = 0; col < colCnt; col++) {
242
+ byCol.push([]);
243
+ }
244
+ for (let seg of segs) {
245
+ for (let col = seg.firstCol; col <= seg.lastCol; col++) {
246
+ if (seg.firstCol !== col) {
247
+ seg = Object.assign(Object.assign({}, seg), { firstCol: col, lastCol: col, isStart: false, isEnd: seg.isEnd && seg.lastCol === col, isStandin: true });
248
+ }
249
+ byCol[col].push(seg);
250
+ }
251
+ }
252
+ return byCol;
253
+ }
130
254
 
131
255
  const DEFAULT_TABLE_EVENT_TIME_FORMAT = internal_cjs.createFormatter({
132
256
  hour: 'numeric',
@@ -144,21 +268,21 @@ function hasListItemDisplay(seg) {
144
268
  );
145
269
  }
146
270
 
147
- class TableBlockEvent extends internal_cjs.BaseComponent {
271
+ class DayGridBlockEvent extends internal_cjs.BaseComponent {
148
272
  render() {
149
273
  let { props } = this;
150
- 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 })));
274
+ return (preact_cjs.createElement(internal_cjs.StandardEvent, Object.assign({}, props, { elClasses: ['fc-daygrid-event', 'fc-daygrid-block-event', 'fc-h-event'], defaultTimeFormat: DEFAULT_TABLE_EVENT_TIME_FORMAT, defaultDisplayEventEnd: props.defaultDisplayEventEnd, disableResizing: !props.eventRange.def.allDay })));
151
275
  }
152
276
  }
153
277
 
154
- class TableListItemEvent extends internal_cjs.BaseComponent {
278
+ class DayGridListEvent extends internal_cjs.BaseComponent {
155
279
  render() {
156
280
  let { props, context } = this;
157
281
  let { options } = context;
158
- let { seg } = props;
282
+ let { eventRange } = props;
159
283
  let timeFormat = options.eventTimeFormat || DEFAULT_TABLE_EVENT_TIME_FORMAT;
160
- let timeText = internal_cjs.buildSegTimeText(seg, timeFormat, context, true, props.defaultDisplayEventEnd);
161
- return (preact_cjs.createElement(internal_cjs.EventContainer, Object.assign({}, props, { elTag: "a", elClasses: ['fc-daygrid-event', 'fc-daygrid-dot-event'], elAttrs: internal_cjs.getSegAnchorAttrs(props.seg, context), defaultGenerator: renderInnerContent, timeText: timeText, isResizing: false, isDateSelecting: false })));
284
+ let timeText = internal_cjs.buildEventRangeTimeText(eventRange, timeFormat, context, true, props.defaultDisplayEventEnd);
285
+ return (preact_cjs.createElement(internal_cjs.EventContainer, Object.assign({}, props, { elTag: "a", elClasses: ['fc-daygrid-event', 'fc-daygrid-dot-event'], elAttrs: internal_cjs.getEventRangeAnchorAttrs(eventRange, context), defaultGenerator: renderInnerContent, timeText: timeText, isResizing: false, isDateSelecting: false })));
162
286
  }
163
287
  }
164
288
  function renderInnerContent(renderProps) {
@@ -168,80 +292,84 @@ function renderInnerContent(renderProps) {
168
292
  preact_cjs.createElement("div", { className: "fc-event-title" }, renderProps.event.title || preact_cjs.createElement(preact_cjs.Fragment, null, "\u00A0"))));
169
293
  }
170
294
 
171
- class TableCellMoreLink extends internal_cjs.BaseComponent {
172
- constructor() {
173
- super(...arguments);
174
- this.compileSegs = internal_cjs.memoize(compileSegs);
175
- }
295
+ class DayGridMoreLink extends internal_cjs.BaseComponent {
176
296
  render() {
177
297
  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) ||
298
+ return (preact_cjs.createElement(internal_cjs.MoreLinkContainer, { elClasses: ['fc-daygrid-more-link'], dateProfile: props.dateProfile, todayRange: props.todayRange, allDayDate: props.allDayDate, segs: props.segs, hiddenSegs: props.hiddenSegs, alignmentElRef: props.alignmentElRef, alignGridTop: props.alignGridTop, extraDateSpan: props.extraDateSpan, popoverContent: () => {
299
+ let forcedInvisibleMap = // TODO: more convenient/DRY
300
+ (props.eventDrag ? props.eventDrag.affectedInstances : null) ||
181
301
  (props.eventResize ? props.eventResize.affectedInstances : null) ||
182
302
  {};
183
- return (preact_cjs.createElement(preact_cjs.Fragment, null, allSegs.map((seg) => {
184
- 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))))));
303
+ return (preact_cjs.createElement(preact_cjs.Fragment, null, props.segs.map((seg) => {
304
+ let { eventRange } = seg;
305
+ let instanceId = eventRange.instance.instanceId;
306
+ return (preact_cjs.createElement("div", { key: instanceId, style: {
307
+ visibility: forcedInvisibleMap[instanceId] ? 'hidden' : '',
308
+ } }, hasListItemDisplay(seg) ? (preact_cjs.createElement(DayGridListEvent, Object.assign({ eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, internal_cjs.getEventRangeMeta(eventRange, props.todayRange)))) : (preact_cjs.createElement(DayGridBlockEvent, Object.assign({ eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, internal_cjs.getEventRangeMeta(eventRange, props.todayRange))))));
188
309
  })));
189
310
  } }));
190
311
  }
191
312
  }
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
313
 
204
- const DEFAULT_WEEK_NUM_FORMAT = internal_cjs.createFormatter({ week: 'narrow' });
205
- class TableCell extends internal_cjs.DateComponent {
314
+ class DayGridCell extends internal_cjs.DateComponent {
206
315
  constructor() {
207
316
  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
- };
317
+ // ref
318
+ this.innerElRef = preact_cjs.createRef();
319
+ this.headerWrapElRef = preact_cjs.createRef();
216
320
  }
217
321
  render() {
218
- let { context, props, state, rootElRef } = this;
322
+ let { props, context } = this;
219
323
  let { options, dateEnv } = context;
220
- let { date, dateProfile } = props;
221
- // TODO: memoize this?
324
+ // TODO: memoize this
222
325
  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',
326
+ shouldDisplayMonthStart(props.date, props.dateProfile.currentRange, dateEnv);
327
+ return (preact_cjs.createElement(internal_cjs.DayCellContainer, { elTag: "div", elClasses: [
328
+ 'fc-daygrid-cell',
329
+ 'fc-cell',
330
+ props.width != null ? '' : 'fc-liquid',
331
+ 'fc-flex-column',
226
332
  ...(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" },
333
+ ], elAttrs: Object.assign(Object.assign({}, props.extraDataAttrs), { role: 'gridcell' }), elStyle: {
334
+ width: props.width
335
+ }, extraRenderProps: props.extraRenderProps, defaultGenerator: renderTopInner, date: props.date, dateProfile: props.dateProfile, todayRange: props.todayRange, showDayNumber: props.showDayNumber, isMonthStart: isMonthStart }, (InnerContent, renderProps) => (preact_cjs.createElement("div", { ref: this.innerElRef, className: [
336
+ 'fc-daygrid-cell-inner',
337
+ props.fgLiquidHeight ? 'fc-liquid' : ''
338
+ ].join(' ') },
339
+ preact_cjs.createElement("div", { ref: this.headerWrapElRef, className: "fc-flex-column" }, !renderProps.isDisabled && (props.showDayNumber || internal_cjs.hasCustomDayCellContent(options)) && (preact_cjs.createElement("div", { className: "fc-daygrid-cell-header" },
231
340
  preact_cjs.createElement(InnerContent, { elTag: "a", elClasses: [
232
- 'fc-daygrid-day-number',
341
+ 'fc-daygrid-cell-number',
233
342
  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)))));
343
+ ], elAttrs: internal_cjs.buildNavLinkAttrs(context, props.date) })))),
344
+ preact_cjs.createElement("div", { className: "fc-daygrid-cell-main", style: {
345
+ height: props.fgLiquidHeight ? '' : props.fgHeight
346
+ } }, props.fg),
347
+ preact_cjs.createElement("div", { className: "fc-daygrid-cell-footer", style: props.fgLiquidHeight
348
+ ? { position: 'relative', top: props.fgHeight }
349
+ : {} },
350
+ preact_cjs.createElement(DayGridMoreLink, { allDayDate: props.date, segs: props.segs, hiddenSegs: props.hiddenSegs, alignmentElRef: this.innerElRef, alignGridTop: !props.showDayNumber, extraDateSpan: props.extraDateSpan, dateProfile: props.dateProfile, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, todayRange: props.todayRange })),
351
+ props.bg))));
352
+ }
353
+ componentDidMount() {
354
+ const innerEl = this.innerElRef.current; // TODO: make dynamic with useEffect
355
+ const headerWrapEl = this.headerWrapElRef.current; // "
356
+ // TODO: only attach this if refs props present
357
+ this.detachInnerHeight = internal_cjs.watchHeight(innerEl, (height) => {
358
+ internal_cjs.setRef(this.props.innerHeightRef, height);
359
+ });
360
+ this.detachHeaderHeight = internal_cjs.watchHeight(headerWrapEl, (height) => {
361
+ internal_cjs.setRef(this.props.headerHeightRef, height);
362
+ });
363
+ }
364
+ componentWillUnmount() {
365
+ this.detachInnerHeight();
366
+ this.detachHeaderHeight();
367
+ internal_cjs.setRef(this.props.innerHeightRef, null);
368
+ internal_cjs.setRef(this.props.headerHeightRef, null);
243
369
  }
244
370
  }
371
+ // Utils
372
+ // -------------------------------------------------------------------------------------------------
245
373
  function renderTopInner(props) {
246
374
  return props.dayNumberText || preact_cjs.createElement(preact_cjs.Fragment, null, "\u00A0");
247
375
  }
@@ -261,26 +389,43 @@ function shouldDisplayMonthStart(date, currentRange, dateEnv) {
261
389
  (dateEnv.getDay(date) === 1 && date.valueOf() < currentEnd.valueOf()));
262
390
  }
263
391
 
264
- function generateSegKey(seg) {
392
+ /*
393
+ Unique per-START-column, good for cataloging by top
394
+ */
395
+ function getSegStartId(seg) {
265
396
  return seg.eventRange.instance.instanceId + ':' + seg.firstCol;
266
397
  }
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;
398
+ /*
399
+ Unique per-START-and-END-column, good for cataloging by width/height
400
+ */
401
+ function getSegSpanId(seg) {
402
+ return getSegStartId(seg) + ':' + seg.lastCol;
403
+ }
404
+ function computeFgSegVerticals(segs, segHeightMap, // keyed by segSpanId
405
+ cells, topOrigin, maxHeight, strictOrder, dayMaxEvents, dayMaxEventRows) {
406
+ // initialize column-based arrays
407
+ const colCnt = cells.length;
408
+ const hiddenSegsByCol = [];
409
+ const heightsByCol = [];
410
+ for (let col = 0; col < colCnt; col++) {
411
+ hiddenSegsByCol.push([]);
412
+ heightsByCol.push(0);
413
+ }
414
+ // create entries to be given to DayGridSegHierarchy
415
+ const segEntries = segs.map((seg, index) => ({
416
+ index: index,
417
+ seg,
418
+ span: {
419
+ start: seg.firstCol,
420
+ end: seg.lastCol + 1,
421
+ },
422
+ }));
423
+ // configure hierarchy position-generator
424
+ let hierarchy = new DayGridSegHierarchy((segEntry) => (segHeightMap.get(getSegSpanId(segs[segEntry.index]))));
425
+ hierarchy.allowReslicing = false;
281
426
  hierarchy.strictOrder = strictOrder;
282
427
  if (dayMaxEvents === true || dayMaxEventRows === true) {
283
- hierarchy.maxCoord = maxContentHeight;
428
+ hierarchy.maxCoord = maxHeight;
284
429
  hierarchy.hiddenConsumes = true;
285
430
  }
286
431
  else if (typeof dayMaxEvents === 'number') {
@@ -290,172 +435,30 @@ dayMaxEvents, dayMaxEventRows, strictOrder, segHeights, maxContentHeight, cells)
290
435
  hierarchy.maxStackCnt = dayMaxEventRows;
291
436
  hierarchy.hiddenConsumes = true;
292
437
  }
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
- });
335
- }
336
- }
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
- });
360
- }
361
- }
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
- }
438
+ // compile segTops & heightsByCol
439
+ const hiddenSegEntries = hierarchy.addSegs(segEntries);
440
+ const segRects = hierarchy.toRects();
441
+ const segTops = {};
442
+ for (const segRect of segRects) {
443
+ const seg = segs[segRect.index];
444
+ segTops[getSegStartId(seg)] = topOrigin + segRect.levelCoord;
445
+ let { start: col, end: endCol } = segRect.span;
446
+ for (; col < endCol; col++) {
447
+ heightsByCol[col] = Math.max(heightsByCol[col], segRect.levelCoord + segRect.thickness);
423
448
  }
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
449
  }
435
- for (let rect of rects) {
436
- for (let col = rect.span.start; col < rect.span.end; col += 1) {
437
- rectsByEachCol[col].push(rect);
450
+ // compile # of invisible segs per-column
451
+ for (const hiddenSegEntry of hiddenSegEntries) {
452
+ const { span } = hiddenSegEntry;
453
+ const hiddenSeg = segs[hiddenSegEntry.index];
454
+ for (let col = span.start; col < span.end; col++) {
455
+ hiddenSegsByCol[col].push(hiddenSeg);
438
456
  }
439
457
  }
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() });
458
+ return [segTops, heightsByCol, hiddenSegsByCol];
458
459
  }
460
+ // DayGridSegHierarchy
461
+ // -------------------------------------------------------------------------------------------------
459
462
  class DayGridSegHierarchy extends internal_cjs.SegHierarchy {
460
463
  constructor() {
461
464
  super(...arguments);
@@ -503,74 +506,206 @@ class DayGridSegHierarchy extends internal_cjs.SegHierarchy {
503
506
  }
504
507
  }
505
508
 
506
- class TableRow extends internal_cjs.DateComponent {
509
+ class DayGridEventHarness extends preact_cjs.Component {
507
510
  constructor() {
508
511
  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"
512
+ // ref
513
513
  this.rootElRef = preact_cjs.createRef();
514
- this.state = {
515
- framePositions: null,
516
- maxContentHeight: null,
517
- segHeights: {},
514
+ }
515
+ render() {
516
+ const { props } = this;
517
+ return (preact_cjs.createElement("div", { className: "fc-abs", style: props.style, ref: this.rootElRef }, props.children));
518
+ }
519
+ componentDidMount() {
520
+ const rootEl = this.rootElRef.current; // TODO: make dynamic with useEffect
521
+ this.detachHeight = internal_cjs.watchHeight(rootEl, (height) => {
522
+ internal_cjs.setRef(this.props.heightRef, height);
523
+ });
524
+ }
525
+ componentWillUnmount() {
526
+ this.detachHeight();
527
+ internal_cjs.setRef(this.props.heightRef, null);
528
+ }
529
+ }
530
+
531
+ const DEFAULT_WEEK_NUM_FORMAT = internal_cjs.createFormatter({ week: 'narrow' });
532
+ const COMPACT_CELL_WIDTH = 80;
533
+ class DayGridRow extends internal_cjs.BaseComponent {
534
+ constructor() {
535
+ super(...arguments);
536
+ this.cellInnerHeightRefMap = new internal_cjs.RefMap(() => {
537
+ internal_cjs.afterSize(this.handleInnerHeights);
538
+ });
539
+ this.cellHeaderHeightRefMap = new internal_cjs.RefMap(() => {
540
+ internal_cjs.afterSize(this.handleHeaderHeights);
541
+ });
542
+ this.segHeightRefMap = new internal_cjs.RefMap(() => {
543
+ internal_cjs.afterSize(this.handleSegHeights);
544
+ });
545
+ this.handleRootEl = (rootEl) => {
546
+ this.rootEl = rootEl;
547
+ internal_cjs.setRef(this.props.rootElRef, rootEl);
518
548
  };
519
- this.handleResize = (isForced) => {
520
- if (isForced) {
521
- this.updateSizing(true); // isExternal=true
549
+ // Sizing
550
+ // -----------------------------------------------------------------------------------------------
551
+ this.handleHeaderHeights = () => {
552
+ const cellHeaderHeightMap = this.cellHeaderHeightRefMap.current;
553
+ let max = 0;
554
+ for (const height of cellHeaderHeightMap.values()) {
555
+ max = Math.max(max, height);
556
+ }
557
+ if (this.state.headerHeight !== max) {
558
+ this.setState({ headerHeight: max });
522
559
  }
523
560
  };
561
+ this.handleInnerHeights = () => {
562
+ const { props } = this;
563
+ const fgLiquidHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;
564
+ const cellInnerHeightMap = this.cellInnerHeightRefMap.current;
565
+ let max = 0;
566
+ for (const height of cellInnerHeightMap.values()) {
567
+ max = Math.max(max, height);
568
+ }
569
+ if (fgLiquidHeight) {
570
+ if (this.state.innerHeight !== max) {
571
+ this.setState({ innerHeight: max }); // will trigger event rerender
572
+ }
573
+ }
574
+ else {
575
+ internal_cjs.setRef(props.innerHeightRef, max);
576
+ }
577
+ };
578
+ this.handleSegHeights = () => {
579
+ this.setState({ segHeightRev: this.segHeightRefMap.rev }); // will trigger event rerender
580
+ };
524
581
  }
525
582
  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
583
+ const { props, state, context, cellInnerHeightRefMap, cellHeaderHeightRefMap } = this;
584
+ const { cells } = props;
585
+ const { options } = context;
586
+ const weekDate = props.cells[0].date;
587
+ const colCnt = props.cells.length;
588
+ const fgLiquidHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;
589
+ // TODO: memoize? sort all types of segs?
590
+ const fgEventSegs = internal_cjs.sortEventSegs(props.fgEventSegs, options.eventOrder);
591
+ // TODO: memoize?
592
+ const fgEventSegsByCol = splitSegsByCol(fgEventSegs, colCnt);
593
+ const bgEventSegsByCol = splitSegsByCol(props.bgEventSegs, colCnt);
594
+ const businessHoursByCol = splitSegsByCol(props.businessHourSegs, colCnt);
595
+ const highlightSegsByCol = splitSegsByCol(this.getHighlightSegs(), colCnt); // TODO: doesn't need standins
596
+ const mirrorSegsByCol = splitSegsByCol(this.getMirrorSegs(), colCnt); // TODO: doesn't need standins
597
+ // TODO: memoize?
598
+ const [segTops, heightsByCol, hiddenSegsByCol] = computeFgSegVerticals(fgEventSegs, this.segHeightRefMap.current, cells, state.headerHeight, (fgLiquidHeight && state.innerHeight != null && state.headerHeight != null)
599
+ ? state.innerHeight - state.headerHeight
600
+ : undefined, options.eventOrderStrict, props.dayMaxEvents, props.dayMaxEventRows);
601
+ const forcedInvisibleMap = // TODO: more convenient/DRY
535
602
  (props.eventDrag && props.eventDrag.affectedInstances) ||
536
603
  (props.eventResize && props.eventResize.affectedInstances) ||
537
604
  {};
538
- return (preact_cjs.createElement("tr", { ref: this.rootElRef, role: "row" },
539
- props.renderIntro && props.renderIntro(),
605
+ return (preact_cjs.createElement("div", { role: props.cellGroup ? undefined : 'row', className: [
606
+ 'fc-daygrid-row',
607
+ props.forceVSpacing
608
+ ? 'fc-daygrid-row-spacious'
609
+ : props.compact
610
+ ? 'fc-daygrid-row-compact'
611
+ : '',
612
+ props.cellGroup ? 'fc-flex-row' : 'fc-row',
613
+ 'fc-rel',
614
+ props.className || '',
615
+ ].join(' '), style: {
616
+ minHeight: props.minHeight,
617
+ }, ref: this.handleRootEl },
540
618
  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,
619
+ const normalFgNodes = this.renderFgSegs(fgEventSegsByCol[col], segTops, props.todayRange, forcedInvisibleMap);
620
+ const mirrorFgNodes = this.renderFgSegs(mirrorSegsByCol[col], segTops, props.todayRange, {}, // forcedInvisibleMap
621
+ Boolean(props.eventDrag), Boolean(props.eventResize), false);
622
+ return (preact_cjs.createElement(DayGridCell, { key: cell.key, dateProfile: props.dateProfile, todayRange: props.todayRange, date: cell.date, showDayNumber: props.showDayNumbers,
623
+ // content
624
+ segs: fgEventSegsByCol[col], hiddenSegs: hiddenSegsByCol[col], fgLiquidHeight: fgLiquidHeight, fg: (preact_cjs.createElement(preact_cjs.Fragment, null,
545
625
  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,
626
+ preact_cjs.createElement(preact_cjs.Fragment, null, mirrorFgNodes))), bg: (preact_cjs.createElement(preact_cjs.Fragment, null,
548
627
  this.renderFillSegs(highlightSegsByCol[col], 'highlight'),
549
628
  this.renderFillSegs(businessHoursByCol[col], 'non-business'),
550
- this.renderFillSegs(bgEventSegsByCol[col], 'bg-event'))), minHeight: props.cellMinHeight }));
551
- })));
629
+ this.renderFillSegs(bgEventSegsByCol[col], 'bg-event'))), eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
630
+ // render hooks
631
+ extraRenderProps: cell.extraRenderProps, extraDateSpan: cell.extraDateSpan, extraDataAttrs: cell.extraDataAttrs, extraClassNames: cell.extraClassNames,
632
+ // dimensions
633
+ fgHeight: heightsByCol[col], width: props.colWidth,
634
+ // refs
635
+ innerHeightRef: cellInnerHeightRefMap.createRef(cell.key), headerHeightRef: cellHeaderHeightRefMap.createRef(cell.key) }));
636
+ }),
637
+ props.showWeekNumbers && (preact_cjs.createElement(internal_cjs.WeekNumberContainer, { elTag: "a", elClasses: ['fc-daygrid-week-number'], elAttrs: internal_cjs.buildNavLinkAttrs(context, weekDate, 'week'), date: weekDate, defaultFormat: DEFAULT_WEEK_NUM_FORMAT }))));
638
+ }
639
+ renderFgSegs(segs, segTops, todayRange, forcedInvisibleMap, isDragging, isResizing, isDateSelecting) {
640
+ const { props, context, segHeightRefMap } = this;
641
+ const { isRtl } = context;
642
+ const { colWidth, eventSelection } = props;
643
+ const colCnt = props.cells.length;
644
+ const defaultDisplayEventEnd = props.cells.length === 1;
645
+ const isMirror = isDragging || isResizing || isDateSelecting;
646
+ const nodes = [];
647
+ for (const seg of segs) {
648
+ const { left, right, width } = computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl);
649
+ // TODO: optimize ID creation? all related
650
+ const { eventRange } = seg;
651
+ const { instanceId } = eventRange.instance;
652
+ const segSpanId = getSegSpanId(seg);
653
+ const segStartId = getSegStartId(seg);
654
+ const top = segTops[segStartId];
655
+ const isVisible = !seg.isStandin &&
656
+ top != null &&
657
+ !forcedInvisibleMap[instanceId];
658
+ /*
659
+ TODO: is this comment still relevant? vvvvvvvv
660
+ known bug: events that are force to be list-item but span multiple days still take up space in later columns
661
+ todo: in print view, for multi-day events, don't display title within non-start/end segs
662
+ */
663
+ nodes.push(preact_cjs.createElement(DayGridEventHarness, { key: segSpanId, style: {
664
+ visibility: isVisible ? '' : 'hidden',
665
+ top,
666
+ left,
667
+ right,
668
+ width,
669
+ }, heightRef: (isMirror || seg.isStandin)
670
+ ? null
671
+ : segHeightRefMap.createRef(segSpanId) }, hasListItemDisplay(seg) ? (preact_cjs.createElement(DayGridListEvent, Object.assign({ eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: isDragging, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, internal_cjs.getEventRangeMeta(eventRange, todayRange)))) : (preact_cjs.createElement(DayGridBlockEvent, Object.assign({ eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, internal_cjs.getEventRangeMeta(eventRange, todayRange))))));
672
+ }
673
+ return nodes;
552
674
  }
553
- componentDidMount() {
554
- this.updateSizing(true);
555
- this.context.addResizeHandler(this.handleResize);
675
+ renderFillSegs(segs, fillType) {
676
+ const { props, context } = this;
677
+ const { isRtl } = context;
678
+ const { todayRange, colWidth } = props;
679
+ const colCnt = props.cells.length;
680
+ const nodes = [];
681
+ for (const seg of segs) {
682
+ const { left, right, width } = computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl);
683
+ const isVisible = !seg.isStandin;
684
+ nodes.push(preact_cjs.createElement("div", { key: internal_cjs.buildEventRangeKey(seg.eventRange), className: "fc-fill-y", style: {
685
+ visibility: isVisible ? '' : 'hidden',
686
+ left,
687
+ right,
688
+ width,
689
+ } }, fillType === 'bg-event' ?
690
+ preact_cjs.createElement(internal_cjs.BgEvent, Object.assign({ eventRange: seg.eventRange, isStart: seg.isStart, isEnd: seg.isEnd }, internal_cjs.getEventRangeMeta(seg.eventRange, todayRange))) : (internal_cjs.renderFill(fillType))));
691
+ }
692
+ return preact_cjs.createElement(preact_cjs.Fragment, {}, ...nodes);
556
693
  }
557
- componentDidUpdate(prevProps, prevState) {
558
- let currentProps = this.props;
559
- this.updateSizing(!internal_cjs.isPropsEqual(prevProps, currentProps));
694
+ // Sizing
695
+ // -----------------------------------------------------------------------------------------------
696
+ componentDidMount() {
697
+ const { rootEl } = this; // TODO: make dynamic with useEffect
698
+ this.disconnectHeight = internal_cjs.watchHeight(rootEl, (contentHeight) => {
699
+ internal_cjs.setRef(this.props.heightRef, contentHeight);
700
+ });
560
701
  }
561
702
  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;
703
+ this.disconnectHeight();
704
+ internal_cjs.setRef(this.props.heightRef, null);
705
+ internal_cjs.setRef(this.props.innerHeightRef, null);
573
706
  }
707
+ // Utils
708
+ // -----------------------------------------------------------------------------------------------
574
709
  getMirrorSegs() {
575
710
  let { props } = this;
576
711
  if (props.eventResize && props.eventResize.segs.length) { // messy check
@@ -578,420 +713,488 @@ class TableRow extends internal_cjs.DateComponent {
578
713
  }
579
714
  return [];
580
715
  }
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);
716
+ getHighlightSegs() {
717
+ let { props } = this;
718
+ if (props.eventDrag && props.eventDrag.segs.length) { // messy check
719
+ return props.eventDrag.segs;
680
720
  }
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;
721
+ if (props.eventResize && props.eventResize.segs.length) { // messy check
722
+ return props.eventResize.segs;
715
723
  }
724
+ return props.dateSelectionSegs;
716
725
  }
717
- return topsByInstanceId;
718
726
  }
719
727
 
720
- class TableRows extends internal_cjs.DateComponent {
728
+ class DayGridRows extends internal_cjs.DateComponent {
721
729
  constructor() {
722
730
  super(...arguments);
731
+ // memo
723
732
  this.splitBusinessHourSegs = internal_cjs.memoize(splitSegsByRow);
724
733
  this.splitBgEventSegs = internal_cjs.memoize(splitSegsByRow);
725
734
  this.splitFgEventSegs = internal_cjs.memoize(splitSegsByRow);
726
735
  this.splitDateSelectionSegs = internal_cjs.memoize(splitSegsByRow);
727
736
  this.splitEventDrag = internal_cjs.memoize(splitInteractionByRow);
728
737
  this.splitEventResize = internal_cjs.memoize(splitInteractionByRow);
729
- this.rowRefs = new internal_cjs.RefMap();
738
+ // internal
739
+ this.rowHeightRefMap = new internal_cjs.RefMap((height, key) => {
740
+ // HACKy way of syncing RefMap results with prop
741
+ const { rowHeightRefMap } = this.props;
742
+ if (rowHeightRefMap) {
743
+ rowHeightRefMap.handleValue(height, key);
744
+ }
745
+ });
746
+ this.handleRootEl = (rootEl) => {
747
+ this.rootEl = rootEl;
748
+ if (rootEl) {
749
+ this.context.registerInteractiveComponent(this, {
750
+ el: rootEl,
751
+ isHitComboAllowed: this.props.isHitComboAllowed,
752
+ });
753
+ }
754
+ else {
755
+ this.context.unregisterInteractiveComponent(this);
756
+ }
757
+ };
730
758
  }
731
759
  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);
760
+ let { props, state, context, rowHeightRefMap } = this;
761
+ let { options } = context;
762
+ let rowCnt = props.cellRows.length;
736
763
  let fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, rowCnt);
764
+ let bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, rowCnt);
765
+ let businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, rowCnt);
737
766
  let dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, rowCnt);
738
767
  let eventDragByRow = this.splitEventDrag(props.eventDrag, rowCnt);
739
768
  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 })))))));
769
+ // whether the ROW should expand in height
770
+ // (not to be confused with whether the fg events within the row should be molded by height of row)
771
+ let isHeightAuto = internal_cjs.getIsHeightAuto(options);
772
+ // maintain at least aspectRatio for cells?
773
+ let rowMinHeight = (state.width != null && (rowCnt >= 7 || // TODO: better way to infer if across single-month boundary
774
+ isHeightAuto)) ? state.width / context.options.aspectRatio / 6 // okay to hardcode 6 (weeks) ?
775
+ : null;
776
+ return (preact_cjs.createElement("div", { className: 'fc-grow fc-flex-column', style: { width: props.width }, ref: this.handleRootEl }, props.cellRows.map((cells, row) => (preact_cjs.createElement(DayGridRow, { key: cells[0].key, dateProfile: props.dateProfile, todayRange: props.todayRange, cells: cells, showDayNumbers: rowCnt > 1, showWeekNumbers: options.weekNumbers, forPrint: props.forPrint, compact: state.width != null && (state.width / cells.length) < COMPACT_CELL_WIDTH,
777
+ // if not auto-height, distribute height of container somewhat evently to rows
778
+ // (treat all as zero, distribute height, then ensure min-heights -- the inner content height)
779
+ className: isHeightAuto ? '' : 'fc-grow fc-basis0',
780
+ // content
781
+ fgEventSegs: fgEventSegsByRow[row], bgEventSegs: bgEventSegsByRow[row].filter(isSegAllDay) /* HACK */, businessHourSegs: businessHourSegsByRow[row], dateSelectionSegs: dateSelectionSegsByRow[row], eventSelection: props.eventSelection, eventDrag: eventDragByRow[row], eventResize: eventResizeByRow[row], dayMaxEvents: options.dayMaxEvents, dayMaxEventRows: options.dayMaxEventRows,
782
+ // dimensions
783
+ colWidth: props.colWidth, minHeight: rowMinHeight,
784
+ // refs
785
+ heightRef: rowHeightRefMap.createRef(cells[0].key) })))));
749
786
  }
750
787
  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
- }
788
+ this.detachWidth = internal_cjs.watchWidth(this.rootEl, (width) => {
789
+ this.setState({ width });
790
+ });
771
791
  }
772
792
  componentWillUnmount() {
773
- if (this.rootEl) {
774
- this.context.unregisterInteractiveComponent(this);
775
- this.rootEl = null;
776
- }
793
+ this.detachWidth();
777
794
  }
778
795
  // 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 };
796
+ // -----------------------------------------------------------------------------------------------
797
+ queryHit(positionLeft, positionTop, elWidth) {
798
+ const { props, context } = this;
799
+ const colCnt = props.cellRows[0].length;
800
+ const { col, left, right } = computeColFromPosition(positionLeft, elWidth, props.colWidth, colCnt, context.isRtl);
801
+ const { row, top, bottom } = computeRowFromPosition(positionTop, props.cellRows, this.rowHeightRefMap.current);
802
+ const cell = props.cellRows[row][col];
803
+ const cellStartDate = cell.date;
804
+ const cellEndDate = internal_cjs.addDays(cellStartDate, 1);
805
+ return {
806
+ dateProfile: props.dateProfile,
807
+ dateSpan: Object.assign({ range: {
808
+ start: cellStartDate,
809
+ end: cellEndDate,
810
+ }, allDay: true }, cell.extraDateSpan),
811
+ // HACK. TODO: This is expensive to do every hit-query
812
+ dayEl: getCellEl(getRowEl(this.rootEl, row), col),
813
+ rect: {
814
+ left,
815
+ right,
816
+ top,
817
+ bottom,
818
+ },
819
+ layer: 0,
820
+ };
815
821
  }
816
822
  }
823
+ // Utils
824
+ // -------------------------------------------------------------------------------------------------
817
825
  function isSegAllDay(seg) {
818
826
  return seg.eventRange.def.allDay;
819
827
  }
820
828
 
821
- class Table extends internal_cjs.DateComponent {
829
+ class HeaderRow extends internal_cjs.BaseComponent {
830
+ render() {
831
+ const { props } = this;
832
+ return (preact_cjs.createElement("div", { role: props.cellGroup ? undefined : 'row', className: [
833
+ props.cellGroup ? 'fc-flex-row' : 'fc-row',
834
+ props.className || '',
835
+ ].join(' ') }, props.cells.map((cell) => (preact_cjs.createElement(preact_cjs.Fragment, { key: props.getHeaderModelKey(cell) }, props.renderHeaderContent(cell, props.tierNum, undefined, // innerHeightRef
836
+ props.colWidth))))));
837
+ }
838
+ }
839
+
840
+ function DayGridHeader(props) {
841
+ return (preact_cjs.createElement("div", { className: [
842
+ 'fc-rowgroup',
843
+ 'fc-content-box',
844
+ ...(props.extraClassNames || []),
845
+ ].join(' '), style: {
846
+ width: props.width,
847
+ paddingLeft: props.paddingLeft,
848
+ paddingRight: props.paddingRight,
849
+ } }, props.headerTiers.map((cells, tierNum) => (preact_cjs.createElement(HeaderRow, { key: tierNum, tierNum: tierNum, cells: cells, renderHeaderContent: props.renderHeaderContent, getHeaderModelKey: props.getHeaderModelKey, colWidth: props.colWidth })))));
850
+ }
851
+
852
+ class DayGridLayoutNormal extends internal_cjs.BaseComponent {
822
853
  constructor() {
823
854
  super(...arguments);
824
- this.elRef = preact_cjs.createRef();
825
- this.needsScrollReset = false;
855
+ this.handleScroller = (scroller) => {
856
+ internal_cjs.setRef(this.props.scrollerRef, scroller);
857
+ };
858
+ this.handleLeftScrollbarWidth = (leftScrollbarWidth) => {
859
+ this.setState({ leftScrollbarWidth });
860
+ };
861
+ this.handleRightScrollbarWidth = (rightScrollbarWidth) => {
862
+ this.setState({ rightScrollbarWidth });
863
+ };
826
864
  }
827
865
  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 })))));
866
+ const { props, state, context } = this;
867
+ const { options } = context;
868
+ const verticalScrollbars = !props.forPrint && !internal_cjs.getIsHeightAuto(options);
869
+ const stickyHeaderDates = !props.forPrint && internal_cjs.getStickyHeaderDates(options);
870
+ return (preact_cjs.createElement(preact_cjs.Fragment, null,
871
+ options.dayHeaders && (preact_cjs.createElement(DayGridHeader, { headerTiers: props.headerTiers, renderHeaderContent: props.renderHeaderContent, getHeaderModelKey: props.getHeaderModelKey,
872
+ // render hooks
873
+ extraClassNames: [
874
+ 'fc-daygrid-header',
875
+ stickyHeaderDates ? 'fc-sticky-header' : '',
876
+ ],
877
+ // dimensions
878
+ paddingLeft: state.leftScrollbarWidth, paddingRight: state.rightScrollbarWidth })),
879
+ preact_cjs.createElement(internal_cjs.Scroller, { vertical: verticalScrollbars, leftScrollbarWidthRef: this.handleLeftScrollbarWidth, rightScrollbarWidthRef: this.handleRightScrollbarWidth, elClassNames: [
880
+ 'fc-daygrid-body',
881
+ 'fc-rowgroup',
882
+ 'fc-flex-column',
883
+ verticalScrollbars ? 'fc-liquid' : '',
884
+ ], ref: this.handleScroller },
885
+ preact_cjs.createElement(DayGridRows // .fc-grow
886
+ , { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: props.cellRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed,
887
+ // content
888
+ fgEventSegs: props.fgEventSegs, bgEventSegs: props.bgEventSegs, businessHourSegs: props.businessHourSegs, dateSelectionSegs: props.dateSelectionSegs, eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
889
+ // refs
890
+ rowHeightRefMap: props.rowHeightRefMap }))));
857
891
  }
858
- componentDidMount() {
859
- this.requestScrollReset();
892
+ }
893
+
894
+ class DayGridLayoutPannable extends internal_cjs.BaseComponent {
895
+ constructor() {
896
+ super(...arguments);
897
+ this.headerScrollerRef = preact_cjs.createRef();
898
+ this.bodyScrollerRef = preact_cjs.createRef();
899
+ this.footerScrollerRef = preact_cjs.createRef();
900
+ // Sizing
901
+ // -----------------------------------------------------------------------------------------------
902
+ this.handleWidth = (width) => {
903
+ this.setState({ width });
904
+ };
905
+ this.handleLeftScrollbarWidth = (leftScrollbarWidth) => {
906
+ this.setState({ leftScrollbarWidth });
907
+ };
908
+ this.handleRightScrollbarWidth = (rightScrollbarWidth) => {
909
+ this.setState({ rightScrollbarWidth });
910
+ };
860
911
  }
861
- componentDidUpdate(prevProps) {
862
- if (prevProps.dateProfile !== this.props.dateProfile) {
863
- this.requestScrollReset();
864
- }
865
- else {
866
- this.flushScrollReset();
867
- }
912
+ render() {
913
+ const { props, state, context } = this;
914
+ const { options } = context;
915
+ const verticalScrollbars = !props.forPrint && !internal_cjs.getIsHeightAuto(options);
916
+ const stickyHeaderDates = !props.forPrint && internal_cjs.getStickyHeaderDates(options);
917
+ const stickyFooterScrollbar = !props.forPrint && internal_cjs.getStickyFooterScrollbar(options);
918
+ const colCnt = props.cellRows[0].length;
919
+ const [canvasWidth, colWidth] = computeColWidth(colCnt, props.dayMinWidth, state.width);
920
+ return (preact_cjs.createElement(preact_cjs.Fragment, null,
921
+ options.dayHeaders && (preact_cjs.createElement(internal_cjs.Scroller, { horizontal: true, hideScrollbars: true, elClassNames: [
922
+ 'fc-daygrid-header',
923
+ 'fc-rowgroup',
924
+ stickyHeaderDates ? 'fc-sticky-header' : ''
925
+ ], ref: this.headerScrollerRef },
926
+ preact_cjs.createElement(DayGridHeader, { headerTiers: props.headerTiers, renderHeaderContent: props.renderHeaderContent, getHeaderModelKey: props.getHeaderModelKey,
927
+ // dimensions
928
+ colWidth: colWidth, width: canvasWidth, paddingLeft: state.leftScrollbarWidth, paddingRight: state.rightScrollbarWidth }))),
929
+ preact_cjs.createElement(internal_cjs.Scroller, { vertical: verticalScrollbars, horizontal: true, hideScrollbars: stickyFooterScrollbar, widthRef: this.handleWidth, leftScrollbarWidthRef: this.handleLeftScrollbarWidth, rightScrollbarWidthRef: this.handleRightScrollbarWidth, elClassNames: [
930
+ 'fc-daygrid-body',
931
+ 'fc-rowgroup',
932
+ 'fc-flex-column',
933
+ verticalScrollbars ? 'fc-liquid' : '',
934
+ ], ref: this.bodyScrollerRef },
935
+ preact_cjs.createElement(DayGridRows // .fc-grow
936
+ , { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: props.cellRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed,
937
+ // content
938
+ fgEventSegs: props.fgEventSegs, bgEventSegs: props.bgEventSegs, businessHourSegs: props.businessHourSegs, dateSelectionSegs: props.dateSelectionSegs, eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
939
+ // dimensions
940
+ colWidth: colWidth, width: canvasWidth,
941
+ // refs
942
+ rowHeightRefMap: props.rowHeightRefMap })),
943
+ Boolean(stickyFooterScrollbar) && (preact_cjs.createElement(internal_cjs.Scroller, { ref: this.footerScrollerRef, horizontal: true, elClassNames: ['fc-sticky-footer'], elStyle: {
944
+ marginTop: '-1px', // HACK
945
+ } },
946
+ preact_cjs.createElement("div", { style: {
947
+ width: canvasWidth,
948
+ height: '1px', // HACK
949
+ } })))));
868
950
  }
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
- }
951
+ // Lifecycle
952
+ // -----------------------------------------------------------------------------------------------
953
+ componentDidMount() {
954
+ // scroller
955
+ const ScrollerSyncer = internal_cjs.getScrollerSyncerClass(this.context.pluginHooks);
956
+ this.syncedScroller = new ScrollerSyncer(true); // horizontal=true
957
+ internal_cjs.setRef(this.props.scrollerRef, this.syncedScroller);
958
+ this.updateSyncedScroller();
887
959
  }
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...
960
+ componentDidUpdate() {
961
+ // scroller
962
+ this.updateSyncedScroller();
894
963
  }
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
964
+ componentWillUnmount() {
965
+ // scroller
966
+ this.syncedScroller.destroy();
967
+ }
968
+ // Scrolling
969
+ // -----------------------------------------------------------------------------------------------
970
+ updateSyncedScroller() {
971
+ this.syncedScroller.handleChildren([
972
+ this.headerScrollerRef.current,
973
+ this.bodyScrollerRef.current,
974
+ this.footerScrollerRef.current,
975
+ ]);
898
976
  }
899
- return el;
900
977
  }
901
978
 
902
- class DayTableSlicer extends internal_cjs.Slicer {
979
+ class DayGridLayout extends internal_cjs.BaseComponent {
903
980
  constructor() {
904
981
  super(...arguments);
905
- this.forceDayIfListItem = true;
982
+ // ref
983
+ this.scrollerRef = preact_cjs.createRef();
984
+ this.rowHeightRefMap = new internal_cjs.RefMap(() => {
985
+ internal_cjs.afterSize(this.updateScrollY);
986
+ });
987
+ // internal
988
+ this.scrollDate = null;
989
+ this.updateScrollY = () => {
990
+ const rowHeightMap = this.rowHeightRefMap.current;
991
+ const scroller = this.scrollerRef.current;
992
+ // Since updateScrollY is called by rowHeightRefMap, could be called with null during cleanup,
993
+ // and the scroller might not exist
994
+ if (scroller && this.scrollDate) {
995
+ let scrollTop = computeTopFromDate(this.scrollDate, this.props.cellRows, rowHeightMap, 1);
996
+ if (scrollTop != null) {
997
+ if (scrollTop) {
998
+ scrollTop++; // clear top border
999
+ }
1000
+ scroller.scrollTo({ y: scrollTop });
1001
+ }
1002
+ }
1003
+ };
1004
+ this.clearScroll = () => {
1005
+ this.scrollDate = null;
1006
+ };
906
1007
  }
907
- sliceRange(dateRange, dayTableModel) {
908
- return dayTableModel.sliceRange(dateRange);
1008
+ render() {
1009
+ const { props, context } = this;
1010
+ const { options } = context;
1011
+ const commonLayoutProps = Object.assign(Object.assign({}, props), { scrollerRef: this.scrollerRef, rowHeightRefMap: this.rowHeightRefMap });
1012
+ return (preact_cjs.createElement(internal_cjs.ViewContainer, { viewSpec: context.viewSpec, elClasses: [props.className, 'fc-flex-column', 'fc-border'] }, options.dayMinWidth ? (preact_cjs.createElement(DayGridLayoutPannable, Object.assign({}, commonLayoutProps, { dayMinWidth: options.dayMinWidth }))) : (preact_cjs.createElement(DayGridLayoutNormal, Object.assign({}, commonLayoutProps)))));
1013
+ }
1014
+ // Lifecycle
1015
+ // -----------------------------------------------------------------------------------------------
1016
+ componentDidMount() {
1017
+ this.resetScroll();
1018
+ this.scrollerRef.current.addScrollEndListener(this.clearScroll);
1019
+ }
1020
+ componentDidUpdate(prevProps) {
1021
+ if (prevProps.dateProfile !== this.props.dateProfile && this.context.options.scrollTimeReset) {
1022
+ this.resetScroll();
1023
+ }
1024
+ }
1025
+ componentWillUnmount() {
1026
+ this.scrollerRef.current.removeScrollEndListener(this.clearScroll);
1027
+ }
1028
+ // Scrolling
1029
+ // -----------------------------------------------------------------------------------------------
1030
+ resetScroll() {
1031
+ this.scrollDate = this.props.dateProfile.currentDate;
1032
+ this.updateScrollY();
1033
+ // updateScrollX
1034
+ const scroller = this.scrollerRef.current;
1035
+ scroller.scrollTo({ x: 0 });
909
1036
  }
910
1037
  }
911
1038
 
912
- class DayTable extends internal_cjs.DateComponent {
1039
+ const WEEKDAY_FORMAT = internal_cjs.createFormatter({ weekday: 'long' });
1040
+ class DayOfWeekHeaderCell extends internal_cjs.BaseComponent {
913
1041
  constructor() {
914
1042
  super(...arguments);
915
- this.slicer = new DayTableSlicer();
916
- this.tableRef = preact_cjs.createRef();
1043
+ // ref
1044
+ this.innerElRef = preact_cjs.createRef();
917
1045
  }
918
1046
  render() {
919
1047
  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 })));
1048
+ let { dateEnv, theme, viewApi, options } = context;
1049
+ let date = internal_cjs.addDays(new Date(259200000), props.dow); // start with Sun, 04 Jan 1970 00:00:00 GMT
1050
+ let dateMeta = {
1051
+ dow: props.dow,
1052
+ isDisabled: false,
1053
+ isFuture: false,
1054
+ isPast: false,
1055
+ isToday: false,
1056
+ isOther: false,
1057
+ };
1058
+ let text = dateEnv.format(date, props.dayHeaderFormat);
1059
+ let renderProps = Object.assign(Object.assign(Object.assign(Object.assign({ date }, dateMeta), { view: viewApi }), props.extraRenderProps), { text });
1060
+ return (preact_cjs.createElement(internal_cjs.ContentContainer, { elTag: 'div', elClasses: [
1061
+ ...internal_cjs.getDayClassNames(dateMeta, theme),
1062
+ ...(props.extraClassNames || []),
1063
+ 'fc-header-cell',
1064
+ 'fc-cell',
1065
+ props.colWidth != null ? '' : 'fc-liquid',
1066
+ 'fc-flex-column',
1067
+ 'fc-align-center',
1068
+ ], elAttrs: props.extraDataAttrs, elStyle: {
1069
+ width: props.colWidth != null // TODO: DRY
1070
+ ? props.colWidth * (props.colSpan || 1)
1071
+ : undefined,
1072
+ }, renderProps: renderProps, generatorName: "dayHeaderContent", customGenerator: options.dayHeaderContent, defaultGenerator: renderInner, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount }, (InnerContent) => (preact_cjs.createElement("div", { ref: this.innerElRef, className: [
1073
+ 'fc-flex-column',
1074
+ props.isSticky ? 'fc-sticky-x' : '',
1075
+ ].join(' ') },
1076
+ preact_cjs.createElement(InnerContent, { elTag: "a", elClasses: [
1077
+ 'fc-cell-inner',
1078
+ 'fc-padding-sm',
1079
+ ], elAttrs: {
1080
+ 'aria-label': dateEnv.format(date, WEEKDAY_FORMAT),
1081
+ } })))));
1082
+ }
1083
+ componentDidMount() {
1084
+ const innerEl = this.innerElRef.current; // TODO: make dynamic with useEffect
1085
+ // TODO: only attach this if refs props present
1086
+ this.disconectInnerHeight = internal_cjs.watchHeight(innerEl, (height) => {
1087
+ internal_cjs.setRef(this.props.innerHeightRef, height);
1088
+ });
1089
+ }
1090
+ componentWillUnmount() {
1091
+ this.disconectInnerHeight();
1092
+ internal_cjs.setRef(this.props.innerHeightRef, null);
921
1093
  }
922
1094
  }
923
1095
 
924
- class DayTableView extends TableView {
1096
+ function createDayHeaderFormatter(explicitFormat, datesRepDistinctDays, dateCnt) {
1097
+ return explicitFormat || computeFallbackHeaderFormat(datesRepDistinctDays, dateCnt);
1098
+ }
1099
+ // Computes a default column header formatting string if `colFormat` is not explicitly defined
1100
+ function computeFallbackHeaderFormat(datesRepDistinctDays, dayCnt) {
1101
+ // if more than one week row, or if there are a lot of columns with not much space,
1102
+ // put just the day numbers will be in each cell
1103
+ if (!datesRepDistinctDays || dayCnt > 10) {
1104
+ return internal_cjs.createFormatter({ weekday: 'short' }); // "Sat"
1105
+ }
1106
+ if (dayCnt > 1) {
1107
+ return internal_cjs.createFormatter({ weekday: 'short', month: 'numeric', day: 'numeric', omitCommas: true }); // "Sat 11/12"
1108
+ }
1109
+ return internal_cjs.createFormatter({ weekday: 'long' }); // "Saturday"
1110
+ }
1111
+
1112
+ class DayGridView extends internal_cjs.BaseComponent {
925
1113
  constructor() {
926
1114
  super(...arguments);
1115
+ // memo
927
1116
  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
1117
+ this.buildHeaderTiers = internal_cjs.memoize(buildHeaderTiers);
1118
+ this.createDayHeaderFormatter = internal_cjs.memoize(createDayHeaderFormatter);
1119
+ // internal
1120
+ this.slicer = new DayTableSlicer();
931
1121
  }
932
1122
  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);
1123
+ const { props, context } = this;
1124
+ const { options } = context;
1125
+ const dayTableModel = this.buildDayTableModel(props.dateProfile, context.dateProfileGenerator);
1126
+ const datesRepDistinctDays = dayTableModel.rowCnt === 1;
1127
+ const headerTiers = this.buildHeaderTiers(dayTableModel.headerDates, datesRepDistinctDays);
1128
+ const slicedProps = this.slicer.sliceProps(props, props.dateProfile, options.nextDayThreshold, context, dayTableModel);
1129
+ const dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, datesRepDistinctDays, dayTableModel.colCnt);
1130
+ return (preact_cjs.createElement(internal_cjs.NowTimer, { unit: "day" }, (nowDate, todayRange) => (preact_cjs.createElement(DayGridLayout, { dateProfile: props.dateProfile, todayRange: todayRange, cellRows: dayTableModel.cellRows, forPrint: props.forPrint, className: 'fc-daygrid-view',
1131
+ // header content
1132
+ headerTiers: headerTiers, renderHeaderContent: (model, tier, innerHeightRef, colWidth) => {
1133
+ if (model.date) {
1134
+ return (preact_cjs.createElement(DateHeaderCell, Object.assign({}, model, { dateProfile: props.dateProfile, todayRange: todayRange, navLink: dayTableModel.colCnt > 1, dayHeaderFormat: dayHeaderFormat, colSpan: model.colSpan, colWidth: colWidth })));
1135
+ }
1136
+ else {
1137
+ return (preact_cjs.createElement(DayOfWeekHeaderCell, Object.assign({}, model, { dayHeaderFormat: dayHeaderFormat, colSpan: model.colSpan, colWidth: colWidth })));
1138
+ }
1139
+ }, getHeaderModelKey: (model) => {
1140
+ // can use model.key???
1141
+ if (model.date) {
1142
+ return model.date.toUTCString();
1143
+ }
1144
+ return model.dow;
1145
+ },
1146
+ // body content
1147
+ fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection }))));
941
1148
  }
942
1149
  }
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
1150
 
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,
1151
+ /*
1152
+ TODO: is it even worth doing this "advanced" version?
1153
+ */
1154
+ class HeaderRowAdvanced extends internal_cjs.BaseComponent {
1155
+ constructor() {
1156
+ super(...arguments);
1157
+ // ref
1158
+ this.innerHeightRefMap = new internal_cjs.RefMap(() => {
1159
+ internal_cjs.afterSize(this.handleInnerHeights);
958
1160
  });
1161
+ this.handleInnerHeights = () => {
1162
+ const innerHeightMap = this.innerHeightRefMap.current;
1163
+ let max = 0;
1164
+ for (const innerHeight of innerHeightMap.values()) {
1165
+ max = Math.max(max, innerHeight);
1166
+ }
1167
+ if (this.currentInnerHeight !== max) {
1168
+ this.currentInnerHeight = max;
1169
+ internal_cjs.setRef(this.props.innerHeightRef, max);
1170
+ }
1171
+ };
959
1172
  }
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);
1173
+ render() {
1174
+ const { props } = this;
1175
+ return (preact_cjs.createElement("div", { role: 'row', className: 'fc-row', style: { height: props.height } }, props.cells.map((cell) => {
1176
+ const key = props.getHeaderModelKey(cell);
1177
+ return (preact_cjs.createElement(preact_cjs.Fragment, { key: props.getHeaderModelKey(cell) }, props.renderHeaderContent(cell, props.tierNum, this.innerHeightRefMap.createRef(key), // innerHeightRef
1178
+ props.colWidth)));
1179
+ })));
982
1180
  }
983
- return { start, end };
984
1181
  }
985
1182
 
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;
1183
+ exports.COMPACT_CELL_WIDTH = COMPACT_CELL_WIDTH;
1184
+ exports.DateHeaderCell = DateHeaderCell;
1185
+ exports.DayGridLayout = DayGridLayout;
1186
+ exports.DayGridRow = DayGridRow;
1187
+ exports.DayGridRows = DayGridRows;
1188
+ exports.DayGridView = DayGridView;
1189
+ exports.DayOfWeekHeaderCell = DayOfWeekHeaderCell;
991
1190
  exports.DayTableSlicer = DayTableSlicer;
992
- exports.Table = Table;
1191
+ exports.HeaderRow = HeaderRow;
1192
+ exports.HeaderRowAdvanced = HeaderRowAdvanced;
993
1193
  exports.TableDateProfileGenerator = TableDateProfileGenerator;
994
- exports.TableRows = TableRows;
995
- exports.TableView = TableView;
996
1194
  exports.buildDayTableModel = buildDayTableModel;
997
1195
  exports.buildDayTableRenderRange = buildDayTableRenderRange;
1196
+ exports.computeColFromPosition = computeColFromPosition;
1197
+ exports.computeColWidth = computeColWidth;
1198
+ exports.createDayHeaderFormatter = createDayHeaderFormatter;
1199
+ exports.getCellEl = getCellEl;
1200
+ exports.getRowEl = getRowEl;