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