@fullcalendar/daygrid 7.0.0-beta.4 → 7.0.0-beta.5
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/LICENSE.md +1 -1
- package/README.md +6 -1
- package/{index.cjs → cjs/index.cjs} +15 -4
- package/cjs/internal.cjs +1339 -0
- package/esm/index.d.ts +23 -0
- package/{index.js → esm/index.js} +14 -3
- package/{internal.d.ts → esm/internal.d.ts} +49 -31
- package/{internal.js → esm/internal.js} +397 -272
- package/{index.global.js → global.js} +412 -273
- package/global.min.js +6 -0
- package/package.json +22 -19
- package/index.d.ts +0 -6
- package/index.global.min.js +0 -6
- package/internal.cjs +0 -1208
package/cjs/internal.cjs
ADDED
|
@@ -0,0 +1,1339 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var internal = require('@fullcalendar/core/internal');
|
|
6
|
+
var preact = require('@fullcalendar/core/preact');
|
|
7
|
+
var core = require('@fullcalendar/core');
|
|
8
|
+
var classNames = require('@fullcalendar/core/internal-classnames');
|
|
9
|
+
|
|
10
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
11
|
+
|
|
12
|
+
var classNames__default = /*#__PURE__*/_interopDefaultLegacy(classNames);
|
|
13
|
+
|
|
14
|
+
class DayTableSlicer extends internal.Slicer {
|
|
15
|
+
constructor() {
|
|
16
|
+
super(...arguments);
|
|
17
|
+
this.forceDayIfListItem = true;
|
|
18
|
+
}
|
|
19
|
+
sliceRange(dateRange, dayTableModel) {
|
|
20
|
+
return dayTableModel.sliceRange(dateRange);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// TODO: converge types with DayTableCell and DayCellContainer (the component) and refineRenderProps
|
|
25
|
+
// the generation of DayTableCell will be distinct (for the BODY cells)
|
|
26
|
+
// but can share some of the same types/utils
|
|
27
|
+
// Date Cells
|
|
28
|
+
// -------------------------------------------------------------------------------------------------
|
|
29
|
+
const firstSunday = new Date(259200000);
|
|
30
|
+
function buildDateRowConfigs(dates, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, // TODO: rename to dateHeaderFormat?
|
|
31
|
+
context) {
|
|
32
|
+
const rowConfig = buildDateRowConfig(dates, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, context);
|
|
33
|
+
const majorUnit = internal.computeMajorUnit(dateProfile, context.dateEnv);
|
|
34
|
+
// HACK mutate isMajor
|
|
35
|
+
if (datesRepDistinctDays) {
|
|
36
|
+
for (const dataConfig of rowConfig.dataConfigs) {
|
|
37
|
+
if (internal.isMajorUnit(dataConfig.dateMarker, majorUnit, context.dateEnv)) {
|
|
38
|
+
dataConfig.renderProps.isMajor = true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return [rowConfig];
|
|
43
|
+
}
|
|
44
|
+
/*
|
|
45
|
+
Should this receive resource data attributes?
|
|
46
|
+
Or ResourceApi object itself?
|
|
47
|
+
*/
|
|
48
|
+
function buildDateRowConfig(dateMarkers, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, // TODO: rename to dateHeaderFormat?
|
|
49
|
+
context, colSpan, isMajorMod) {
|
|
50
|
+
return {
|
|
51
|
+
isDateRow: true,
|
|
52
|
+
renderConfig: buildDateRenderConfig(context),
|
|
53
|
+
dataConfigs: buildDateDataConfigs(dateMarkers, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, context, colSpan, undefined, undefined, undefined, undefined, isMajorMod)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/*
|
|
57
|
+
For header cells: how to connect w/ custom rendering
|
|
58
|
+
Applies to all cells in a row
|
|
59
|
+
*/
|
|
60
|
+
function buildDateRenderConfig(context) {
|
|
61
|
+
const { options } = context;
|
|
62
|
+
return {
|
|
63
|
+
generatorName: 'dayHeaderContent',
|
|
64
|
+
customGenerator: options.dayHeaderContent,
|
|
65
|
+
classNameGenerator: options.dayHeaderClass,
|
|
66
|
+
innerClassNameGenerator: options.dayHeaderInnerClass,
|
|
67
|
+
didMount: options.dayHeaderDidMount,
|
|
68
|
+
willUnmount: options.dayHeaderWillUnmount,
|
|
69
|
+
align: options.dayHeaderAlign,
|
|
70
|
+
sticky: options.dayHeaderSticky,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const dowDates = [];
|
|
74
|
+
for (let dow = 0; dow < 7; dow++) {
|
|
75
|
+
dowDates.push(internal.addDays(new Date(259200000), dow)); // start with Sun, 04 Jan 1970 00:00:00 GMT)
|
|
76
|
+
}
|
|
77
|
+
/*
|
|
78
|
+
For header cells: data
|
|
79
|
+
*/
|
|
80
|
+
function buildDateDataConfigs(dateMarkers, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, // TODO: rename to dateHeaderFormat?
|
|
81
|
+
context, colSpan = 1, keyPrefix = '', extraRenderProps = {}, // TODO
|
|
82
|
+
extraAttrs = {}, // TODO
|
|
83
|
+
className = '', isMajorMod) {
|
|
84
|
+
const { dateEnv, viewApi, options } = context;
|
|
85
|
+
return datesRepDistinctDays
|
|
86
|
+
? dateMarkers.map((dateMarker, i) => {
|
|
87
|
+
const dateMeta = internal.getDateMeta(dateMarker, dateEnv, dateProfile, todayRange);
|
|
88
|
+
const isMajor = isMajorMod != null && !(i % isMajorMod);
|
|
89
|
+
const [text, textParts] = dateEnv.format(dateMarker, dayHeaderFormat);
|
|
90
|
+
const hasNavLink = options.navLinks && !dateMeta.isDisabled &&
|
|
91
|
+
dateMarkers.length > 1; // don't show navlink to day if only one day
|
|
92
|
+
const renderProps = Object.assign(Object.assign(Object.assign({}, dateMeta), extraRenderProps), { text,
|
|
93
|
+
textParts,
|
|
94
|
+
get weekdayText() { return internal.findWeekdayText(textParts); },
|
|
95
|
+
get dayNumberText() { return datesRepDistinctDays ? internal.findDayNumberText(textParts) : ''; },
|
|
96
|
+
isMajor, isNarrow: false, isSticky: false, inPopover: false, level: 0, // HACK. gets overridden
|
|
97
|
+
hasNavLink, view: viewApi });
|
|
98
|
+
const fullDateStr = internal.buildDateStr(context, dateMarker);
|
|
99
|
+
// for DayGridHeaderCell
|
|
100
|
+
return {
|
|
101
|
+
key: keyPrefix + dateMarker.toUTCString(),
|
|
102
|
+
dateMarker,
|
|
103
|
+
renderProps,
|
|
104
|
+
attrs: Object.assign(Object.assign(Object.assign({ 'aria-label': fullDateStr }, (dateMeta.isToday ? { 'aria-current': 'date' } : {})), { 'data-date': internal.formatDayString(dateMarker) }), extraAttrs),
|
|
105
|
+
// for navlink
|
|
106
|
+
innerAttrs: hasNavLink
|
|
107
|
+
? internal.buildNavLinkAttrs(context, dateMarker, undefined, fullDateStr)
|
|
108
|
+
: { 'aria-hidden': true },
|
|
109
|
+
colSpan,
|
|
110
|
+
hasNavLink,
|
|
111
|
+
className,
|
|
112
|
+
};
|
|
113
|
+
})
|
|
114
|
+
: dateMarkers.map((dateMarker, i) => {
|
|
115
|
+
const dow = dateMarker.getUTCDay();
|
|
116
|
+
const normDate = internal.addDays(firstSunday, dow);
|
|
117
|
+
const dateMeta = {
|
|
118
|
+
date: dateEnv.toDate(dateMarker),
|
|
119
|
+
dow,
|
|
120
|
+
isDisabled: false,
|
|
121
|
+
isFuture: false,
|
|
122
|
+
isPast: false,
|
|
123
|
+
isToday: false,
|
|
124
|
+
isOther: false,
|
|
125
|
+
};
|
|
126
|
+
const isMajor = isMajorMod != null && !(i % isMajorMod);
|
|
127
|
+
const [text, textParts] = dateEnv.format(normDate, dayHeaderFormat);
|
|
128
|
+
const renderProps = Object.assign(Object.assign(Object.assign({}, dateMeta), { date: dowDates[dow], isMajor, isNarrow: false, isSticky: false, inPopover: false, hasNavLink: false, level: 0, view: viewApi, text,
|
|
129
|
+
textParts,
|
|
130
|
+
get weekdayText() { return internal.findWeekdayText(textParts); },
|
|
131
|
+
get dayNumberText() { return datesRepDistinctDays ? internal.findDayNumberText(textParts) : ''; } }), extraRenderProps);
|
|
132
|
+
const fullWeekDayStr = dateEnv.format(normDate, internal.WEEKDAY_ONLY_FORMAT)[0];
|
|
133
|
+
// for DayGridHeaderCell
|
|
134
|
+
return {
|
|
135
|
+
key: keyPrefix + String(dow),
|
|
136
|
+
dateMarker,
|
|
137
|
+
renderProps,
|
|
138
|
+
attrs: Object.assign({ 'aria-label': fullWeekDayStr }, extraAttrs),
|
|
139
|
+
// NOT a navlink
|
|
140
|
+
innerAttrs: {
|
|
141
|
+
'aria-hidden': true, // label already on cell
|
|
142
|
+
},
|
|
143
|
+
colSpan,
|
|
144
|
+
className,
|
|
145
|
+
};
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/*
|
|
150
|
+
We need really specific keys because RefMap::createRef() which is then given to heightRef
|
|
151
|
+
unable to change key! As a result, we cannot reuse elements between normal/slice/standin types,
|
|
152
|
+
but that's okay since they render quite differently
|
|
153
|
+
*/
|
|
154
|
+
function getEventPartKey(seg) {
|
|
155
|
+
return internal.getEventKey(seg) + ':' + seg.start +
|
|
156
|
+
(seg.standinFor ? ':standin' : seg.isSlice ? ':slice' : '');
|
|
157
|
+
}
|
|
158
|
+
// DayGridRange utils (TODO: move)
|
|
159
|
+
// -------------------------------------------------------------------------------------------------
|
|
160
|
+
function splitSegsByRow(segs, rowCount) {
|
|
161
|
+
const byRow = [];
|
|
162
|
+
for (let row = 0; row < rowCount; row++) {
|
|
163
|
+
byRow[row] = [];
|
|
164
|
+
}
|
|
165
|
+
for (const seg of segs) {
|
|
166
|
+
byRow[seg.row].push(seg);
|
|
167
|
+
}
|
|
168
|
+
return byRow;
|
|
169
|
+
}
|
|
170
|
+
function splitInteractionByRow(ui, rowCount) {
|
|
171
|
+
const byRow = [];
|
|
172
|
+
if (!ui) {
|
|
173
|
+
for (let row = 0; row < rowCount; row++) {
|
|
174
|
+
byRow[row] = null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
for (let row = 0; row < rowCount; row++) {
|
|
179
|
+
byRow[row] = {
|
|
180
|
+
affectedInstances: ui.affectedInstances,
|
|
181
|
+
isEvent: ui.isEvent,
|
|
182
|
+
segs: [],
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
for (const seg of ui.segs) {
|
|
186
|
+
byRow[seg.row].segs.push(seg);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return byRow;
|
|
190
|
+
}
|
|
191
|
+
function sliceSegForCol(seg, col) {
|
|
192
|
+
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 });
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const DEFAULT_TABLE_EVENT_TIME_FORMAT = internal.createFormatter({
|
|
196
|
+
hour: 'numeric',
|
|
197
|
+
minute: '2-digit',
|
|
198
|
+
omitZeroMinute: true,
|
|
199
|
+
meridiem: 'narrow',
|
|
200
|
+
});
|
|
201
|
+
function hasListItemDisplay(seg) {
|
|
202
|
+
let { display } = seg.eventRange.ui;
|
|
203
|
+
return display === 'list-item' || (display === 'auto' &&
|
|
204
|
+
!seg.eventRange.def.allDay &&
|
|
205
|
+
(seg.end - seg.start) === 1 && // single-day
|
|
206
|
+
seg.isStart && // "
|
|
207
|
+
seg.isEnd // "
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
class DayGridMoreLink extends internal.BaseComponent {
|
|
212
|
+
render() {
|
|
213
|
+
let { props } = this;
|
|
214
|
+
return (preact.createElement(internal.MoreLinkContainer, { display: 'row', className: props.className, isNarrow: props.isNarrow, isMicro: props.isMicro, dateProfile: props.dateProfile, todayRange: props.todayRange, allDayDate: props.allDayDate, segs: props.segs, hiddenSegs: props.hiddenSegs, alignElRef: props.alignElRef, alignParentTop: props.alignParentTop, dateSpanProps: props.dateSpanProps, popoverContent: () => (preact.createElement(preact.Fragment, null, props.segs.map((seg) => {
|
|
215
|
+
let { eventRange } = seg;
|
|
216
|
+
let { instanceId } = eventRange.instance;
|
|
217
|
+
let isDragging = Boolean(props.eventDrag && props.eventDrag.affectedInstances[instanceId]);
|
|
218
|
+
let isResizing = Boolean(props.eventResize && props.eventResize.affectedInstances[instanceId]);
|
|
219
|
+
let isInvisible = isDragging || isResizing;
|
|
220
|
+
return (preact.createElement("div", { key: instanceId, style: {
|
|
221
|
+
visibility: isInvisible ? 'hidden' : undefined,
|
|
222
|
+
} },
|
|
223
|
+
preact.createElement(internal.StandardEvent, Object.assign({ display: hasListItemDisplay(seg) ? 'list-item' : 'row', eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: isDragging, isResizing: isResizing, isMirror: false, isSelected: instanceId === props.eventSelection, defaultTimeFormat: DEFAULT_TABLE_EVENT_TIME_FORMAT, defaultDisplayEventEnd: false }, internal.getEventRangeMeta(eventRange, props.todayRange)))));
|
|
224
|
+
}))) }));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
class DayGridCell extends internal.DateComponent {
|
|
229
|
+
constructor() {
|
|
230
|
+
super(...arguments);
|
|
231
|
+
// memo
|
|
232
|
+
this.getDateMeta = internal.memoize(internal.getDateMeta);
|
|
233
|
+
this.refineRenderProps = internal.memoizeObjArg(refineRenderProps);
|
|
234
|
+
// ref
|
|
235
|
+
this.rootElRef = preact.createRef();
|
|
236
|
+
this.handleBodyEl = (bodyEl) => {
|
|
237
|
+
if (this.disconnectBodyHeight) {
|
|
238
|
+
this.disconnectBodyHeight();
|
|
239
|
+
this.disconnectBodyHeight = undefined;
|
|
240
|
+
internal.setRef(this.props.headerHeightRef, null);
|
|
241
|
+
internal.setRef(this.props.mainHeightRef, null);
|
|
242
|
+
}
|
|
243
|
+
if (bodyEl) {
|
|
244
|
+
// we want to fire on ANY size change, because we do more advanced stuff
|
|
245
|
+
this.disconnectBodyHeight = internal.watchSize(bodyEl, (_bodyWidth, bodyHeight) => {
|
|
246
|
+
const { props } = this;
|
|
247
|
+
const mainRect = bodyEl.getBoundingClientRect();
|
|
248
|
+
const rootRect = this.rootElRef.current.getBoundingClientRect();
|
|
249
|
+
const headerHeight = mainRect.top - rootRect.top;
|
|
250
|
+
if (!internal.isDimsEqual(this.headerHeight, headerHeight)) {
|
|
251
|
+
this.headerHeight = headerHeight;
|
|
252
|
+
internal.setRef(props.headerHeightRef, headerHeight);
|
|
253
|
+
}
|
|
254
|
+
if (props.fgLiquidHeight) {
|
|
255
|
+
internal.setRef(props.mainHeightRef, bodyHeight);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
render() {
|
|
262
|
+
let { props, context } = this;
|
|
263
|
+
let { options, dateEnv } = context;
|
|
264
|
+
// TODO: memoize this
|
|
265
|
+
const isMonthStart = props.showDayNumber &&
|
|
266
|
+
shouldDisplayMonthStart(props.date, props.dateProfile.currentRange, dateEnv);
|
|
267
|
+
const dateMeta = this.getDateMeta(props.date, dateEnv, props.dateProfile, props.todayRange);
|
|
268
|
+
const baseClassName = core.joinClassNames(props.borderStart ? classNames__default["default"].borderOnlyS : classNames__default["default"].borderNone, props.width != null ? '' : classNames__default["default"].liquid, classNames__default["default"].flexCol);
|
|
269
|
+
const hasNavLink = options.navLinks;
|
|
270
|
+
const renderProps = this.refineRenderProps({
|
|
271
|
+
date: props.date,
|
|
272
|
+
isMajor: props.isMajor,
|
|
273
|
+
isNarrow: props.isNarrow,
|
|
274
|
+
dateMeta: dateMeta,
|
|
275
|
+
hasLabel: props.showDayNumber,
|
|
276
|
+
hasMonthLabel: isMonthStart,
|
|
277
|
+
hasNavLink,
|
|
278
|
+
renderProps: props.renderProps,
|
|
279
|
+
viewApi: context.viewApi,
|
|
280
|
+
dateEnv: context.dateEnv,
|
|
281
|
+
monthStartFormat: options.monthStartFormat,
|
|
282
|
+
dayCellFormat: options.dayCellFormat,
|
|
283
|
+
businessHours: Boolean(options.businessHours),
|
|
284
|
+
});
|
|
285
|
+
if (dateMeta.isDisabled) {
|
|
286
|
+
return (preact.createElement("div", { role: 'gridcell', "aria-disabled": true, className: internal.joinArrayishClassNames(internal.generateClassName(options.dayCellClass, renderProps), props.className, baseClassName), style: {
|
|
287
|
+
width: props.width
|
|
288
|
+
} }));
|
|
289
|
+
}
|
|
290
|
+
const fullDateStr = internal.buildDateStr(context, props.date);
|
|
291
|
+
return (preact.createElement(internal.ContentContainer, { tag: "div", elRef: this.rootElRef, className: core.joinClassNames(props.className, baseClassName), attrs: Object.assign(Object.assign(Object.assign(Object.assign({}, props.attrs), { role: 'gridcell', 'aria-label': fullDateStr }), (renderProps.isToday ? { 'aria-current': 'date' } : {})), { 'data-date': internal.formatDayString(props.date) }), style: {
|
|
292
|
+
width: props.width,
|
|
293
|
+
}, renderProps: renderProps, generatorName: "dayCellTopContent" // !!! for top
|
|
294
|
+
, customGenerator: options.dayCellTopContent /* !!! for top */, defaultGenerator: renderTopInner, classNameGenerator: options.dayCellClass, didMount: options.dayCellDidMount, willUnmount: options.dayCellWillUnmount }, (InnerContent) => (preact.createElement(preact.Fragment, null,
|
|
295
|
+
preact.createElement("div", { className: core.joinClassNames(classNames__default["default"].rel, // puts it above bg-fills, which are positioned on TOP of this component :|
|
|
296
|
+
internal.generateClassName(options.dayCellTopClass, renderProps)) }, props.showDayNumber && (preact.createElement(InnerContent // the dayCellTopContent
|
|
297
|
+
, { tag: 'div', attrs: hasNavLink
|
|
298
|
+
? internal.buildNavLinkAttrs(context, props.date, undefined, fullDateStr)
|
|
299
|
+
: { 'aria-hidden': true } // label already on cell
|
|
300
|
+
, className: internal.generateClassName(options.dayCellTopInnerClass, renderProps) }))),
|
|
301
|
+
preact.createElement("div", { className: core.joinClassNames(classNames__default["default"].flexCol, props.fgLiquidHeight ? classNames__default["default"].liquid : classNames__default["default"].grow), ref: this.handleBodyEl },
|
|
302
|
+
preact.createElement("div", { className: internal.generateClassName(options.dayCellInnerClass, renderProps), style: { minHeight: props.fgHeight } }, props.fg),
|
|
303
|
+
preact.createElement(DayGridMoreLink, { className: classNames__default["default"].rel, allDayDate: props.date, segs: props.segs, hiddenSegs: props.hiddenSegs, alignElRef: this.rootElRef, alignParentTop: props.showDayNumber
|
|
304
|
+
? '[role=row]'
|
|
305
|
+
: `.${classNames__default["default"].internalView}`, dateSpanProps: props.dateSpanProps, dateProfile: props.dateProfile, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, todayRange: props.todayRange, isNarrow: props.isNarrow, isMicro: props.isMicro })),
|
|
306
|
+
preact.createElement("div", { className: core.joinClassNames(classNames__default["default"].rel, // puts it above bg-fills
|
|
307
|
+
internal.generateClassName(options.dayCellBottomClass, renderProps)) })))));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
// Utils
|
|
311
|
+
// -------------------------------------------------------------------------------------------------
|
|
312
|
+
function renderTopInner(props) {
|
|
313
|
+
return props.text || preact.createElement(preact.Fragment, null, "\u00A0"); // TODO: DRY?
|
|
314
|
+
}
|
|
315
|
+
function shouldDisplayMonthStart(date, currentRange, dateEnv) {
|
|
316
|
+
const { start: currentStart, end: currentEnd } = currentRange;
|
|
317
|
+
const currentEndIncl = internal.addMs(currentEnd, -1);
|
|
318
|
+
const currentFirstYear = dateEnv.getYear(currentStart);
|
|
319
|
+
const currentFirstMonth = dateEnv.getMonth(currentStart);
|
|
320
|
+
const currentLastYear = dateEnv.getYear(currentEndIncl);
|
|
321
|
+
const currentLastMonth = dateEnv.getMonth(currentEndIncl);
|
|
322
|
+
// spans more than one month?
|
|
323
|
+
return !(currentFirstYear === currentLastYear && currentFirstMonth === currentLastMonth) &&
|
|
324
|
+
Boolean(
|
|
325
|
+
// first date in current view?
|
|
326
|
+
date.valueOf() === currentStart.valueOf() ||
|
|
327
|
+
// a month-start that's within the current range?
|
|
328
|
+
(dateEnv.getDay(date) === 1 && date.valueOf() < currentEnd.valueOf()));
|
|
329
|
+
}
|
|
330
|
+
function refineRenderProps(raw) {
|
|
331
|
+
let { date, dateEnv, hasLabel, hasMonthLabel, hasNavLink, businessHours } = raw;
|
|
332
|
+
let [text, textParts] = hasLabel
|
|
333
|
+
? dateEnv.format(date, hasMonthLabel ? raw.monthStartFormat : raw.dayCellFormat)
|
|
334
|
+
: ['', []];
|
|
335
|
+
return Object.assign(Object.assign(Object.assign({}, raw.dateMeta), raw.renderProps), { text,
|
|
336
|
+
textParts, isMajor: raw.isMajor, isNarrow: raw.isNarrow, inPopover: false, hasNavLink,
|
|
337
|
+
get dayNumberText() { return internal.findDayNumberText(textParts); },
|
|
338
|
+
get monthText() { return internal.findMonthText(textParts); }, options: { businessHours }, view: raw.viewApi });
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function computeFgSegVerticals(segs, segHeightMap, cells, maxHeight, strictOrder, allowSlicing = true, dayMaxEvents, dayMaxEventRows) {
|
|
342
|
+
let maxCoord;
|
|
343
|
+
let maxDepth;
|
|
344
|
+
let hiddenConsumes;
|
|
345
|
+
if (dayMaxEvents === true || dayMaxEventRows === true) {
|
|
346
|
+
maxCoord = maxHeight;
|
|
347
|
+
hiddenConsumes = true;
|
|
348
|
+
}
|
|
349
|
+
else if (typeof dayMaxEvents === 'number') {
|
|
350
|
+
maxDepth = dayMaxEvents;
|
|
351
|
+
hiddenConsumes = false;
|
|
352
|
+
}
|
|
353
|
+
else if (typeof dayMaxEventRows === 'number') {
|
|
354
|
+
maxDepth = dayMaxEventRows;
|
|
355
|
+
hiddenConsumes = true;
|
|
356
|
+
}
|
|
357
|
+
// NOTE: visibleSegsMap and hiddenSegMap map NEVER overlap for a given event
|
|
358
|
+
// once a seg has a height, the combined potentially-sliced segs will comprise the entire span of the seg
|
|
359
|
+
// if a seg does not have a height yet, it won't be inserted into either visibleSegsMap/hiddenSegMap
|
|
360
|
+
const visibleSegMap = new Map();
|
|
361
|
+
const hiddenSegMap = new Map();
|
|
362
|
+
const segTops = new Map();
|
|
363
|
+
const isSlicedMap = new Map();
|
|
364
|
+
let hierarchy = new internal.SegHierarchy(segs, (seg) => segHeightMap.get(getEventPartKey(seg)), strictOrder, maxCoord, maxDepth, hiddenConsumes, allowSlicing);
|
|
365
|
+
hierarchy.traverseSegs((seg, segTop) => {
|
|
366
|
+
addToSegMap(visibleSegMap, seg);
|
|
367
|
+
segTops.set(getEventPartKey(seg), segTop);
|
|
368
|
+
if (seg.isSlice) {
|
|
369
|
+
isSlicedMap.set(seg.eventRange, true);
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
for (const hiddenSeg of hierarchy.hiddenSegs) {
|
|
373
|
+
addToSegMap(hiddenSegMap, hiddenSeg); // hidden main segs
|
|
374
|
+
}
|
|
375
|
+
// recompute tops while considering slices
|
|
376
|
+
// portions of these slices might be added to hiddenSegMap
|
|
377
|
+
if (isSlicedMap.size) {
|
|
378
|
+
segTops.clear();
|
|
379
|
+
hierarchy = new internal.SegHierarchy(compileSegMap(segs, visibleSegMap), (seg) => segHeightMap.get(getEventPartKey(seg)), strictOrder, maxCoord, maxDepth, hiddenConsumes);
|
|
380
|
+
hierarchy.traverseSegs((seg, segTop) => {
|
|
381
|
+
segTops.set(getEventPartKey(seg), segTop); // newly-hidden main segs and slices
|
|
382
|
+
});
|
|
383
|
+
for (const hiddenSeg of hierarchy.hiddenSegs) {
|
|
384
|
+
addToSegMap(hiddenSegMap, hiddenSeg);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
const segsByCol = [];
|
|
388
|
+
const hiddenSegsByCol = [];
|
|
389
|
+
const renderableSegsByCol = [];
|
|
390
|
+
const heightsByCol = [];
|
|
391
|
+
for (let col = 0; col < cells.length; col++) {
|
|
392
|
+
segsByCol.push([]);
|
|
393
|
+
hiddenSegsByCol.push([]);
|
|
394
|
+
renderableSegsByCol.push([]);
|
|
395
|
+
heightsByCol.push(0);
|
|
396
|
+
}
|
|
397
|
+
for (const seg of segs) {
|
|
398
|
+
const { eventRange } = seg;
|
|
399
|
+
const visibleSegs = visibleSegMap.get(eventRange) || [];
|
|
400
|
+
const hiddenSegs = hiddenSegMap.get(eventRange) || [];
|
|
401
|
+
const isSliced = isSlicedMap.get(eventRange) || false;
|
|
402
|
+
// add orig to renderable
|
|
403
|
+
renderableSegsByCol[seg.start].push(seg);
|
|
404
|
+
// add slices to renderable
|
|
405
|
+
if (isSliced) {
|
|
406
|
+
for (const visibleSeg of visibleSegs) {
|
|
407
|
+
renderableSegsByCol[visibleSeg.start].push(visibleSeg);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
// accumulate segsByCol/heightsByCol for visible segs
|
|
411
|
+
for (const visibleSeg of visibleSegs) {
|
|
412
|
+
for (let col = visibleSeg.start; col < visibleSeg.end; col++) {
|
|
413
|
+
const slice = sliceSegForCol(visibleSeg, col);
|
|
414
|
+
segsByCol[col].push(slice);
|
|
415
|
+
}
|
|
416
|
+
const segKey = getEventPartKey(visibleSeg);
|
|
417
|
+
const segTop = segTops.get(segKey);
|
|
418
|
+
if (segTop != null) { // positioned?
|
|
419
|
+
const segHeight = segHeightMap.get(segKey);
|
|
420
|
+
for (let col = visibleSeg.start; col < visibleSeg.end; col++) {
|
|
421
|
+
heightsByCol[col] = Math.max(heightsByCol[col], segTop + segHeight);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
// accumulate segsByCol/hiddenSegsByCol for hidden segs
|
|
426
|
+
for (const hiddenSeg of hiddenSegs) {
|
|
427
|
+
for (let col = hiddenSeg.start; col < hiddenSeg.end; col++) {
|
|
428
|
+
const slice = sliceSegForCol(hiddenSeg, col);
|
|
429
|
+
segsByCol[col].push(slice);
|
|
430
|
+
hiddenSegsByCol[col].push(slice);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return [
|
|
435
|
+
segsByCol,
|
|
436
|
+
hiddenSegsByCol,
|
|
437
|
+
renderableSegsByCol,
|
|
438
|
+
segTops,
|
|
439
|
+
heightsByCol,
|
|
440
|
+
];
|
|
441
|
+
}
|
|
442
|
+
// Utils
|
|
443
|
+
// -------------------------------------------------------------------------------------------------
|
|
444
|
+
function addToSegMap(map, seg) {
|
|
445
|
+
let list = map.get(seg.eventRange);
|
|
446
|
+
if (!list) {
|
|
447
|
+
map.set(seg.eventRange, list = []);
|
|
448
|
+
}
|
|
449
|
+
list.push(seg);
|
|
450
|
+
}
|
|
451
|
+
/*
|
|
452
|
+
Ensures relative order of DayRowEventRange stays consistent with segs
|
|
453
|
+
*/
|
|
454
|
+
function compileSegMap(segs, segMap) {
|
|
455
|
+
const res = [];
|
|
456
|
+
for (const seg of segs) {
|
|
457
|
+
res.push(...(segMap.get(seg.eventRange) || []));
|
|
458
|
+
}
|
|
459
|
+
return res;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function buildDayTableModel(dateProfile, dateProfileGenerator, dateEnv) {
|
|
463
|
+
const daySeries = new internal.DaySeriesModel(dateProfile.renderRange, dateProfileGenerator);
|
|
464
|
+
const breakOnWeeks = /year|month|week/.test(dateProfile.currentRangeUnit);
|
|
465
|
+
const majorUnit = !breakOnWeeks && internal.computeMajorUnit(dateProfile, dateEnv);
|
|
466
|
+
return new internal.DayTableModel(daySeries, breakOnWeeks, dateEnv, majorUnit);
|
|
467
|
+
}
|
|
468
|
+
function computeColWidth(colCount, colMinWidth, viewportWidth) {
|
|
469
|
+
if (viewportWidth == null) {
|
|
470
|
+
return [undefined, undefined];
|
|
471
|
+
}
|
|
472
|
+
const colTempWidth = viewportWidth / colCount;
|
|
473
|
+
if (colTempWidth < colMinWidth) {
|
|
474
|
+
return [colMinWidth * colCount, colMinWidth];
|
|
475
|
+
}
|
|
476
|
+
return [viewportWidth, undefined];
|
|
477
|
+
}
|
|
478
|
+
// Positioning
|
|
479
|
+
// -------------------------------------------------------------------------------------------------
|
|
480
|
+
function computeTopFromDate(date, cellRows, rowHeightMap, adjust = 0) {
|
|
481
|
+
let top = 0;
|
|
482
|
+
for (const cells of cellRows) {
|
|
483
|
+
const start = cells[0].date;
|
|
484
|
+
const end = cells[cells.length - 1].date;
|
|
485
|
+
const key = start.toISOString();
|
|
486
|
+
if (date >= start && date <= end) {
|
|
487
|
+
return top;
|
|
488
|
+
}
|
|
489
|
+
const rowHeight = rowHeightMap.get(key);
|
|
490
|
+
if (rowHeight == null) {
|
|
491
|
+
return; // denote unknown
|
|
492
|
+
}
|
|
493
|
+
top += rowHeight + adjust;
|
|
494
|
+
}
|
|
495
|
+
return top;
|
|
496
|
+
}
|
|
497
|
+
/*
|
|
498
|
+
FYI, `width` is not dependable for aligning completely to farside
|
|
499
|
+
*/
|
|
500
|
+
function computeHorizontalsFromSeg(seg, colWidth, colCount) {
|
|
501
|
+
let fromStart;
|
|
502
|
+
let fromEnd;
|
|
503
|
+
if (colWidth != null) {
|
|
504
|
+
fromStart = seg.start * colWidth;
|
|
505
|
+
fromEnd = (colCount - seg.end) * colWidth;
|
|
506
|
+
}
|
|
507
|
+
else {
|
|
508
|
+
const colWidthFrac = 1 / colCount;
|
|
509
|
+
fromStart = internal.fracToCssDim(seg.start * colWidthFrac);
|
|
510
|
+
fromEnd = internal.fracToCssDim(1 - seg.end * colWidthFrac);
|
|
511
|
+
}
|
|
512
|
+
return { insetInlineStart: fromStart, insetInlineEnd: fromEnd };
|
|
513
|
+
}
|
|
514
|
+
function computeColFromPosition(positionLeft, elWidth, colWidth, colCount, isRtl) {
|
|
515
|
+
const realColWidth = colWidth != null ? colWidth : elWidth / colCount;
|
|
516
|
+
const colFromLeft = Math.floor(positionLeft / realColWidth);
|
|
517
|
+
const col = isRtl ? (colCount - colFromLeft - 1) : colFromLeft;
|
|
518
|
+
const left = colFromLeft * realColWidth;
|
|
519
|
+
const right = left + realColWidth;
|
|
520
|
+
return { col, left, right };
|
|
521
|
+
}
|
|
522
|
+
function computeRowFromPosition(positionTop, cellRows, rowHeightMap) {
|
|
523
|
+
let row = 0;
|
|
524
|
+
let top = 0;
|
|
525
|
+
let bottom = 0;
|
|
526
|
+
for (const cells of cellRows) {
|
|
527
|
+
const key = cells[0].key;
|
|
528
|
+
top = bottom;
|
|
529
|
+
bottom = top + rowHeightMap.get(key);
|
|
530
|
+
if (positionTop < bottom) {
|
|
531
|
+
break;
|
|
532
|
+
}
|
|
533
|
+
row++;
|
|
534
|
+
}
|
|
535
|
+
return { row, top, bottom };
|
|
536
|
+
}
|
|
537
|
+
// Hit Element
|
|
538
|
+
// -------------------------------------------------------------------------------------------------
|
|
539
|
+
function getRowEl(rootEl, row) {
|
|
540
|
+
return rootEl.querySelectorAll('[role=row]')[row];
|
|
541
|
+
}
|
|
542
|
+
function getCellEl(rowEl, col) {
|
|
543
|
+
return rowEl.querySelectorAll('[role=gridcell]')[col];
|
|
544
|
+
}
|
|
545
|
+
// Header Formatting
|
|
546
|
+
// -------------------------------------------------------------------------------------------------
|
|
547
|
+
const dayMicroWidth = 50;
|
|
548
|
+
const dayHeaderMicroFormat = internal.createFormatter({
|
|
549
|
+
weekday: 'narrow'
|
|
550
|
+
});
|
|
551
|
+
function createDayHeaderFormatter(explicitFormat, datesRepDistinctDays, dateCnt) {
|
|
552
|
+
return explicitFormat || computeFallbackHeaderFormat(datesRepDistinctDays, dateCnt);
|
|
553
|
+
}
|
|
554
|
+
// Computes a default column header formatting string if `colFormat` is not explicitly defined
|
|
555
|
+
function computeFallbackHeaderFormat(datesRepDistinctDays, dayCnt) {
|
|
556
|
+
// if more than one week row, or if there are a lot of columns with not much space,
|
|
557
|
+
// put just the day numbers will be in each cell
|
|
558
|
+
if (!datesRepDistinctDays) {
|
|
559
|
+
return internal.createFormatter({ weekday: 'short' }); // "Sat"
|
|
560
|
+
}
|
|
561
|
+
if (dayCnt > 1) {
|
|
562
|
+
return internal.createFormatter({
|
|
563
|
+
weekday: 'short',
|
|
564
|
+
weekdayJustify: 'start',
|
|
565
|
+
day: 'numeric',
|
|
566
|
+
omitCommas: true,
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
return internal.createFormatter({
|
|
570
|
+
weekday: 'long',
|
|
571
|
+
weekdayJustify: 'start',
|
|
572
|
+
day: 'numeric',
|
|
573
|
+
omitCommas: true,
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
class DayGridEventHarness extends preact.Component {
|
|
578
|
+
constructor() {
|
|
579
|
+
super(...arguments);
|
|
580
|
+
// ref
|
|
581
|
+
this.rootElRef = preact.createRef();
|
|
582
|
+
}
|
|
583
|
+
render() {
|
|
584
|
+
const { props } = this;
|
|
585
|
+
return (preact.createElement("div", { className: core.joinClassNames(props.className, classNames__default["default"].abs), style: props.style, ref: this.rootElRef }, props.children));
|
|
586
|
+
}
|
|
587
|
+
componentDidMount() {
|
|
588
|
+
const rootEl = this.rootElRef.current; // TODO: make dynamic with useEffect
|
|
589
|
+
this.disconnectHeight = internal.watchHeight(rootEl, (height) => {
|
|
590
|
+
internal.setRef(this.props.heightRef, height);
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
componentWillUnmount() {
|
|
594
|
+
this.disconnectHeight();
|
|
595
|
+
internal.setRef(this.props.heightRef, null);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const DEFAULT_WEEK_NUM_FORMAT = internal.createFormatter({ week: 'narrow' });
|
|
600
|
+
class DayGridRow extends internal.BaseComponent {
|
|
601
|
+
constructor() {
|
|
602
|
+
super(...arguments);
|
|
603
|
+
this.headerHeightRefMap = new internal.RefMap(() => {
|
|
604
|
+
internal.afterSize(this.handleSegPositioning);
|
|
605
|
+
});
|
|
606
|
+
this.mainHeightRefMap = new internal.RefMap(() => {
|
|
607
|
+
const fgLiquidHeight = this.props.dayMaxEvents === true || this.props.dayMaxEventRows === true;
|
|
608
|
+
if (fgLiquidHeight) {
|
|
609
|
+
internal.afterSize(this.handleSegPositioning);
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
this.segHeightRefMap = new internal.RefMap(() => {
|
|
613
|
+
internal.afterSize(this.handleSegPositioning);
|
|
614
|
+
});
|
|
615
|
+
// memo
|
|
616
|
+
this.buildWeekNumberRenderProps = internal.memoize(buildWeekNumberRenderProps);
|
|
617
|
+
this.handleRootEl = (rootEl) => {
|
|
618
|
+
this.rootEl = rootEl;
|
|
619
|
+
internal.setRef(this.props.rootElRef, rootEl);
|
|
620
|
+
};
|
|
621
|
+
this.handleSegPositioning = () => {
|
|
622
|
+
this.forceUpdate();
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
render() {
|
|
626
|
+
const { props, context, headerHeightRefMap, mainHeightRefMap } = this;
|
|
627
|
+
const { cells } = props;
|
|
628
|
+
const { options } = context;
|
|
629
|
+
const weekDateMarker = props.cells[0].date;
|
|
630
|
+
const fgLiquidHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;
|
|
631
|
+
// TODO: memoize? sort all types of segs?
|
|
632
|
+
const fgEventSegs = internal.sortEventSegs(props.fgEventSegs, options.eventOrder);
|
|
633
|
+
// TODO: memoize?
|
|
634
|
+
const [maxMainTop, minMainHeight] = this.computeFgDims(); // uses headerHeightRefMap/mainHeightRefMap
|
|
635
|
+
const [segsByCol, hiddenSegsByCol, renderableSegsByCol, segTops, simpleHeightsByCol] = computeFgSegVerticals(fgEventSegs, this.segHeightRefMap.current, cells, fgLiquidHeight ? minMainHeight : undefined, // if not defined in first run, will unlimited!?
|
|
636
|
+
options.eventOrderStrict, options.eventSlicing, props.dayMaxEvents, props.dayMaxEventRows);
|
|
637
|
+
const heightsByCol = [];
|
|
638
|
+
if (maxMainTop != null) {
|
|
639
|
+
let col = 0;
|
|
640
|
+
for (const cell of cells) { // uses headerHeightRefMap/maxMainTop/simpleHeightsByCol
|
|
641
|
+
const cellHeaderHeight = headerHeightRefMap.current.get(cell.key);
|
|
642
|
+
const extraFgHeight = maxMainTop - cellHeaderHeight;
|
|
643
|
+
heightsByCol.push(simpleHeightsByCol[col++] + extraFgHeight);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
const highlightSegs = this.getHighlightSegs();
|
|
647
|
+
const mirrorSegs = this.getMirrorSegs();
|
|
648
|
+
const hasNavLink = options.navLinks;
|
|
649
|
+
const fullWeekStr = internal.buildDateStr(context, weekDateMarker, 'week');
|
|
650
|
+
const weekNumberRenderProps = this.buildWeekNumberRenderProps(weekDateMarker, context, props.cellIsNarrow, hasNavLink);
|
|
651
|
+
return (preact.createElement("div", { role: props.role /* !!! */, "aria-label": props.role === 'row' // HACK
|
|
652
|
+
? fullWeekStr
|
|
653
|
+
: undefined // can't have label on non-role div
|
|
654
|
+
, className: internal.joinArrayishClassNames(options.dayRowClass, props.className, classNames__default["default"].flexRow, classNames__default["default"].rel, // origin for inlineWeekNumber?
|
|
655
|
+
classNames__default["default"].isolate, (props.forPrint && props.basis !== undefined) && // basis implies siblings (must share height)
|
|
656
|
+
classNames__default["default"].printSiblingRow), style: {
|
|
657
|
+
'flex-basis': props.basis,
|
|
658
|
+
}, ref: this.handleRootEl },
|
|
659
|
+
(props.showWeekNumbers && !props.cellIsMicro) && (preact.createElement(internal.ContentContainer, { tag: 'div', attrs: Object.assign(Object.assign({}, (hasNavLink
|
|
660
|
+
? internal.buildNavLinkAttrs(context, weekDateMarker, 'week', fullWeekStr, /* isTabbable = */ false)
|
|
661
|
+
: {})), { 'role': undefined, 'aria-hidden': true }),
|
|
662
|
+
// put above all cells (TODO: put explicit z0 on each cell?)
|
|
663
|
+
className: classNames__default["default"].z1, renderProps: weekNumberRenderProps, generatorName: "inlineWeekNumberContent", customGenerator: options.inlineWeekNumberContent, defaultGenerator: internal.renderText, classNameGenerator: options.inlineWeekNumberClass, didMount: options.inlineWeekNumberDidMount, willUnmount: options.inlineWeekNumberWillUnmount })),
|
|
664
|
+
this.renderFillSegs(props.businessHourSegs, 'non-business'),
|
|
665
|
+
this.renderFillSegs(props.bgEventSegs, 'bg-event'),
|
|
666
|
+
this.renderFillSegs(highlightSegs, 'highlight'),
|
|
667
|
+
props.cells.map((cell, col) => {
|
|
668
|
+
const normalFgNodes = this.renderFgSegs(maxMainTop, renderableSegsByCol[col], segTops, props.todayRange,
|
|
669
|
+
/* isMirror = */ false);
|
|
670
|
+
return (preact.createElement(DayGridCell, { key: cell.key, dateProfile: props.dateProfile, todayRange: props.todayRange, date: cell.date, isMajor: cell.isMajor, showDayNumber: props.showDayNumbers, isNarrow: props.cellIsNarrow, isMicro: props.cellIsMicro, borderStart: Boolean(col),
|
|
671
|
+
// content
|
|
672
|
+
segs: segsByCol[col], hiddenSegs: hiddenSegsByCol[col], fgLiquidHeight: fgLiquidHeight, fg: (preact.createElement(preact.Fragment, null, normalFgNodes)), eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
|
|
673
|
+
// render hooks
|
|
674
|
+
renderProps: cell.renderProps, dateSpanProps: cell.dateSpanProps, attrs: cell.attrs, className: cell.className,
|
|
675
|
+
// dimensions
|
|
676
|
+
fgHeight: heightsByCol[col], width: props.colWidth,
|
|
677
|
+
// refs
|
|
678
|
+
headerHeightRef: headerHeightRefMap.createRef(cell.key), mainHeightRef: mainHeightRefMap.createRef(cell.key) }));
|
|
679
|
+
}),
|
|
680
|
+
this.renderFgSegs(maxMainTop, mirrorSegs, segTops, props.todayRange,
|
|
681
|
+
/* isMirror = */ true)));
|
|
682
|
+
}
|
|
683
|
+
renderFgSegs(headerHeight, segs, segTops, todayRange, isMirror) {
|
|
684
|
+
var _a;
|
|
685
|
+
const { props, segHeightRefMap } = this;
|
|
686
|
+
const { colWidth, eventSelection, cellIsMicro } = props;
|
|
687
|
+
const colCount = props.cells.length;
|
|
688
|
+
const defaultDisplayEventEnd = props.cells.length === 1;
|
|
689
|
+
const nodes = [];
|
|
690
|
+
for (const seg of segs) {
|
|
691
|
+
const key = getEventPartKey(seg);
|
|
692
|
+
const { standinFor, eventRange } = seg;
|
|
693
|
+
const { instanceId } = eventRange.instance;
|
|
694
|
+
if (standinFor) {
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
const { insetInlineStart, insetInlineEnd } = computeHorizontalsFromSeg(seg, colWidth, colCount);
|
|
698
|
+
const localTop = (_a = segTops.get(standinFor ? getEventPartKey(standinFor) : key)) !== null && _a !== void 0 ? _a : (isMirror ? 0 : undefined);
|
|
699
|
+
const top = headerHeight != null && localTop != null
|
|
700
|
+
? headerHeight + localTop
|
|
701
|
+
: undefined;
|
|
702
|
+
const isDragging = Boolean(props.eventDrag && props.eventDrag.affectedInstances[instanceId]);
|
|
703
|
+
const isResizing = Boolean(props.eventResize && props.eventResize.affectedInstances[instanceId]);
|
|
704
|
+
const isInvisible = !isMirror && (isDragging || isResizing || standinFor || top == null);
|
|
705
|
+
const isListItem = hasListItemDisplay(seg);
|
|
706
|
+
nodes.push(preact.createElement(DayGridEventHarness, { key: key, className: seg.start ? classNames__default["default"].fakeBorderS : '', style: {
|
|
707
|
+
visibility: isInvisible ? 'hidden' : undefined,
|
|
708
|
+
top,
|
|
709
|
+
insetInlineStart,
|
|
710
|
+
insetInlineEnd,
|
|
711
|
+
zIndex: 0, // container inner z-indexes
|
|
712
|
+
}, heightRef: (!standinFor && !isMirror)
|
|
713
|
+
? segHeightRefMap.createRef(key)
|
|
714
|
+
: null },
|
|
715
|
+
preact.createElement(internal.StandardEvent, Object.assign({ display: isListItem ? 'list-item' : 'row', eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: isDragging, isResizing: isResizing, isMirror: isMirror, isSelected: instanceId === eventSelection, isNarrow: props.cellIsNarrow, defaultTimeFormat: DEFAULT_TABLE_EVENT_TIME_FORMAT, defaultDisplayEventEnd: defaultDisplayEventEnd, disableResizing: isListItem, forcedTimeText: cellIsMicro ? '' : undefined }, internal.getEventRangeMeta(eventRange, todayRange)))));
|
|
716
|
+
}
|
|
717
|
+
return nodes;
|
|
718
|
+
}
|
|
719
|
+
renderFillSegs(segs, fillType) {
|
|
720
|
+
const { props, context } = this;
|
|
721
|
+
const { todayRange, colWidth } = props;
|
|
722
|
+
const colCount = props.cells.length;
|
|
723
|
+
const nodes = [];
|
|
724
|
+
for (const seg of segs) {
|
|
725
|
+
const key = internal.buildEventRangeKey(seg.eventRange); // TODO: use different type of key than fg!?
|
|
726
|
+
const { insetInlineStart, insetInlineEnd } = computeHorizontalsFromSeg(seg, colWidth, colCount);
|
|
727
|
+
const isVisible = !seg.standinFor;
|
|
728
|
+
nodes.push(preact.createElement("div", { key: key, className: classNames__default["default"].fillY, style: {
|
|
729
|
+
visibility: isVisible ? '' : 'hidden',
|
|
730
|
+
insetInlineStart,
|
|
731
|
+
insetInlineEnd,
|
|
732
|
+
} }, fillType === 'bg-event' ?
|
|
733
|
+
preact.createElement(internal.BgEvent, Object.assign({ eventRange: seg.eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isNarrow: props.cellIsNarrow, isVertical: false }, internal.getEventRangeMeta(seg.eventRange, todayRange))) : (internal.renderFill(fillType, context.options))));
|
|
734
|
+
}
|
|
735
|
+
return preact.createElement(preact.Fragment, {}, ...nodes); // TODO: shouldn't this be an array, so keyed?
|
|
736
|
+
}
|
|
737
|
+
// Sizing
|
|
738
|
+
// -----------------------------------------------------------------------------------------------
|
|
739
|
+
componentDidMount() {
|
|
740
|
+
const { rootEl } = this; // TODO: make dynamic with useEffect
|
|
741
|
+
this.disconnectHeight = internal.watchHeight(rootEl, (contentHeight) => {
|
|
742
|
+
internal.setRef(this.props.heightRef, contentHeight);
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
componentWillUnmount() {
|
|
746
|
+
this.disconnectHeight();
|
|
747
|
+
internal.setRef(this.props.heightRef, null);
|
|
748
|
+
}
|
|
749
|
+
computeFgDims() {
|
|
750
|
+
const { cells } = this.props;
|
|
751
|
+
const headerHeightMap = this.headerHeightRefMap.current;
|
|
752
|
+
const mainHeightMap = this.mainHeightRefMap.current;
|
|
753
|
+
let maxMainTop;
|
|
754
|
+
let minMainBottom;
|
|
755
|
+
for (const cell of cells) {
|
|
756
|
+
const mainTop = headerHeightMap.get(cell.key);
|
|
757
|
+
const mainHeight = mainHeightMap.get(cell.key);
|
|
758
|
+
if (mainTop != null) {
|
|
759
|
+
if (maxMainTop === undefined || mainTop > maxMainTop) {
|
|
760
|
+
maxMainTop = mainTop;
|
|
761
|
+
}
|
|
762
|
+
if (mainHeight != null) {
|
|
763
|
+
const mainBottom = mainTop + mainHeight;
|
|
764
|
+
if (minMainBottom === undefined || mainBottom < minMainBottom) {
|
|
765
|
+
minMainBottom = mainBottom;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
return [
|
|
771
|
+
maxMainTop,
|
|
772
|
+
minMainBottom != null && maxMainTop != null
|
|
773
|
+
? minMainBottom - maxMainTop
|
|
774
|
+
: undefined,
|
|
775
|
+
];
|
|
776
|
+
}
|
|
777
|
+
// Internal Utils
|
|
778
|
+
// -----------------------------------------------------------------------------------------------
|
|
779
|
+
getMirrorSegs() {
|
|
780
|
+
let { props } = this;
|
|
781
|
+
if (props.eventResize && props.eventResize.segs.length) { // messy check
|
|
782
|
+
return props.eventResize.segs;
|
|
783
|
+
}
|
|
784
|
+
return [];
|
|
785
|
+
}
|
|
786
|
+
getHighlightSegs() {
|
|
787
|
+
let { props } = this;
|
|
788
|
+
if (props.eventDrag && props.eventDrag.segs.length) { // messy check
|
|
789
|
+
return props.eventDrag.segs;
|
|
790
|
+
}
|
|
791
|
+
if (props.eventResize && props.eventResize.segs.length) { // messy check
|
|
792
|
+
return props.eventResize.segs;
|
|
793
|
+
}
|
|
794
|
+
return props.dateSelectionSegs;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
// Utils
|
|
798
|
+
// -------------------------------------------------------------------------------------------------
|
|
799
|
+
function buildWeekNumberRenderProps(weekDateMarker, context, isNarrow, hasNavLink) {
|
|
800
|
+
const { dateEnv, options } = context;
|
|
801
|
+
const weekNum = dateEnv.computeWeekNumber(weekDateMarker);
|
|
802
|
+
const [weekNumText, weekNumTextParts] = dateEnv.format(weekDateMarker, options.weekNumberFormat || DEFAULT_WEEK_NUM_FORMAT);
|
|
803
|
+
const weekDateZoned = dateEnv.toDate(weekDateMarker);
|
|
804
|
+
return {
|
|
805
|
+
num: weekNum,
|
|
806
|
+
text: weekNumText,
|
|
807
|
+
textParts: weekNumTextParts,
|
|
808
|
+
date: weekDateZoned,
|
|
809
|
+
isNarrow,
|
|
810
|
+
hasNavLink,
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
class DayGridRows extends internal.DateComponent {
|
|
815
|
+
constructor() {
|
|
816
|
+
super(...arguments);
|
|
817
|
+
// memo
|
|
818
|
+
this.splitBusinessHourSegs = internal.memoize(splitSegsByRow);
|
|
819
|
+
this.splitBgEventSegs = internal.memoize(splitSegsByRow);
|
|
820
|
+
this.splitFgEventSegs = internal.memoize(splitSegsByRow);
|
|
821
|
+
this.splitDateSelectionSegs = internal.memoize(splitSegsByRow);
|
|
822
|
+
this.splitEventDrag = internal.memoize(splitInteractionByRow);
|
|
823
|
+
this.splitEventResize = internal.memoize(splitInteractionByRow);
|
|
824
|
+
// internal
|
|
825
|
+
this.rowHeightRefMap = new internal.RefMap((height, key) => {
|
|
826
|
+
// HACKy way of syncing RefMap results with prop
|
|
827
|
+
const { rowHeightRefMap } = this.props;
|
|
828
|
+
if (rowHeightRefMap) {
|
|
829
|
+
rowHeightRefMap.handleValue(height, key);
|
|
830
|
+
}
|
|
831
|
+
});
|
|
832
|
+
this.handleRootEl = (rootEl) => {
|
|
833
|
+
this.rootEl = rootEl;
|
|
834
|
+
if (rootEl) {
|
|
835
|
+
this.context.registerInteractiveComponent(this, {
|
|
836
|
+
el: rootEl,
|
|
837
|
+
isHitComboAllowed: this.props.isHitComboAllowed,
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
else {
|
|
841
|
+
this.context.unregisterInteractiveComponent(this);
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
render() {
|
|
846
|
+
let { props, context, rowHeightRefMap } = this;
|
|
847
|
+
let { options } = context;
|
|
848
|
+
let rowCount = props.cellRows.length;
|
|
849
|
+
let fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, rowCount);
|
|
850
|
+
let bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, rowCount);
|
|
851
|
+
let businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, rowCount);
|
|
852
|
+
let dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, rowCount);
|
|
853
|
+
let eventDragByRow = this.splitEventDrag(props.eventDrag, rowCount);
|
|
854
|
+
let eventResizeByRow = this.splitEventResize(props.eventResize, rowCount);
|
|
855
|
+
let isHeightAuto = internal.getIsHeightAuto(options);
|
|
856
|
+
let rowHeightsRedistribute = !props.forPrint && !isHeightAuto;
|
|
857
|
+
let rowBasis = computeRowBasis(props.visibleWidth, rowCount, isHeightAuto, options);
|
|
858
|
+
return (preact.createElement("div", { role: 'rowgroup', className: core.joinClassNames(props.className,
|
|
859
|
+
// HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
|
|
860
|
+
// https://stackoverflow.com/a/60256345
|
|
861
|
+
!props.forPrint && classNames__default["default"].flexCol), style: { width: props.width }, ref: this.handleRootEl }, props.cellRows.map((cells, row) => (preact.createElement(DayGridRow, { key: cells[0].key, role: 'row', dateProfile: props.dateProfile, todayRange: props.todayRange, cells: cells, cellIsNarrow: props.cellIsNarrow, cellIsMicro: props.cellIsMicro, showDayNumbers: rowCount > 1, showWeekNumbers: rowCount > 1 && options.weekNumbers, forPrint: props.forPrint,
|
|
862
|
+
// if not auto-height, distribute height of container somewhat evently to rows
|
|
863
|
+
className: core.joinClassNames(rowHeightsRedistribute && classNames__default["default"].grow, rowCount > 1 && classNames__default["default"].breakInsideAvoid, // don't avoid breaks for single tall row
|
|
864
|
+
row < rowCount - 1 ? classNames__default["default"].borderOnlyB : classNames__default["default"].borderNone),
|
|
865
|
+
// content
|
|
866
|
+
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,
|
|
867
|
+
// dimensions
|
|
868
|
+
colWidth: props.colWidth, basis: rowBasis,
|
|
869
|
+
// refs
|
|
870
|
+
heightRef: rowHeightRefMap.createRef(cells[0].key) })))));
|
|
871
|
+
}
|
|
872
|
+
// Hit System
|
|
873
|
+
// -----------------------------------------------------------------------------------------------
|
|
874
|
+
queryHit(isRtl, positionLeft, positionTop, elWidth) {
|
|
875
|
+
const { props } = this;
|
|
876
|
+
const colCount = props.cellRows[0].length;
|
|
877
|
+
const { col, left, right } = computeColFromPosition(positionLeft, elWidth, props.colWidth, colCount, isRtl);
|
|
878
|
+
const { row, top, bottom } = computeRowFromPosition(positionTop, props.cellRows, this.rowHeightRefMap.current);
|
|
879
|
+
const cell = props.cellRows[row][col];
|
|
880
|
+
const cellStartDate = cell.date;
|
|
881
|
+
const cellEndDate = internal.addDays(cellStartDate, 1);
|
|
882
|
+
return {
|
|
883
|
+
dateProfile: props.dateProfile,
|
|
884
|
+
dateSpan: Object.assign({ range: {
|
|
885
|
+
start: cellStartDate,
|
|
886
|
+
end: cellEndDate,
|
|
887
|
+
}, allDay: true }, cell.dateSpanProps),
|
|
888
|
+
getDayEl: () => getCellEl(getRowEl(this.rootEl, row), col),
|
|
889
|
+
rect: {
|
|
890
|
+
left,
|
|
891
|
+
right,
|
|
892
|
+
top,
|
|
893
|
+
bottom,
|
|
894
|
+
},
|
|
895
|
+
layer: 0,
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
// Utils
|
|
900
|
+
// -------------------------------------------------------------------------------------------------
|
|
901
|
+
function isSegAllDay(seg) {
|
|
902
|
+
return seg.eventRange.def.allDay;
|
|
903
|
+
}
|
|
904
|
+
/*
|
|
905
|
+
Amount of height a row should consume prior to expanding
|
|
906
|
+
We don't want to use min-height with flexbox because we leverage min-height:auto,
|
|
907
|
+
which yields value based on natural height of events
|
|
908
|
+
*/
|
|
909
|
+
function computeRowBasis(visibleWidth, // should INCLUDE any scrollbar width to avoid oscillation
|
|
910
|
+
rowCount, isHeightAuto, options) {
|
|
911
|
+
if (visibleWidth != null) {
|
|
912
|
+
// ensure a consistent row min-height modelled after a month with 6 rows respecting aspectRatio
|
|
913
|
+
// will result in same minHeight regardless of weekends, dayMinWidth, height:auto
|
|
914
|
+
const rowBasis = visibleWidth / options.aspectRatio / 6;
|
|
915
|
+
// don't give minHeight when single-month non-auto-height
|
|
916
|
+
// TODO: better way to detect this with DateProfile?
|
|
917
|
+
return (rowCount > 6 || isHeightAuto) ? rowBasis : 0;
|
|
918
|
+
}
|
|
919
|
+
return 0;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
class DayGridHeaderCell extends internal.BaseComponent {
|
|
923
|
+
constructor() {
|
|
924
|
+
super(...arguments);
|
|
925
|
+
this.handleInnerEl = (innerEl) => {
|
|
926
|
+
if (this.disconnectSize) {
|
|
927
|
+
this.disconnectSize();
|
|
928
|
+
this.disconnectSize = undefined;
|
|
929
|
+
}
|
|
930
|
+
if (innerEl) {
|
|
931
|
+
this.disconnectSize = internal.watchSize(innerEl, (width, height) => {
|
|
932
|
+
internal.setRef(this.props.innerHeightRef, height);
|
|
933
|
+
/*
|
|
934
|
+
TODO: DRY with TimelineHeaderCell
|
|
935
|
+
*/
|
|
936
|
+
if (this.align === 'center' && this.isSticky) {
|
|
937
|
+
this.setState({ innerWidth: width });
|
|
938
|
+
}
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
else {
|
|
942
|
+
internal.setRef(this.props.innerHeightRef, null);
|
|
943
|
+
}
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
render() {
|
|
947
|
+
const { props, state, context } = this;
|
|
948
|
+
const { renderConfig, dataConfig } = props;
|
|
949
|
+
// HACK
|
|
950
|
+
const isDisabled = dataConfig.renderProps.isDisabled;
|
|
951
|
+
const finalRenderProps = Object.assign(Object.assign({}, dataConfig.renderProps), { isNarrow: props.cellIsNarrow, level: props.rowLevel });
|
|
952
|
+
if (props.cellIsMicro) {
|
|
953
|
+
// TODO: only if not distinct dates
|
|
954
|
+
const [microText, microTextParts] = context.dateEnv.format(dataConfig.dateMarker, dayHeaderMicroFormat);
|
|
955
|
+
finalRenderProps.text = finalRenderProps.weekdayText = microText;
|
|
956
|
+
finalRenderProps.textParts = microTextParts;
|
|
957
|
+
}
|
|
958
|
+
/*
|
|
959
|
+
TODO: DRY with TimelineHeaderCell
|
|
960
|
+
*/
|
|
961
|
+
const alignInput = renderConfig.align;
|
|
962
|
+
const align = this.align =
|
|
963
|
+
typeof alignInput === 'function'
|
|
964
|
+
? alignInput({ level: props.rowLevel, inPopover: dataConfig.renderProps.inPopover, isNarrow: props.cellIsNarrow })
|
|
965
|
+
: alignInput;
|
|
966
|
+
const stickyInput = renderConfig.sticky;
|
|
967
|
+
const isSticky = this.isSticky =
|
|
968
|
+
props.rowLevel && stickyInput !== false;
|
|
969
|
+
let edgeCoord;
|
|
970
|
+
if (isSticky) {
|
|
971
|
+
if (align === 'center') {
|
|
972
|
+
if (state.innerWidth != null) {
|
|
973
|
+
edgeCoord = `calc(50% - ${state.innerWidth / 2}px)`;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
else {
|
|
977
|
+
edgeCoord = (typeof stickyInput === 'number' ||
|
|
978
|
+
typeof stickyInput === 'string') ? stickyInput : 0;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
return (preact.createElement(internal.ContentContainer, { tag: 'div', attrs: Object.assign({ role: 'columnheader', 'aria-colspan': dataConfig.colSpan }, dataConfig.attrs), className: core.joinClassNames(dataConfig.className, classNames__default["default"].tight, classNames__default["default"].flexCol, props.borderStart ? classNames__default["default"].borderOnlyS : classNames__default["default"].borderNone, align === 'center' ? classNames__default["default"].alignCenter :
|
|
982
|
+
align === 'end' ? classNames__default["default"].alignEnd :
|
|
983
|
+
classNames__default["default"].alignStart, props.colWidth == null && classNames__default["default"].liquid, !isSticky && classNames__default["default"].crop), style: {
|
|
984
|
+
width: props.colWidth != null
|
|
985
|
+
? props.colWidth * (dataConfig.colSpan || 1)
|
|
986
|
+
: undefined,
|
|
987
|
+
}, renderProps: finalRenderProps, generatorName: renderConfig.generatorName, customGenerator: renderConfig.customGenerator, defaultGenerator: internal.renderText, classNameGenerator:
|
|
988
|
+
// don't use custom classNames if disabled
|
|
989
|
+
// TODO: make DRY with DayCellContainer
|
|
990
|
+
isDisabled ? undefined : renderConfig.classNameGenerator, didMount: renderConfig.didMount, willUnmount: renderConfig.willUnmount }, (InnerContainer) => (preact.createElement("div", { ref: this.handleInnerEl, className: core.joinClassNames(classNames__default["default"].flexCol, classNames__default["default"].rigid, isSticky && classNames__default["default"].sticky), style: {
|
|
991
|
+
left: edgeCoord,
|
|
992
|
+
right: edgeCoord,
|
|
993
|
+
} },
|
|
994
|
+
preact.createElement(InnerContainer, { tag: 'div', attrs: dataConfig.innerAttrs, className: internal.generateClassName(renderConfig.innerClassNameGenerator, finalRenderProps) })))));
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
class DayGridHeaderRow extends internal.BaseComponent {
|
|
999
|
+
constructor() {
|
|
1000
|
+
super(...arguments);
|
|
1001
|
+
// ref
|
|
1002
|
+
this.innerHeightRefMap = new internal.RefMap(() => {
|
|
1003
|
+
internal.afterSize(this.handleInnerHeights);
|
|
1004
|
+
});
|
|
1005
|
+
this.handleInnerHeights = () => {
|
|
1006
|
+
const innerHeightMap = this.innerHeightRefMap.current;
|
|
1007
|
+
let max = 0;
|
|
1008
|
+
for (const innerHeight of innerHeightMap.values()) {
|
|
1009
|
+
max = Math.max(max, innerHeight);
|
|
1010
|
+
}
|
|
1011
|
+
if (this.currentInnerHeight !== max) {
|
|
1012
|
+
this.currentInnerHeight = max;
|
|
1013
|
+
internal.setRef(this.props.innerHeightRef, max);
|
|
1014
|
+
}
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
render() {
|
|
1018
|
+
const { props, context } = this;
|
|
1019
|
+
const { options } = context;
|
|
1020
|
+
return (preact.createElement("div", { role: props.role /* !!! */, "aria-rowindex": props.rowIndex != null ? 1 + props.rowIndex : undefined, className: internal.joinArrayishClassNames(options.dayHeaderRowClass, props.className, classNames__default["default"].flexRow, classNames__default["default"].contentBox, props.borderBottom ? classNames__default["default"].borderOnlyB : classNames__default["default"].borderNone), style: {
|
|
1021
|
+
height: props.height,
|
|
1022
|
+
} }, props.dataConfigs.map((dataConfig, cellI) => (preact.createElement(DayGridHeaderCell, { key: dataConfig.key, renderConfig: props.renderConfig, dataConfig: dataConfig, borderStart: Boolean(cellI), colWidth: props.colWidth, innerHeightRef: this.innerHeightRefMap.createRef(dataConfig.key), cellIsNarrow: props.cellIsNarrow, cellIsMicro: props.cellIsMicro, rowLevel: props.rowLevel })))));
|
|
1023
|
+
}
|
|
1024
|
+
componentWillUnmount() {
|
|
1025
|
+
internal.setRef(this.props.innerHeightRef, null);
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
/*
|
|
1030
|
+
TODO: kill this class in favor of DayGridHeaderRows?
|
|
1031
|
+
*/
|
|
1032
|
+
class DayGridHeader extends internal.BaseComponent {
|
|
1033
|
+
render() {
|
|
1034
|
+
const { props } = this;
|
|
1035
|
+
const { headerTiers } = props;
|
|
1036
|
+
return (preact.createElement("div", { role: 'rowgroup', className: core.joinClassNames(props.className, classNames__default["default"].flexCol, props.width == null && classNames__default["default"].liquid), style: {
|
|
1037
|
+
width: props.width,
|
|
1038
|
+
} }, headerTiers.map((rowConfig, i) => (preact.createElement(DayGridHeaderRow, Object.assign({}, rowConfig, { key: i, role: 'row', borderBottom: i < headerTiers.length - 1, colWidth: props.colWidth, cellIsNarrow: props.cellIsNarrow, cellIsMicro: props.cellIsMicro, rowLevel: headerTiers.length - i - 1 }))))));
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
class DayGridLayoutNormal extends internal.BaseComponent {
|
|
1043
|
+
constructor() {
|
|
1044
|
+
super(...arguments);
|
|
1045
|
+
this.handleScroller = (scroller) => {
|
|
1046
|
+
internal.setRef(this.props.scrollerRef, scroller);
|
|
1047
|
+
};
|
|
1048
|
+
this.handleTotalWidth = (totalWidth) => {
|
|
1049
|
+
this.setState({ totalWidth });
|
|
1050
|
+
};
|
|
1051
|
+
this.handleClientWidth = (clientWidth) => {
|
|
1052
|
+
this.setState({ clientWidth });
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
render() {
|
|
1056
|
+
const { props, state, context } = this;
|
|
1057
|
+
const { options } = context;
|
|
1058
|
+
const { totalWidth, clientWidth } = state;
|
|
1059
|
+
let endScrollbarWidth = (totalWidth != null && clientWidth != null)
|
|
1060
|
+
? totalWidth - clientWidth
|
|
1061
|
+
: undefined;
|
|
1062
|
+
// HACK when clientWidth does NOT include body-border, compared to totalWidth
|
|
1063
|
+
if (endScrollbarWidth < 3) {
|
|
1064
|
+
endScrollbarWidth = 0;
|
|
1065
|
+
}
|
|
1066
|
+
const verticalScrollbars = !props.forPrint && !internal.getIsHeightAuto(options);
|
|
1067
|
+
const stickyHeaderDates = !props.forPrint && internal.getStickyHeaderDates(options);
|
|
1068
|
+
const colCount = props.cellRows[0].length;
|
|
1069
|
+
const cellWidth = clientWidth != null ? clientWidth / colCount : undefined;
|
|
1070
|
+
const cellIsMicro = cellWidth != null && cellWidth <= dayMicroWidth;
|
|
1071
|
+
const cellIsNarrow = cellIsMicro || (cellWidth != null && cellWidth <= options.dayNarrowWidth);
|
|
1072
|
+
return (preact.createElement(preact.Fragment, null,
|
|
1073
|
+
options.dayHeaders && (preact.createElement("div", { className: core.joinClassNames(internal.generateClassName(options.tableHeaderClass, {
|
|
1074
|
+
isSticky: stickyHeaderDates,
|
|
1075
|
+
}), props.borderlessX && classNames__default["default"].borderlessX, classNames__default["default"].printHeader, // either flexCol or table-header-group
|
|
1076
|
+
stickyHeaderDates && classNames__default["default"].tableHeaderSticky) },
|
|
1077
|
+
preact.createElement("div", { className: classNames__default["default"].flexRow },
|
|
1078
|
+
preact.createElement(DayGridHeader, { headerTiers: props.headerTiers, cellIsNarrow: cellIsNarrow, cellIsMicro: cellIsMicro }),
|
|
1079
|
+
Boolean(endScrollbarWidth) && (preact.createElement("div", { className: internal.joinArrayishClassNames(internal.generateClassName(options.fillerClass, { isHeader: true }), classNames__default["default"].borderOnlyS), style: { minWidth: endScrollbarWidth } }))),
|
|
1080
|
+
preact.createElement("div", { className: internal.generateClassName(options.dayHeaderDividerClass, {
|
|
1081
|
+
isSticky: stickyHeaderDates,
|
|
1082
|
+
options: { allDaySlot: Boolean(options.allDaySlot) },
|
|
1083
|
+
}) }))),
|
|
1084
|
+
preact.createElement(internal.Scroller, { vertical: verticalScrollbars, className: internal.joinArrayishClassNames(options.tableBodyClass, props.borderlessX && classNames__default["default"].borderlessX, stickyHeaderDates && classNames__default["default"].borderlessTop, (stickyHeaderDates || props.noEdgeEffects) && classNames__default["default"].noEdgeEffects,
|
|
1085
|
+
// HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
|
|
1086
|
+
// https://stackoverflow.com/a/60256345
|
|
1087
|
+
!props.forPrint && classNames__default["default"].flexCol, verticalScrollbars && classNames__default["default"].liquid), ref: this.handleScroller, clientWidthRef: this.handleClientWidth },
|
|
1088
|
+
preact.createElement(DayGridRows, { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: props.cellRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed, className: classNames__default["default"].grow, dayMaxEvents: props.forPrint ? undefined : options.dayMaxEvents, dayMaxEventRows: options.dayMaxEventRows,
|
|
1089
|
+
// content
|
|
1090
|
+
fgEventSegs: props.fgEventSegs, bgEventSegs: props.bgEventSegs, businessHourSegs: props.businessHourSegs, dateSelectionSegs: props.dateSelectionSegs, eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
|
|
1091
|
+
// dimensions
|
|
1092
|
+
visibleWidth: totalWidth, cellIsNarrow: cellIsNarrow, cellIsMicro: cellIsMicro,
|
|
1093
|
+
// refs
|
|
1094
|
+
rowHeightRefMap: props.rowHeightRefMap })),
|
|
1095
|
+
preact.createElement(internal.Ruler, { widthRef: this.handleTotalWidth })));
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
class DayGridLayoutPannable extends internal.BaseComponent {
|
|
1100
|
+
constructor() {
|
|
1101
|
+
super(...arguments);
|
|
1102
|
+
this.headerScrollerRef = preact.createRef();
|
|
1103
|
+
this.bodyScrollerRef = preact.createRef();
|
|
1104
|
+
this.footerScrollerRef = preact.createRef();
|
|
1105
|
+
// Sizing
|
|
1106
|
+
// -----------------------------------------------------------------------------------------------
|
|
1107
|
+
this.handleTotalWidth = (totalWidth) => {
|
|
1108
|
+
this.setState({ totalWidth });
|
|
1109
|
+
};
|
|
1110
|
+
this.handleClientWidth = (clientWidth) => {
|
|
1111
|
+
this.setState({ clientWidth });
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
render() {
|
|
1115
|
+
const { props, state, context } = this;
|
|
1116
|
+
const { options } = context;
|
|
1117
|
+
const { totalWidth, clientWidth } = state;
|
|
1118
|
+
const endScrollbarWidth = (totalWidth != null && clientWidth != null)
|
|
1119
|
+
? totalWidth - clientWidth
|
|
1120
|
+
: undefined;
|
|
1121
|
+
const verticalScrollbars = !props.forPrint && !internal.getIsHeightAuto(options);
|
|
1122
|
+
const stickyHeaderDates = !props.forPrint && internal.getStickyHeaderDates(options);
|
|
1123
|
+
const stickyFooterScrollbar = !props.forPrint && internal.getStickyFooterScrollbar(options);
|
|
1124
|
+
const colCount = props.cellRows[0].length;
|
|
1125
|
+
const [canvasWidth, colWidth] = computeColWidth(colCount, props.dayMinWidth, clientWidth);
|
|
1126
|
+
const cellIsMicro = colWidth != null && colWidth <= dayMicroWidth;
|
|
1127
|
+
const cellIsNarrow = cellIsMicro || (colWidth != null && colWidth <= options.dayNarrowWidth);
|
|
1128
|
+
return (preact.createElement(preact.Fragment, null,
|
|
1129
|
+
options.dayHeaders && (preact.createElement("div", { className: core.joinClassNames(internal.generateClassName(options.tableHeaderClass, {
|
|
1130
|
+
isSticky: stickyHeaderDates,
|
|
1131
|
+
}), props.borderlessX && classNames__default["default"].borderlessX, classNames__default["default"].printHeader, // either flexCol or table-header-group
|
|
1132
|
+
stickyHeaderDates && classNames__default["default"].tableHeaderSticky) },
|
|
1133
|
+
preact.createElement(internal.Scroller, { horizontal: true, hideScrollbars: true, className: classNames__default["default"].flexRow, ref: this.headerScrollerRef },
|
|
1134
|
+
preact.createElement(DayGridHeader, { headerTiers: props.headerTiers, colWidth: colWidth, width: canvasWidth, cellIsNarrow: cellIsNarrow, cellIsMicro: cellIsMicro }),
|
|
1135
|
+
Boolean(endScrollbarWidth) && (preact.createElement("div", { className: internal.joinArrayishClassNames(internal.generateClassName(options.fillerClass, { isHeader: true }), classNames__default["default"].borderOnlyS), style: { minWidth: endScrollbarWidth } }))),
|
|
1136
|
+
preact.createElement("div", { className: internal.generateClassName(options.dayHeaderDividerClass, {
|
|
1137
|
+
isSticky: stickyHeaderDates,
|
|
1138
|
+
options: { allDaySlot: Boolean(options.allDaySlot) },
|
|
1139
|
+
}) }))),
|
|
1140
|
+
preact.createElement(internal.Scroller, { vertical: verticalScrollbars, horizontal: true, hideScrollbars: stickyFooterScrollbar ||
|
|
1141
|
+
props.forPrint // prevents blank space in print-view on Safari
|
|
1142
|
+
, className: internal.joinArrayishClassNames(options.tableBodyClass, props.borderlessX && classNames__default["default"].borderlessX, stickyHeaderDates && classNames__default["default"].borderlessTop, (stickyHeaderDates || props.noEdgeEffects) && classNames__default["default"].noEdgeEffects,
|
|
1143
|
+
// HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
|
|
1144
|
+
// https://stackoverflow.com/a/60256345
|
|
1145
|
+
!props.forPrint && classNames__default["default"].flexCol, verticalScrollbars && classNames__default["default"].liquid), ref: this.bodyScrollerRef, clientWidthRef: this.handleClientWidth },
|
|
1146
|
+
preact.createElement(DayGridRows, { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: props.cellRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed, className: classNames__default["default"].grow, dayMaxEvents: props.forPrint ? undefined : options.dayMaxEvents, dayMaxEventRows: options.dayMaxEventRows,
|
|
1147
|
+
// content
|
|
1148
|
+
fgEventSegs: props.fgEventSegs, bgEventSegs: props.bgEventSegs, businessHourSegs: props.businessHourSegs, dateSelectionSegs: props.dateSelectionSegs, eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
|
|
1149
|
+
// dimensions
|
|
1150
|
+
colWidth: colWidth, width: canvasWidth, visibleWidth: totalWidth, cellIsNarrow: cellIsNarrow, cellIsMicro: cellIsMicro,
|
|
1151
|
+
// refs
|
|
1152
|
+
rowHeightRefMap: props.rowHeightRefMap })),
|
|
1153
|
+
Boolean(stickyFooterScrollbar) && (preact.createElement(internal.FooterScrollbar, { isSticky: true, canvasWidth: canvasWidth, scrollerRef: this.footerScrollerRef })),
|
|
1154
|
+
preact.createElement(internal.Ruler, { widthRef: this.handleTotalWidth })));
|
|
1155
|
+
}
|
|
1156
|
+
// Lifecycle
|
|
1157
|
+
// -----------------------------------------------------------------------------------------------
|
|
1158
|
+
componentDidMount() {
|
|
1159
|
+
// scroller
|
|
1160
|
+
const ScrollerSyncer = internal.getScrollerSyncerClass(this.context.pluginHooks);
|
|
1161
|
+
this.syncedScroller = new ScrollerSyncer(true); // horizontal=true
|
|
1162
|
+
internal.setRef(this.props.scrollerRef, this.syncedScroller);
|
|
1163
|
+
this.updateSyncedScroller();
|
|
1164
|
+
}
|
|
1165
|
+
componentDidUpdate() {
|
|
1166
|
+
// scroller
|
|
1167
|
+
this.updateSyncedScroller();
|
|
1168
|
+
}
|
|
1169
|
+
componentWillUnmount() {
|
|
1170
|
+
// scroller
|
|
1171
|
+
this.syncedScroller.destroy();
|
|
1172
|
+
}
|
|
1173
|
+
// Scrolling
|
|
1174
|
+
// -----------------------------------------------------------------------------------------------
|
|
1175
|
+
updateSyncedScroller() {
|
|
1176
|
+
this.syncedScroller.handleChildren([
|
|
1177
|
+
this.headerScrollerRef.current,
|
|
1178
|
+
this.bodyScrollerRef.current,
|
|
1179
|
+
this.footerScrollerRef.current,
|
|
1180
|
+
]);
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
class DayGridLayout extends internal.BaseComponent {
|
|
1185
|
+
constructor() {
|
|
1186
|
+
super(...arguments);
|
|
1187
|
+
// ref
|
|
1188
|
+
this.scrollerRef = preact.createRef();
|
|
1189
|
+
this.rowHeightRefMap = new internal.RefMap(() => {
|
|
1190
|
+
internal.afterSize(this.updateScrollY);
|
|
1191
|
+
});
|
|
1192
|
+
// internal
|
|
1193
|
+
this.scrollDate = null;
|
|
1194
|
+
this.updateScrollY = () => {
|
|
1195
|
+
const rowHeightMap = this.rowHeightRefMap.current;
|
|
1196
|
+
const scroller = this.scrollerRef.current;
|
|
1197
|
+
// Since updateScrollY is called by rowHeightRefMap, could be called with null during cleanup,
|
|
1198
|
+
// and the scroller might not exist
|
|
1199
|
+
if (scroller && this.scrollDate) {
|
|
1200
|
+
let scrollTop = computeTopFromDate(this.scrollDate, this.props.cellRows, rowHeightMap, 1);
|
|
1201
|
+
if (scrollTop != null) {
|
|
1202
|
+
if (scrollTop) {
|
|
1203
|
+
scrollTop++; // clear top border
|
|
1204
|
+
}
|
|
1205
|
+
scroller.scrollTo({ y: scrollTop });
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
};
|
|
1209
|
+
this.handleScrollEnd = (isUser) => {
|
|
1210
|
+
if (isUser) {
|
|
1211
|
+
this.scrollDate = null;
|
|
1212
|
+
}
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
render() {
|
|
1216
|
+
const { props, context } = this;
|
|
1217
|
+
const { options } = context;
|
|
1218
|
+
const commonLayoutProps = Object.assign(Object.assign({}, props), { scrollerRef: this.scrollerRef, rowHeightRefMap: this.rowHeightRefMap });
|
|
1219
|
+
return (preact.createElement(internal.ViewContainer, { viewSpec: context.viewSpec, attrs: {
|
|
1220
|
+
role: 'grid',
|
|
1221
|
+
'aria-rowcount': props.headerTiers.length + props.cellRows.length,
|
|
1222
|
+
'aria-colcount': props.cellRows[0].length,
|
|
1223
|
+
'aria-labelledby': props.labelId,
|
|
1224
|
+
'aria-label': props.labelStr,
|
|
1225
|
+
}, className: internal.joinArrayishClassNames(props.className, classNames__default["default"].printRoot, // either flexCol or table
|
|
1226
|
+
options.tableClass), borderlessX: props.borderlessX, borderlessTop: props.borderlessTop, borderlessBottom: props.borderlessBottom, noEdgeEffects: props.noEdgeEffects }, options.dayMinWidth ? (preact.createElement(DayGridLayoutPannable, Object.assign({}, commonLayoutProps, { dayMinWidth: options.dayMinWidth }))) : (preact.createElement(DayGridLayoutNormal, Object.assign({}, commonLayoutProps)))));
|
|
1227
|
+
}
|
|
1228
|
+
// Lifecycle
|
|
1229
|
+
// -----------------------------------------------------------------------------------------------
|
|
1230
|
+
componentDidMount() {
|
|
1231
|
+
this.resetScroll();
|
|
1232
|
+
this.scrollerRef.current.addScrollEndListener(this.handleScrollEnd);
|
|
1233
|
+
}
|
|
1234
|
+
componentDidUpdate(prevProps) {
|
|
1235
|
+
if (prevProps.dateProfile !== this.props.dateProfile && this.context.options.scrollTimeReset) {
|
|
1236
|
+
this.resetScroll();
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
componentWillUnmount() {
|
|
1240
|
+
this.scrollerRef.current.removeScrollEndListener(this.handleScrollEnd);
|
|
1241
|
+
}
|
|
1242
|
+
// Scrolling
|
|
1243
|
+
// -----------------------------------------------------------------------------------------------
|
|
1244
|
+
resetScroll() {
|
|
1245
|
+
this.scrollDate = this.props.dateProfile.currentDate;
|
|
1246
|
+
this.updateScrollY();
|
|
1247
|
+
const scroller = this.scrollerRef.current;
|
|
1248
|
+
scroller.scrollTo({ x: 0 });
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
class DayGridView extends internal.BaseComponent {
|
|
1253
|
+
constructor() {
|
|
1254
|
+
super(...arguments);
|
|
1255
|
+
// memo
|
|
1256
|
+
this.buildDayTableModel = internal.memoize(buildDayTableModel);
|
|
1257
|
+
this.buildDateRowConfigs = internal.memoize(buildDateRowConfigs);
|
|
1258
|
+
this.createDayHeaderFormatter = internal.memoize(createDayHeaderFormatter);
|
|
1259
|
+
// internal
|
|
1260
|
+
this.slicer = new DayTableSlicer();
|
|
1261
|
+
}
|
|
1262
|
+
render() {
|
|
1263
|
+
const { props, context } = this;
|
|
1264
|
+
const { dateProfile } = props;
|
|
1265
|
+
const { options, dateEnv } = context;
|
|
1266
|
+
const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator, dateEnv);
|
|
1267
|
+
const datesRepDistinctDays = dayTableModel.rowCount === 1;
|
|
1268
|
+
const dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, datesRepDistinctDays, dayTableModel.colCount);
|
|
1269
|
+
const slicedProps = this.slicer.sliceProps(props, dateProfile, options.nextDayThreshold, context, dayTableModel);
|
|
1270
|
+
return (preact.createElement(internal.NowTimer, { unit: "day" }, (nowDate, todayRange) => {
|
|
1271
|
+
const headerTiers = this.buildDateRowConfigs(dayTableModel.headerDates, datesRepDistinctDays, dateProfile, todayRange, dayHeaderFormat, context);
|
|
1272
|
+
return (preact.createElement(DayGridLayout, { labelId: props.labelId, labelStr: props.labelStr, dateProfile: dateProfile, todayRange: todayRange, cellRows: dayTableModel.cellRows, forPrint: props.forPrint, className: props.className,
|
|
1273
|
+
// header content
|
|
1274
|
+
headerTiers: headerTiers,
|
|
1275
|
+
// body content
|
|
1276
|
+
fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection, borderlessX: props.borderlessX, borderlessTop: props.borderlessTop, borderlessBottom: props.borderlessBottom, noEdgeEffects: props.noEdgeEffects }));
|
|
1277
|
+
}));
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
class TableDateProfileGenerator extends internal.DateProfileGenerator {
|
|
1282
|
+
// Computes the date range that will be rendered
|
|
1283
|
+
buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay) {
|
|
1284
|
+
let renderRange = super.buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay);
|
|
1285
|
+
let { props } = this;
|
|
1286
|
+
return buildDayTableRenderRange({
|
|
1287
|
+
currentRange: renderRange,
|
|
1288
|
+
snapToWeek: /^(year|month)$/.test(currentRangeUnit),
|
|
1289
|
+
fixedWeekCount: props.fixedWeekCount,
|
|
1290
|
+
dateEnv: props.dateEnv,
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
function buildDayTableRenderRange(props) {
|
|
1295
|
+
let { dateEnv, currentRange } = props;
|
|
1296
|
+
let { start, end } = currentRange;
|
|
1297
|
+
let endOfWeek;
|
|
1298
|
+
// year and month views should be aligned with weeks. this is already done for week
|
|
1299
|
+
if (props.snapToWeek) {
|
|
1300
|
+
start = dateEnv.startOfWeek(start);
|
|
1301
|
+
// make end-of-week if not already
|
|
1302
|
+
endOfWeek = dateEnv.startOfWeek(end);
|
|
1303
|
+
if (endOfWeek.valueOf() !== end.valueOf()) {
|
|
1304
|
+
end = internal.addWeeks(endOfWeek, 1);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
// ensure 6 weeks
|
|
1308
|
+
if (props.fixedWeekCount) {
|
|
1309
|
+
// TODO: instead of these date-math gymnastics (for multimonth view),
|
|
1310
|
+
// compute dateprofiles of all months, then use start of first and end of last.
|
|
1311
|
+
let lastMonthRenderStart = dateEnv.startOfWeek(dateEnv.startOfMonth(internal.addDays(currentRange.end, -1)));
|
|
1312
|
+
let rowCount = Math.ceil(// could be partial weeks due to hiddenDays
|
|
1313
|
+
internal.diffWeeks(lastMonthRenderStart, end));
|
|
1314
|
+
end = internal.addWeeks(end, 6 - rowCount);
|
|
1315
|
+
}
|
|
1316
|
+
return { start, end };
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
exports.DayGridHeaderRow = DayGridHeaderRow;
|
|
1320
|
+
exports.DayGridLayout = DayGridLayout;
|
|
1321
|
+
exports.DayGridRow = DayGridRow;
|
|
1322
|
+
exports.DayGridRows = DayGridRows;
|
|
1323
|
+
exports.DayGridView = DayGridView;
|
|
1324
|
+
exports.DayTableSlicer = DayTableSlicer;
|
|
1325
|
+
exports.TableDateProfileGenerator = TableDateProfileGenerator;
|
|
1326
|
+
exports.buildDateDataConfigs = buildDateDataConfigs;
|
|
1327
|
+
exports.buildDateRenderConfig = buildDateRenderConfig;
|
|
1328
|
+
exports.buildDateRowConfig = buildDateRowConfig;
|
|
1329
|
+
exports.buildDateRowConfigs = buildDateRowConfigs;
|
|
1330
|
+
exports.buildDayTableModel = buildDayTableModel;
|
|
1331
|
+
exports.buildDayTableRenderRange = buildDayTableRenderRange;
|
|
1332
|
+
exports.computeColFromPosition = computeColFromPosition;
|
|
1333
|
+
exports.computeColWidth = computeColWidth;
|
|
1334
|
+
exports.computeRowBasis = computeRowBasis;
|
|
1335
|
+
exports.createDayHeaderFormatter = createDayHeaderFormatter;
|
|
1336
|
+
exports.dayHeaderMicroFormat = dayHeaderMicroFormat;
|
|
1337
|
+
exports.dayMicroWidth = dayMicroWidth;
|
|
1338
|
+
exports.getCellEl = getCellEl;
|
|
1339
|
+
exports.getRowEl = getRowEl;
|