@fullcalendar/scrollgrid 6.1.14 → 7.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.global.js CHANGED
@@ -1,246 +1,15 @@
1
1
  /*!
2
- FullCalendar ScrollGrid Plugin v6.1.14
2
+ FullCalendar ScrollGrid Plugin v7.0.0-beta.0
3
3
  Docs & License: https://fullcalendar.io/docs/premium
4
4
  (c) 2024 Adam Shaw
5
5
  */
6
- FullCalendar.ScrollGrid = (function (exports, core, premiumCommonPlugin, internal$1, preact) {
6
+ FullCalendar.ScrollGrid = (function (exports, core, premiumCommonPlugin, internal$1) {
7
7
  'use strict';
8
8
 
9
9
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
10
10
 
11
11
  var premiumCommonPlugin__default = /*#__PURE__*/_interopDefault(premiumCommonPlugin);
12
12
 
13
- // TODO: assume the el has no borders?
14
- function getScrollCanvasOrigin(scrollEl) {
15
- let rect = scrollEl.getBoundingClientRect();
16
- let edges = internal$1.computeEdges(scrollEl); // TODO: pass in isRtl?
17
- return {
18
- left: rect.left + edges.borderLeft + edges.scrollbarLeft - getScrollFromLeftEdge(scrollEl),
19
- top: rect.top + edges.borderTop - scrollEl.scrollTop,
20
- };
21
- }
22
- function getScrollFromLeftEdge(el) {
23
- let scrollLeft = el.scrollLeft;
24
- let computedStyles = window.getComputedStyle(el); // TODO: pass in isRtl instead?
25
- if (computedStyles.direction === 'rtl') {
26
- switch (getRtlScrollSystem()) {
27
- case 'negative':
28
- scrollLeft *= -1; // convert to 'reverse'. fall through...
29
- case 'reverse': // scrollLeft is distance between scrollframe's right edge scrollcanvas's right edge
30
- scrollLeft = el.scrollWidth - scrollLeft - el.clientWidth;
31
- }
32
- }
33
- return scrollLeft;
34
- }
35
- function setScrollFromLeftEdge(el, scrollLeft) {
36
- let computedStyles = window.getComputedStyle(el); // TODO: pass in isRtl instead?
37
- if (computedStyles.direction === 'rtl') {
38
- switch (getRtlScrollSystem()) {
39
- case 'reverse':
40
- scrollLeft = el.scrollWidth - scrollLeft;
41
- break;
42
- case 'negative':
43
- scrollLeft = -(el.scrollWidth - scrollLeft);
44
- break;
45
- }
46
- }
47
- el.scrollLeft = scrollLeft;
48
- }
49
- // Horizontal Scroll System Detection
50
- // ----------------------------------------------------------------------------------------------
51
- let _rtlScrollSystem;
52
- function getRtlScrollSystem() {
53
- return _rtlScrollSystem || (_rtlScrollSystem = detectRtlScrollSystem());
54
- }
55
- function detectRtlScrollSystem() {
56
- let el = document.createElement('div');
57
- el.style.position = 'absolute';
58
- el.style.top = '-1000px';
59
- el.style.width = '100px'; // must be at least the side of scrollbars or you get inaccurate values (#7335)
60
- el.style.height = '100px'; // "
61
- el.style.overflow = 'scroll';
62
- el.style.direction = 'rtl';
63
- let innerEl = document.createElement('div');
64
- innerEl.style.width = '200px';
65
- innerEl.style.height = '200px';
66
- el.appendChild(innerEl);
67
- document.body.appendChild(el);
68
- let system;
69
- if (el.scrollLeft > 0) {
70
- system = 'positive'; // scroll is a positive number from the left edge
71
- }
72
- else {
73
- el.scrollLeft = 1;
74
- if (el.scrollLeft > 0) {
75
- system = 'reverse'; // scroll is a positive number from the right edge
76
- }
77
- else {
78
- system = 'negative'; // scroll is a negative number from the right edge
79
- }
80
- }
81
- internal$1.removeElement(el);
82
- return system;
83
- }
84
-
85
- const STICKY_SELECTOR = '.fc-sticky';
86
- /*
87
- Goes beyond mere position:sticky, allows horizontal centering
88
-
89
- REQUIREMENT: fc-sticky elements, if the fc-sticky className is taken away, should NOT have relative or absolute positioning.
90
- This is because we attach the coords with JS, and the VDOM might take away the fc-sticky class but doesn't know kill the positioning.
91
-
92
- TODO: don't query text-align:center. isn't compatible with flexbox centering. instead, check natural X coord within parent container
93
- */
94
- class StickyScrolling {
95
- constructor(scrollEl, isRtl) {
96
- this.scrollEl = scrollEl;
97
- this.isRtl = isRtl;
98
- this.updateSize = () => {
99
- let { scrollEl } = this;
100
- let els = internal$1.findElements(scrollEl, STICKY_SELECTOR);
101
- let elGeoms = this.queryElGeoms(els);
102
- let viewportWidth = scrollEl.clientWidth;
103
- assignStickyPositions(els, elGeoms, viewportWidth);
104
- };
105
- }
106
- queryElGeoms(els) {
107
- let { scrollEl, isRtl } = this;
108
- let canvasOrigin = getScrollCanvasOrigin(scrollEl);
109
- let elGeoms = [];
110
- for (let el of els) {
111
- let parentBound = internal$1.translateRect(internal$1.computeInnerRect(el.parentNode, true, true), // weird way to call this!!!
112
- -canvasOrigin.left, -canvasOrigin.top);
113
- let elRect = el.getBoundingClientRect();
114
- let computedStyles = window.getComputedStyle(el);
115
- let textAlign = window.getComputedStyle(el.parentNode).textAlign; // ask the parent
116
- let naturalBound = null;
117
- if (textAlign === 'start') {
118
- textAlign = isRtl ? 'right' : 'left';
119
- }
120
- else if (textAlign === 'end') {
121
- textAlign = isRtl ? 'left' : 'right';
122
- }
123
- if (computedStyles.position !== 'sticky') {
124
- naturalBound = internal$1.translateRect(elRect, -canvasOrigin.left - (parseFloat(computedStyles.left) || 0), // could be 'auto'
125
- -canvasOrigin.top - (parseFloat(computedStyles.top) || 0));
126
- }
127
- elGeoms.push({
128
- parentBound,
129
- naturalBound,
130
- elWidth: elRect.width,
131
- elHeight: elRect.height,
132
- textAlign,
133
- });
134
- }
135
- return elGeoms;
136
- }
137
- }
138
- function assignStickyPositions(els, elGeoms, viewportWidth) {
139
- els.forEach((el, i) => {
140
- let { textAlign, elWidth, parentBound } = elGeoms[i];
141
- let parentWidth = parentBound.right - parentBound.left;
142
- let left;
143
- if (textAlign === 'center' &&
144
- parentWidth > viewportWidth) {
145
- left = (viewportWidth - elWidth) / 2;
146
- }
147
- else { // if parent container can be completely in view, we don't need stickiness
148
- left = '';
149
- }
150
- internal$1.applyStyle(el, {
151
- left,
152
- right: left,
153
- top: 0,
154
- });
155
- });
156
- }
157
-
158
- class ClippedScroller extends internal$1.BaseComponent {
159
- constructor() {
160
- super(...arguments);
161
- this.elRef = preact.createRef();
162
- this.state = {
163
- xScrollbarWidth: 0,
164
- yScrollbarWidth: 0,
165
- };
166
- this.handleScroller = (scroller) => {
167
- this.scroller = scroller;
168
- internal$1.setRef(this.props.scrollerRef, scroller);
169
- };
170
- this.handleSizing = () => {
171
- let { props } = this;
172
- if (props.overflowY === 'scroll-hidden') {
173
- this.setState({ yScrollbarWidth: this.scroller.getYScrollbarWidth() });
174
- }
175
- if (props.overflowX === 'scroll-hidden') {
176
- this.setState({ xScrollbarWidth: this.scroller.getXScrollbarWidth() });
177
- }
178
- };
179
- }
180
- render() {
181
- let { props, state, context } = this;
182
- let isScrollbarOnLeft = context.isRtl && internal$1.getIsRtlScrollbarOnLeft();
183
- let overcomeLeft = 0;
184
- let overcomeRight = 0;
185
- let overcomeBottom = 0;
186
- let { overflowX, overflowY } = props;
187
- if (props.forPrint) {
188
- overflowX = 'visible';
189
- overflowY = 'visible';
190
- }
191
- if (overflowX === 'scroll-hidden') {
192
- overcomeBottom = state.xScrollbarWidth;
193
- }
194
- if (overflowY === 'scroll-hidden') {
195
- if (state.yScrollbarWidth != null) {
196
- if (isScrollbarOnLeft) {
197
- overcomeLeft = state.yScrollbarWidth;
198
- }
199
- else {
200
- overcomeRight = state.yScrollbarWidth;
201
- }
202
- }
203
- }
204
- return (preact.createElement("div", { ref: this.elRef, className: 'fc-scroller-harness' + (props.liquid ? ' fc-scroller-harness-liquid' : '') },
205
- preact.createElement(internal$1.Scroller, { ref: this.handleScroller, elRef: this.props.scrollerElRef, overflowX: overflowX === 'scroll-hidden' ? 'scroll' : overflowX, overflowY: overflowY === 'scroll-hidden' ? 'scroll' : overflowY, overcomeLeft: overcomeLeft, overcomeRight: overcomeRight, overcomeBottom: overcomeBottom, maxHeight: typeof props.maxHeight === 'number'
206
- ? (props.maxHeight + (overflowX === 'scroll-hidden' ? state.xScrollbarWidth : 0))
207
- : '', liquid: props.liquid, liquidIsAbsolute: true }, props.children)));
208
- }
209
- componentDidMount() {
210
- this.handleSizing();
211
- this.context.addResizeHandler(this.handleSizing);
212
- }
213
- getSnapshotBeforeUpdate(prevProps) {
214
- if (this.props.forPrint && !prevProps.forPrint) {
215
- return { simulateScrollLeft: this.scroller.el.scrollLeft };
216
- }
217
- return {};
218
- }
219
- componentDidUpdate(prevProps, prevState, snapshot) {
220
- const { props, scroller: { el: scrollerEl } } = this;
221
- if (!internal$1.isPropsEqual(prevProps, props)) { // an external change?
222
- this.handleSizing();
223
- }
224
- if (snapshot.simulateScrollLeft !== undefined) {
225
- scrollerEl.style.left = -snapshot.simulateScrollLeft + 'px';
226
- }
227
- else if (!props.forPrint && prevProps.forPrint) {
228
- const restoredScrollLeft = -parseInt(scrollerEl.style.left);
229
- scrollerEl.style.left = '';
230
- scrollerEl.scrollLeft = restoredScrollLeft;
231
- }
232
- }
233
- componentWillUnmount() {
234
- this.context.removeResizeHandler(this.handleSizing);
235
- }
236
- needsXScrolling() {
237
- return this.scroller.needsXScrolling();
238
- }
239
- needsYScrolling() {
240
- return this.scroller.needsYScrolling();
241
- }
242
- }
243
-
244
13
  const WHEEL_EVENT_NAMES = 'wheel mousewheel DomMouseScroll MozMousePixelScroll'.split(' ');
245
14
  /*
246
15
  ALSO, with the ability to disable touch
@@ -284,7 +53,7 @@ FullCalendar.ScrollGrid = (function (exports, core, premiumCommonPlugin, interna
284
53
  el.addEventListener('touchstart', this.handleTouchStart, { passive: true });
285
54
  el.addEventListener('touchend', this.handleTouchEnd);
286
55
  for (let eventName of WHEEL_EVENT_NAMES) {
287
- el.addEventListener(eventName, this.handleWheel);
56
+ el.addEventListener(eventName, this.handleWheel, { passive: true });
288
57
  }
289
58
  }
290
59
  destroy() {
@@ -293,7 +62,7 @@ FullCalendar.ScrollGrid = (function (exports, core, premiumCommonPlugin, interna
293
62
  el.removeEventListener('touchstart', this.handleTouchStart, { passive: true });
294
63
  el.removeEventListener('touchend', this.handleTouchEnd);
295
64
  for (let eventName of WHEEL_EVENT_NAMES) {
296
- el.removeEventListener(eventName, this.handleWheel);
65
+ el.removeEventListener(eventName, this.handleWheel, { passive: true });
297
66
  }
298
67
  }
299
68
  // Start / Stop
@@ -327,20 +96,59 @@ FullCalendar.ScrollGrid = (function (exports, core, premiumCommonPlugin, interna
327
96
  }
328
97
  }
329
98
 
330
- class ScrollSyncer {
331
- constructor(isVertical, scrollEls) {
332
- this.isVertical = isVertical;
333
- this.scrollEls = scrollEls;
99
+ class ScrollerSyncer {
100
+ constructor(isHorizontal = false) {
101
+ this.isHorizontal = isHorizontal;
102
+ this.scrollers = []; // TODO: move away from requiring Scroller
103
+ this.scrollListeners = [];
334
104
  this.isPaused = false;
335
- this.scrollListeners = scrollEls.map((el) => this.bindScroller(el));
105
+ }
106
+ handleChildren(scrollers, isRtl) {
107
+ if (!internal$1.isArraysEqual(this.scrollers, scrollers)) {
108
+ this.destroy();
109
+ this.scrollers = scrollers;
110
+ const scrollListeners = [];
111
+ for (const scroller of scrollers) {
112
+ if (scroller) { // could be null
113
+ scrollListeners.push(this.bindScroller(scroller.el));
114
+ }
115
+ }
116
+ this.scrollListeners = scrollListeners;
117
+ }
118
+ this.isRtl = isRtl;
336
119
  }
337
120
  destroy() {
338
121
  for (let scrollListener of this.scrollListeners) {
339
122
  scrollListener.destroy();
340
123
  }
341
124
  }
125
+ get x() {
126
+ const { scrollListeners, masterEl, isRtl } = this;
127
+ const el = masterEl || (scrollListeners.length ? scrollListeners[0].el : undefined);
128
+ return internal$1.getNormalizedScrollX(el, isRtl);
129
+ }
130
+ get y() {
131
+ const { scrollListeners, masterEl } = this;
132
+ const el = masterEl || (scrollListeners.length ? scrollListeners[0].el : undefined);
133
+ return el.scrollTop;
134
+ }
135
+ scrollTo({ x, y }) {
136
+ this.isPaused = true;
137
+ const { scrollListeners, isRtl } = this;
138
+ if (y != null) {
139
+ for (let scrollListener of scrollListeners) {
140
+ scrollListener.el.scrollTop = y;
141
+ }
142
+ }
143
+ if (x != null) {
144
+ for (let scrollListener of scrollListeners) {
145
+ internal$1.setNormalizedScrollX(scrollListener.el, isRtl, x);
146
+ }
147
+ }
148
+ this.isPaused = false;
149
+ }
342
150
  bindScroller(el) {
343
- let { scrollEls, isVertical } = this;
151
+ let { isHorizontal } = this;
344
152
  let scrollListener = new ScrollListener(el);
345
153
  const onScroll = (isWheel, isTouch) => {
346
154
  if (!this.isPaused) {
@@ -348,13 +156,14 @@ FullCalendar.ScrollGrid = (function (exports, core, premiumCommonPlugin, interna
348
156
  this.assignMaster(el);
349
157
  }
350
158
  if (this.masterEl === el) { // dealing with current
351
- for (let otherEl of scrollEls) {
159
+ for (let scrollListener of this.scrollListeners) {
160
+ const otherEl = scrollListener.el;
352
161
  if (otherEl !== el) {
353
- if (isVertical) {
354
- otherEl.scrollTop = el.scrollTop;
162
+ if (isHorizontal) {
163
+ otherEl.scrollLeft = el.scrollLeft;
355
164
  }
356
165
  else {
357
- otherEl.scrollLeft = el.scrollLeft;
166
+ otherEl.scrollTop = el.scrollTop;
358
167
  }
359
168
  }
360
169
  }
@@ -378,496 +187,20 @@ FullCalendar.ScrollGrid = (function (exports, core, premiumCommonPlugin, interna
378
187
  }
379
188
  }
380
189
  }
381
- /*
382
- will normalize the scrollLeft value
383
- */
384
- forceScrollLeft(scrollLeft) {
385
- this.isPaused = true;
386
- for (let listener of this.scrollListeners) {
387
- setScrollFromLeftEdge(listener.el, scrollLeft);
388
- }
389
- this.isPaused = false;
390
- }
391
- forceScrollTop(top) {
392
- this.isPaused = true;
393
- for (let listener of this.scrollListeners) {
394
- listener.el.scrollTop = top;
395
- }
396
- this.isPaused = false;
397
- }
398
- }
399
-
400
- internal$1.config.SCROLLGRID_RESIZE_INTERVAL = 500;
401
- /*
402
- TODO: make <ScrollGridSection> subcomponent
403
- NOTE: doesn't support collapsibleWidth (which is sortof a hack anyway)
404
- */
405
- class ScrollGrid extends internal$1.BaseComponent {
406
- constructor() {
407
- super(...arguments);
408
- this.compileColGroupStats = internal$1.memoizeArraylike(compileColGroupStat, isColGroupStatsEqual);
409
- this.renderMicroColGroups = internal$1.memoizeArraylike(internal$1.renderMicroColGroup); // yucky to memoize VNodes, but much more efficient for consumers
410
- this.clippedScrollerRefs = new internal$1.RefMap();
411
- // doesn't hold non-scrolling els used just for padding
412
- this.scrollerElRefs = new internal$1.RefMap(this._handleScrollerEl.bind(this));
413
- this.chunkElRefs = new internal$1.RefMap(this._handleChunkEl.bind(this));
414
- this.scrollSyncersBySection = {};
415
- this.scrollSyncersByColumn = {};
416
- // for row-height-syncing
417
- this.rowUnstableMap = new Map(); // no need to groom. always self-cancels
418
- this.rowInnerMaxHeightMap = new Map();
419
- this.anyRowHeightsChanged = false;
420
- this.recentSizingCnt = 0;
421
- this.state = {
422
- shrinkWidths: [],
423
- forceYScrollbars: false,
424
- forceXScrollbars: false,
425
- scrollerClientWidths: {},
426
- scrollerClientHeights: {},
427
- sectionRowMaxHeights: [],
428
- };
429
- this.handleSizing = (isForcedResize, sectionRowMaxHeightsChanged) => {
430
- if (!this.allowSizing()) {
431
- return;
432
- }
433
- if (!sectionRowMaxHeightsChanged) { // something else changed, probably external
434
- this.anyRowHeightsChanged = true;
435
- }
436
- let otherState = {};
437
- // if reacting to self-change of sectionRowMaxHeightsChanged, or not stable, don't do anything
438
- if (isForcedResize || (!sectionRowMaxHeightsChanged && !this.rowUnstableMap.size)) {
439
- otherState.sectionRowMaxHeights = this.computeSectionRowMaxHeights();
440
- }
441
- this.setState(Object.assign(Object.assign({ shrinkWidths: this.computeShrinkWidths() }, this.computeScrollerDims()), otherState), () => {
442
- if (!this.rowUnstableMap.size) {
443
- this.updateStickyScrolling(); // needs to happen AFTER final positioning committed to DOM
444
- }
445
- });
446
- };
447
- this.handleRowHeightChange = (rowEl, isStable) => {
448
- let { rowUnstableMap, rowInnerMaxHeightMap } = this;
449
- if (!isStable) {
450
- rowUnstableMap.set(rowEl, true);
451
- }
452
- else {
453
- rowUnstableMap.delete(rowEl);
454
- let innerMaxHeight = getRowInnerMaxHeight(rowEl);
455
- if (!rowInnerMaxHeightMap.has(rowEl) || rowInnerMaxHeightMap.get(rowEl) !== innerMaxHeight) {
456
- rowInnerMaxHeightMap.set(rowEl, innerMaxHeight);
457
- this.anyRowHeightsChanged = true;
458
- }
459
- if (!rowUnstableMap.size && this.anyRowHeightsChanged) {
460
- this.anyRowHeightsChanged = false;
461
- this.setState({
462
- sectionRowMaxHeights: this.computeSectionRowMaxHeights(),
463
- });
464
- }
465
- }
466
- };
467
- }
468
- render() {
469
- let { props, state, context } = this;
470
- let { shrinkWidths } = state;
471
- let colGroupStats = this.compileColGroupStats(props.colGroups.map((colGroup) => [colGroup]));
472
- let microColGroupNodes = this.renderMicroColGroups(colGroupStats.map((stat, i) => [stat.cols, shrinkWidths[i]]));
473
- let classNames = internal$1.getScrollGridClassNames(props.liquid, context);
474
- this.getDims();
475
- // TODO: make DRY
476
- let sectionConfigs = props.sections;
477
- let configCnt = sectionConfigs.length;
478
- let configI = 0;
479
- let currentConfig;
480
- let headSectionNodes = [];
481
- let bodySectionNodes = [];
482
- let footSectionNodes = [];
483
- while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'header') {
484
- headSectionNodes.push(this.renderSection(currentConfig, configI, colGroupStats, microColGroupNodes, state.sectionRowMaxHeights, true));
485
- configI += 1;
486
- }
487
- while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'body') {
488
- bodySectionNodes.push(this.renderSection(currentConfig, configI, colGroupStats, microColGroupNodes, state.sectionRowMaxHeights, false));
489
- configI += 1;
490
- }
491
- while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'footer') {
492
- footSectionNodes.push(this.renderSection(currentConfig, configI, colGroupStats, microColGroupNodes, state.sectionRowMaxHeights, true));
493
- configI += 1;
494
- }
495
- const isBuggy = !internal$1.getCanVGrowWithinCell(); // see NOTE in SimpleScrollGrid
496
- const roleAttrs = { role: 'rowgroup' };
497
- return preact.createElement('table', {
498
- ref: props.elRef,
499
- role: 'grid',
500
- className: classNames.join(' '),
501
- }, renderMacroColGroup(colGroupStats, shrinkWidths), Boolean(!isBuggy && headSectionNodes.length) && preact.createElement('thead', roleAttrs, ...headSectionNodes), Boolean(!isBuggy && bodySectionNodes.length) && preact.createElement('tbody', roleAttrs, ...bodySectionNodes), Boolean(!isBuggy && footSectionNodes.length) && preact.createElement('tfoot', roleAttrs, ...footSectionNodes), isBuggy && preact.createElement('tbody', roleAttrs, ...headSectionNodes, ...bodySectionNodes, ...footSectionNodes));
502
- }
503
- renderSection(sectionConfig, sectionIndex, colGroupStats, microColGroupNodes, sectionRowMaxHeights, isHeader) {
504
- if ('outerContent' in sectionConfig) {
505
- return (preact.createElement(preact.Fragment, { key: sectionConfig.key }, sectionConfig.outerContent));
506
- }
507
- return (preact.createElement("tr", { key: sectionConfig.key, role: "presentation", className: internal$1.getSectionClassNames(sectionConfig, this.props.liquid).join(' ') }, sectionConfig.chunks.map((chunkConfig, i) => this.renderChunk(sectionConfig, sectionIndex, colGroupStats[i], microColGroupNodes[i], chunkConfig, i, (sectionRowMaxHeights[sectionIndex] || [])[i] || [], isHeader))));
508
- }
509
- renderChunk(sectionConfig, sectionIndex, colGroupStat, microColGroupNode, chunkConfig, chunkIndex, rowHeights, isHeader) {
510
- if ('outerContent' in chunkConfig) {
511
- return (preact.createElement(preact.Fragment, { key: chunkConfig.key }, chunkConfig.outerContent));
512
- }
513
- let { state } = this;
514
- let { scrollerClientWidths, scrollerClientHeights } = state;
515
- let [sectionCnt, chunksPerSection] = this.getDims();
516
- let index = sectionIndex * chunksPerSection + chunkIndex;
517
- let sideScrollIndex = (!this.context.isRtl || internal$1.getIsRtlScrollbarOnLeft()) ? chunksPerSection - 1 : 0;
518
- let isVScrollSide = chunkIndex === sideScrollIndex;
519
- let isLastSection = sectionIndex === sectionCnt - 1;
520
- let forceXScrollbars = isLastSection && state.forceXScrollbars; // NOOOO can result in `null`
521
- let forceYScrollbars = isVScrollSide && state.forceYScrollbars; // NOOOO can result in `null`
522
- let allowXScrolling = colGroupStat && colGroupStat.allowXScrolling; // rename?
523
- let allowYScrolling = internal$1.getAllowYScrolling(this.props, sectionConfig); // rename? do in section func?
524
- let chunkVGrow = internal$1.getSectionHasLiquidHeight(this.props, sectionConfig); // do in section func?
525
- let expandRows = sectionConfig.expandRows && chunkVGrow;
526
- let tableMinWidth = (colGroupStat && colGroupStat.totalColMinWidth) || '';
527
- let content = internal$1.renderChunkContent(sectionConfig, chunkConfig, {
528
- tableColGroupNode: microColGroupNode,
529
- tableMinWidth,
530
- clientWidth: scrollerClientWidths[index] !== undefined ? scrollerClientWidths[index] : null,
531
- clientHeight: scrollerClientHeights[index] !== undefined ? scrollerClientHeights[index] : null,
532
- expandRows,
533
- syncRowHeights: Boolean(sectionConfig.syncRowHeights),
534
- rowSyncHeights: rowHeights,
535
- reportRowHeightChange: this.handleRowHeightChange,
536
- }, isHeader);
537
- let overflowX = forceXScrollbars ? (isLastSection ? 'scroll' : 'scroll-hidden') :
538
- !allowXScrolling ? 'hidden' :
539
- (isLastSection ? 'auto' : 'scroll-hidden');
540
- let overflowY = forceYScrollbars ? (isVScrollSide ? 'scroll' : 'scroll-hidden') :
541
- !allowYScrolling ? 'hidden' :
542
- (isVScrollSide ? 'auto' : 'scroll-hidden');
543
- // it *could* be possible to reduce DOM wrappers by only doing a ClippedScroller when allowXScrolling or allowYScrolling,
544
- // but if these values were to change, the inner components would be unmounted/remounted because of the parent change.
545
- content = (preact.createElement(ClippedScroller, { ref: this.clippedScrollerRefs.createRef(index), scrollerElRef: this.scrollerElRefs.createRef(index), overflowX: overflowX, overflowY: overflowY, forPrint: this.props.forPrint, liquid: chunkVGrow, maxHeight: sectionConfig.maxHeight }, content));
546
- return preact.createElement(isHeader ? 'th' : 'td', {
547
- key: chunkConfig.key,
548
- ref: this.chunkElRefs.createRef(index),
549
- role: 'presentation',
550
- }, content);
551
- }
552
- componentDidMount() {
553
- this.getStickyScrolling = internal$1.memoizeArraylike(initStickyScrolling);
554
- this.getScrollSyncersBySection = internal$1.memoizeHashlike(initScrollSyncer.bind(this, true), null, destroyScrollSyncer);
555
- this.getScrollSyncersByColumn = internal$1.memoizeHashlike(initScrollSyncer.bind(this, false), null, destroyScrollSyncer);
556
- this.updateScrollSyncers();
557
- this.handleSizing(false);
558
- this.context.addResizeHandler(this.handleSizing);
559
- }
560
- componentDidUpdate(prevProps, prevState) {
561
- this.updateScrollSyncers();
562
- // TODO: need better solution when state contains non-sizing things
563
- this.handleSizing(false, prevState.sectionRowMaxHeights !== this.state.sectionRowMaxHeights);
564
- }
565
- componentWillUnmount() {
566
- this.context.removeResizeHandler(this.handleSizing);
567
- this.destroyScrollSyncers();
568
- }
569
- allowSizing() {
570
- let now = new Date();
571
- if (!this.lastSizingDate ||
572
- now.valueOf() > this.lastSizingDate.valueOf() + internal$1.config.SCROLLGRID_RESIZE_INTERVAL) {
573
- this.lastSizingDate = now;
574
- this.recentSizingCnt = 0;
575
- return true;
576
- }
577
- return (this.recentSizingCnt += 1) <= 10;
578
- }
579
- computeShrinkWidths() {
580
- let colGroupStats = this.compileColGroupStats(this.props.colGroups.map((colGroup) => [colGroup]));
581
- let [sectionCnt, chunksPerSection] = this.getDims();
582
- let cnt = sectionCnt * chunksPerSection;
583
- let shrinkWidths = [];
584
- colGroupStats.forEach((colGroupStat, i) => {
585
- if (colGroupStat.hasShrinkCol) {
586
- let chunkEls = this.chunkElRefs.collect(i, cnt, chunksPerSection); // in one col
587
- shrinkWidths[i] = internal$1.computeShrinkWidth(chunkEls);
588
- }
589
- });
590
- return shrinkWidths;
591
- }
592
- // has the side effect of grooming rowInnerMaxHeightMap
593
- // TODO: somehow short-circuit if there are no new height changes
594
- computeSectionRowMaxHeights() {
595
- let newHeightMap = new Map();
596
- let [sectionCnt, chunksPerSection] = this.getDims();
597
- let sectionRowMaxHeights = [];
598
- for (let sectionI = 0; sectionI < sectionCnt; sectionI += 1) {
599
- let sectionConfig = this.props.sections[sectionI];
600
- let assignableHeights = []; // chunk, row
601
- if (sectionConfig && sectionConfig.syncRowHeights) {
602
- let rowHeightsByChunk = [];
603
- for (let chunkI = 0; chunkI < chunksPerSection; chunkI += 1) {
604
- let index = sectionI * chunksPerSection + chunkI;
605
- let rowHeights = [];
606
- let chunkEl = this.chunkElRefs.currentMap[index];
607
- if (chunkEl) {
608
- rowHeights = internal$1.findElements(chunkEl, '.fc-scrollgrid-sync-table tr').map((rowEl) => {
609
- let max = getRowInnerMaxHeight(rowEl);
610
- newHeightMap.set(rowEl, max);
611
- return max;
612
- });
613
- }
614
- else {
615
- rowHeights = [];
616
- }
617
- rowHeightsByChunk.push(rowHeights);
618
- }
619
- let rowCnt = rowHeightsByChunk[0].length;
620
- let isEqualRowCnt = true;
621
- for (let chunkI = 1; chunkI < chunksPerSection; chunkI += 1) {
622
- let isOuterContent = sectionConfig.chunks[chunkI] && sectionConfig.chunks[chunkI].outerContent !== undefined; // can be null
623
- if (!isOuterContent && rowHeightsByChunk[chunkI].length !== rowCnt) { // skip outer content
624
- isEqualRowCnt = false;
625
- break;
626
- }
627
- }
628
- if (!isEqualRowCnt) {
629
- let chunkHeightSums = [];
630
- for (let chunkI = 0; chunkI < chunksPerSection; chunkI += 1) {
631
- chunkHeightSums.push(sumNumbers(rowHeightsByChunk[chunkI]) + rowHeightsByChunk[chunkI].length);
632
- }
633
- let maxTotalSum = Math.max(...chunkHeightSums);
634
- for (let chunkI = 0; chunkI < chunksPerSection; chunkI += 1) {
635
- let rowInChunkCnt = rowHeightsByChunk[chunkI].length;
636
- let rowInChunkTotalHeight = maxTotalSum - rowInChunkCnt; // subtract border
637
- // height of non-first row. we do this to avoid rounding, because it's unreliable within a table
638
- let rowInChunkHeightOthers = Math.floor(rowInChunkTotalHeight / rowInChunkCnt);
639
- // whatever is leftover goes to the first row
640
- let rowInChunkHeightFirst = rowInChunkTotalHeight - rowInChunkHeightOthers * (rowInChunkCnt - 1);
641
- let rowInChunkHeights = [];
642
- let row = 0;
643
- if (row < rowInChunkCnt) {
644
- rowInChunkHeights.push(rowInChunkHeightFirst);
645
- row += 1;
646
- }
647
- while (row < rowInChunkCnt) {
648
- rowInChunkHeights.push(rowInChunkHeightOthers);
649
- row += 1;
650
- }
651
- assignableHeights.push(rowInChunkHeights);
652
- }
653
- }
654
- else {
655
- for (let chunkI = 0; chunkI < chunksPerSection; chunkI += 1) {
656
- assignableHeights.push([]);
657
- }
658
- for (let row = 0; row < rowCnt; row += 1) {
659
- let rowHeightsAcrossChunks = [];
660
- for (let chunkI = 0; chunkI < chunksPerSection; chunkI += 1) {
661
- let h = rowHeightsByChunk[chunkI][row];
662
- if (h != null) { // protect against outerContent
663
- rowHeightsAcrossChunks.push(h);
664
- }
665
- }
666
- let maxHeight = Math.max(...rowHeightsAcrossChunks);
667
- for (let chunkI = 0; chunkI < chunksPerSection; chunkI += 1) {
668
- assignableHeights[chunkI].push(maxHeight);
669
- }
670
- }
671
- }
672
- }
673
- sectionRowMaxHeights.push(assignableHeights);
674
- }
675
- this.rowInnerMaxHeightMap = newHeightMap;
676
- return sectionRowMaxHeights;
677
- }
678
- computeScrollerDims() {
679
- let scrollbarWidth = internal$1.getScrollbarWidths();
680
- let [sectionCnt, chunksPerSection] = this.getDims();
681
- let sideScrollI = (!this.context.isRtl || internal$1.getIsRtlScrollbarOnLeft()) ? chunksPerSection - 1 : 0;
682
- let lastSectionI = sectionCnt - 1;
683
- let currentScrollers = this.clippedScrollerRefs.currentMap;
684
- let scrollerEls = this.scrollerElRefs.currentMap;
685
- let forceYScrollbars = false;
686
- let forceXScrollbars = false;
687
- let scrollerClientWidths = {};
688
- let scrollerClientHeights = {};
689
- for (let sectionI = 0; sectionI < sectionCnt; sectionI += 1) { // along edge
690
- let index = sectionI * chunksPerSection + sideScrollI;
691
- let scroller = currentScrollers[index];
692
- if (scroller && scroller.needsYScrolling()) {
693
- forceYScrollbars = true;
694
- break;
695
- }
696
- }
697
- for (let chunkI = 0; chunkI < chunksPerSection; chunkI += 1) { // along last row
698
- let index = lastSectionI * chunksPerSection + chunkI;
699
- let scroller = currentScrollers[index];
700
- if (scroller && scroller.needsXScrolling()) {
701
- forceXScrollbars = true;
702
- break;
703
- }
704
- }
705
- for (let sectionI = 0; sectionI < sectionCnt; sectionI += 1) {
706
- for (let chunkI = 0; chunkI < chunksPerSection; chunkI += 1) {
707
- let index = sectionI * chunksPerSection + chunkI;
708
- let scrollerEl = scrollerEls[index];
709
- if (scrollerEl) {
710
- // TODO: weird way to get this. need harness b/c doesn't include table borders
711
- let harnessEl = scrollerEl.parentNode;
712
- scrollerClientWidths[index] = Math.floor(harnessEl.getBoundingClientRect().width - ((chunkI === sideScrollI && forceYScrollbars)
713
- ? scrollbarWidth.y // use global because scroller might not have scrollbars yet but will need them in future
714
- : 0));
715
- scrollerClientHeights[index] = Math.floor(harnessEl.getBoundingClientRect().height - ((sectionI === lastSectionI && forceXScrollbars)
716
- ? scrollbarWidth.x // use global because scroller might not have scrollbars yet but will need them in future
717
- : 0));
718
- }
719
- }
720
- }
721
- return { forceYScrollbars, forceXScrollbars, scrollerClientWidths, scrollerClientHeights };
722
- }
723
- updateStickyScrolling() {
724
- let { isRtl } = this.context;
725
- let argsByKey = this.scrollerElRefs.getAll().map((scrollEl) => [scrollEl, isRtl]);
726
- this.getStickyScrolling(argsByKey)
727
- .forEach((stickyScrolling) => stickyScrolling.updateSize());
728
- }
729
- updateScrollSyncers() {
730
- let [sectionCnt, chunksPerSection] = this.getDims();
731
- let cnt = sectionCnt * chunksPerSection;
732
- let scrollElsBySection = {};
733
- let scrollElsByColumn = {};
734
- let scrollElMap = this.scrollerElRefs.currentMap;
735
- for (let sectionI = 0; sectionI < sectionCnt; sectionI += 1) {
736
- let startIndex = sectionI * chunksPerSection;
737
- let endIndex = startIndex + chunksPerSection;
738
- scrollElsBySection[sectionI] = internal$1.collectFromHash(scrollElMap, startIndex, endIndex, 1); // use the filtered
739
- }
740
- for (let col = 0; col < chunksPerSection; col += 1) {
741
- scrollElsByColumn[col] = this.scrollerElRefs.collect(col, cnt, chunksPerSection); // DON'T use the filtered
742
- }
743
- this.scrollSyncersBySection = this.getScrollSyncersBySection(scrollElsBySection);
744
- this.scrollSyncersByColumn = this.getScrollSyncersByColumn(scrollElsByColumn);
745
- }
746
- destroyScrollSyncers() {
747
- internal$1.mapHash(this.scrollSyncersBySection, destroyScrollSyncer);
748
- internal$1.mapHash(this.scrollSyncersByColumn, destroyScrollSyncer);
749
- }
750
- getChunkConfigByIndex(index) {
751
- let chunksPerSection = this.getDims()[1];
752
- let sectionI = Math.floor(index / chunksPerSection);
753
- let chunkI = index % chunksPerSection;
754
- let sectionConfig = this.props.sections[sectionI];
755
- return sectionConfig && sectionConfig.chunks[chunkI];
756
- }
757
- forceScrollLeft(col, scrollLeft) {
758
- let scrollSyncer = this.scrollSyncersByColumn[col];
759
- if (scrollSyncer) {
760
- scrollSyncer.forceScrollLeft(scrollLeft);
761
- }
762
- }
763
- forceScrollTop(sectionI, scrollTop) {
764
- let scrollSyncer = this.scrollSyncersBySection[sectionI];
765
- if (scrollSyncer) {
766
- scrollSyncer.forceScrollTop(scrollTop);
767
- }
768
- }
769
- _handleChunkEl(chunkEl, key) {
770
- let chunkConfig = this.getChunkConfigByIndex(parseInt(key, 10));
771
- if (chunkConfig) { // null if section disappeared. bad, b/c won't null-set the elRef
772
- internal$1.setRef(chunkConfig.elRef, chunkEl);
773
- }
774
- }
775
- _handleScrollerEl(scrollerEl, key) {
776
- let chunkConfig = this.getChunkConfigByIndex(parseInt(key, 10));
777
- if (chunkConfig) { // null if section disappeared. bad, b/c won't null-set the elRef
778
- internal$1.setRef(chunkConfig.scrollerElRef, scrollerEl);
779
- }
780
- }
781
- getDims() {
782
- let sectionCnt = this.props.sections.length;
783
- let chunksPerSection = sectionCnt ? this.props.sections[0].chunks.length : 0;
784
- return [sectionCnt, chunksPerSection];
785
- }
786
- }
787
- ScrollGrid.addStateEquality({
788
- shrinkWidths: internal$1.isArraysEqual,
789
- scrollerClientWidths: internal$1.isPropsEqual,
790
- scrollerClientHeights: internal$1.isPropsEqual,
791
- });
792
- function sumNumbers(numbers) {
793
- let sum = 0;
794
- for (let n of numbers) {
795
- sum += n;
796
- }
797
- return sum;
798
- }
799
- function getRowInnerMaxHeight(rowEl) {
800
- let innerHeights = internal$1.findElements(rowEl, '.fc-scrollgrid-sync-inner').map(getElHeight);
801
- if (innerHeights.length) {
802
- return Math.max(...innerHeights);
803
- }
804
- return 0;
805
- }
806
- function getElHeight(el) {
807
- return el.offsetHeight; // better to deal with integers, for rounding, for PureComponent
808
- }
809
- function renderMacroColGroup(colGroupStats, shrinkWidths) {
810
- let children = colGroupStats.map((colGroupStat, i) => {
811
- let width = colGroupStat.width;
812
- if (width === 'shrink') {
813
- width = colGroupStat.totalColWidth + internal$1.sanitizeShrinkWidth(shrinkWidths[i]) + 1; // +1 for border :(
814
- }
815
- return ( // eslint-disable-next-line react/jsx-key
816
- preact.createElement("col", { style: { width } }));
817
- });
818
- return preact.createElement('colgroup', {}, ...children);
819
- }
820
- function compileColGroupStat(colGroupConfig) {
821
- let totalColWidth = sumColProp(colGroupConfig.cols, 'width'); // excludes "shrink"
822
- let totalColMinWidth = sumColProp(colGroupConfig.cols, 'minWidth');
823
- let hasShrinkCol = internal$1.hasShrinkWidth(colGroupConfig.cols);
824
- let allowXScrolling = colGroupConfig.width !== 'shrink' && Boolean(totalColWidth || totalColMinWidth || hasShrinkCol);
825
- return {
826
- hasShrinkCol,
827
- totalColWidth,
828
- totalColMinWidth,
829
- allowXScrolling,
830
- cols: colGroupConfig.cols,
831
- width: colGroupConfig.width,
832
- };
833
- }
834
- function sumColProp(cols, propName) {
835
- let total = 0;
836
- for (let col of cols) {
837
- let val = col[propName];
838
- if (typeof val === 'number') {
839
- total += val * (col.span || 1);
840
- }
841
- }
842
- return total;
843
- }
844
- const COL_GROUP_STAT_EQUALITY = {
845
- cols: internal$1.isColPropsEqual,
846
- };
847
- function isColGroupStatsEqual(stat0, stat1) {
848
- return internal$1.compareObjs(stat0, stat1, COL_GROUP_STAT_EQUALITY);
849
- }
850
- // for memoizers...
851
- function initScrollSyncer(isVertical, ...scrollEls) {
852
- return new ScrollSyncer(isVertical, scrollEls);
853
- }
854
- function destroyScrollSyncer(scrollSyncer) {
855
- scrollSyncer.destroy();
856
- }
857
- function initStickyScrolling(scrollEl, isRtl) {
858
- return new StickyScrolling(scrollEl, isRtl);
859
190
  }
860
191
 
861
192
  var plugin = core.createPlugin({
862
193
  name: '@fullcalendar/scrollgrid',
863
- premiumReleaseDate: '2024-06-05',
194
+ premiumReleaseDate: '2024-10-01',
864
195
  deps: [premiumCommonPlugin__default["default"]],
865
- scrollGridImpl: ScrollGrid,
196
+ scrollerSyncerClass: ScrollerSyncer
866
197
  });
867
198
 
199
+ // new
200
+
868
201
  var internal = {
869
202
  __proto__: null,
870
- ScrollGrid: ScrollGrid
203
+ ScrollerSyncer: ScrollerSyncer
871
204
  };
872
205
 
873
206
  core.globalPlugins.push(plugin);
@@ -879,4 +212,4 @@ FullCalendar.ScrollGrid = (function (exports, core, premiumCommonPlugin, interna
879
212
 
880
213
  return exports;
881
214
 
882
- })({}, FullCalendar, FullCalendar.PremiumCommon, FullCalendar.Internal, FullCalendar.Preact);
215
+ })({}, FullCalendar, FullCalendar.PremiumCommon, FullCalendar.Internal);