@fullcalendar/timeline 5.7.2 → 5.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/main.cjs.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- FullCalendar Scheduler v5.7.2
2
+ FullCalendar Scheduler v5.10.1
3
3
  Docs & License: https://fullcalendar.io/scheduler
4
4
  (c) 2021 Adam Shaw
5
5
  */
@@ -466,10 +466,7 @@ var TimelineHeaderThInner = /** @class */ (function (_super) {
466
466
  }
467
467
  TimelineHeaderThInner.prototype.render = function () {
468
468
  var _a = this, props = _a.props, context = _a.context;
469
- var navLinkAttrs = props.navLinkData
470
- ? { 'data-navlink': props.navLinkData, tabIndex: 0 }
471
- : {};
472
- return (common.createElement(common.ContentHook, { hookProps: props.hookProps, content: context.options.slotLabelContent, defaultContent: renderInnerContent }, function (innerElRef, innerContent) { return (common.createElement("a", tslib.__assign({ ref: innerElRef, className: 'fc-timeline-slot-cushion fc-scrollgrid-sync-inner' + (props.isSticky ? ' fc-sticky' : '') }, navLinkAttrs), innerContent)); }));
469
+ return (common.createElement(common.ContentHook, { hookProps: props.hookProps, content: context.options.slotLabelContent, defaultContent: renderInnerContent }, function (innerElRef, innerContent) { return (common.createElement("a", tslib.__assign({ ref: innerElRef, className: 'fc-timeline-slot-cushion fc-scrollgrid-sync-inner' + (props.isSticky ? ' fc-sticky' : '') }, props.navLinkAttrs), innerContent)); }));
473
470
  };
474
471
  return TimelineHeaderThInner;
475
472
  }(common.BaseComponent));
@@ -491,9 +488,11 @@ var TimelineHeaderTh = /** @class */ (function (_super) {
491
488
  var _this = _super !== null && _super.apply(this, arguments) || this;
492
489
  _this.refineHookProps = common.memoizeObjArg(refineHookProps);
493
490
  _this.normalizeClassNames = common.buildClassNameNormalizer();
491
+ _this.buildCellNavLinkAttrs = common.memoize(buildCellNavLinkAttrs);
494
492
  return _this;
495
493
  }
496
494
  TimelineHeaderTh.prototype.render = function () {
495
+ var _this = this;
497
496
  var _a = this, props = _a.props, context = _a.context;
498
497
  var dateEnv = context.dateEnv, options = context.options;
499
498
  var cell = props.cell, dateProfile = props.dateProfile, tDateProfile = props.tDateProfile;
@@ -507,9 +506,6 @@ var TimelineHeaderTh = /** @class */ (function (_super) {
507
506
  if (cell.isWeekStart) {
508
507
  classNames.push('fc-timeline-slot-em');
509
508
  }
510
- var navLinkData = (options.navLinks && cell.rowUnit && cell.rowUnit !== 'time')
511
- ? common.buildNavLinkData(cell.date, cell.rowUnit)
512
- : null;
513
509
  var hookProps = this.refineHookProps({
514
510
  level: props.rowLevel,
515
511
  dateMarker: cell.date,
@@ -520,10 +516,15 @@ var TimelineHeaderTh = /** @class */ (function (_super) {
520
516
  var customClassNames = this.normalizeClassNames(options.slotLabelClassNames, hookProps);
521
517
  return (common.createElement(common.MountHook, { hookProps: hookProps, didMount: options.slotLabelDidMount, willUnmount: options.slotLabelWillUnmount }, function (rootElRef) { return (common.createElement("th", { ref: rootElRef, className: classNames.concat(customClassNames).join(' '), "data-date": dateEnv.formatIso(cell.date, { omitTime: !tDateProfile.isTimeScale, omitTimeZoneOffset: true }), colSpan: cell.colspan },
522
518
  common.createElement("div", { className: "fc-timeline-slot-frame", style: { height: props.rowInnerHeight } },
523
- common.createElement(TimelineHeaderThInner, { hookProps: hookProps, isSticky: props.isSticky, navLinkData: navLinkData })))); }));
519
+ common.createElement(TimelineHeaderThInner, { hookProps: hookProps, isSticky: props.isSticky, navLinkAttrs: _this.buildCellNavLinkAttrs(context, cell.date, cell.rowUnit) })))); }));
524
520
  };
525
521
  return TimelineHeaderTh;
526
522
  }(common.BaseComponent));
523
+ function buildCellNavLinkAttrs(context, cellDate, rowUnit) {
524
+ return (rowUnit && rowUnit !== 'time')
525
+ ? common.buildNavLinkAttrs(context, cellDate, rowUnit)
526
+ : {};
527
+ }
527
528
 
528
529
  var TimelineHeaderRows = /** @class */ (function (_super) {
529
530
  tslib.__extends(TimelineHeaderRows, _super);
@@ -547,49 +548,6 @@ var TimelineHeaderRows = /** @class */ (function (_super) {
547
548
  return TimelineHeaderRows;
548
549
  }(common.BaseComponent));
549
550
 
550
- var TimelineHeader = /** @class */ (function (_super) {
551
- tslib.__extends(TimelineHeader, _super);
552
- function TimelineHeader() {
553
- var _this = _super !== null && _super.apply(this, arguments) || this;
554
- _this.rootElRef = common.createRef();
555
- return _this;
556
- }
557
- TimelineHeader.prototype.render = function () {
558
- var _this = this;
559
- var _a = this, props = _a.props, context = _a.context;
560
- // TODO: very repetitive
561
- // TODO: make part of tDateProfile?
562
- var timerUnit = common.greatestDurationDenominator(props.tDateProfile.slotDuration).unit;
563
- // WORKAROUND: make ignore slatCoords when out of sync with dateProfile
564
- var slatCoords = props.slatCoords && props.slatCoords.dateProfile === props.dateProfile ? props.slatCoords : null;
565
- return (common.createElement(common.NowTimer, { unit: timerUnit }, function (nowDate, todayRange) { return (common.createElement("div", { className: "fc-timeline-header", ref: _this.rootElRef },
566
- common.createElement("table", { className: "fc-scrollgrid-sync-table", style: { minWidth: props.tableMinWidth, width: props.clientWidth } },
567
- props.tableColGroupNode,
568
- common.createElement("tbody", null,
569
- common.createElement(TimelineHeaderRows, { dateProfile: props.dateProfile, tDateProfile: props.tDateProfile, nowDate: nowDate, todayRange: todayRange, rowInnerHeights: props.rowInnerHeights }))),
570
- context.options.nowIndicator && (
571
- // need to have a container regardless of whether the current view has a visible now indicator
572
- // because apparently removal of the element resets the scroll for some reasons (issue #5351).
573
- // this issue doesn't happen for the timeline body however (
574
- common.createElement("div", { className: "fc-timeline-now-indicator-container" }, (slatCoords && slatCoords.isDateInRange(nowDate)) && (common.createElement(common.NowIndicatorRoot, { isAxis: true, date: nowDate }, function (rootElRef, classNames, innerElRef, innerContent) { return (common.createElement("div", { ref: rootElRef, className: ['fc-timeline-now-indicator-arrow'].concat(classNames).join(' '), style: { left: slatCoords.dateToCoord(nowDate) } }, innerContent)); })))))); }));
575
- };
576
- TimelineHeader.prototype.componentDidMount = function () {
577
- this.updateSize();
578
- };
579
- TimelineHeader.prototype.componentDidUpdate = function () {
580
- this.updateSize();
581
- };
582
- TimelineHeader.prototype.updateSize = function () {
583
- if (this.props.onMaxCushionWidth) {
584
- this.props.onMaxCushionWidth(this.computeMaxCushionWidth());
585
- }
586
- };
587
- TimelineHeader.prototype.computeMaxCushionWidth = function () {
588
- return Math.max.apply(Math, common.findElements(this.rootElRef.current, '.fc-timeline-header-row:last-child .fc-timeline-slot-cushion').map(function (el) { return el.getBoundingClientRect().width; }));
589
- };
590
- return TimelineHeader;
591
- }(common.BaseComponent));
592
-
593
551
  var TimelineCoords = /** @class */ (function () {
594
552
  function TimelineCoords(slatRootEl, // okay to expose?
595
553
  slatEls, dateProfile, tDateProfile, dateEnv, isRtl) {
@@ -605,17 +563,10 @@ var TimelineCoords = /** @class */ (function () {
605
563
  this.innerCoordCache = new common.PositionCache(slatRootEl, common.findDirectChildren(slatEls, 'div'), true, // isHorizontal
606
564
  false);
607
565
  }
608
- TimelineCoords.prototype.rangeToCoords = function (range) {
609
- if (this.isRtl) {
610
- return { right: this.dateToCoord(range.start), left: this.dateToCoord(range.end) };
611
- }
612
- return { left: this.dateToCoord(range.start), right: this.dateToCoord(range.end) };
613
- };
614
566
  TimelineCoords.prototype.isDateInRange = function (date) {
615
567
  return common.rangeContainsMarker(this.dateProfile.currentRange, date);
616
568
  };
617
- // for LTR, results range from 0 to width of area
618
- // for RTL, results range from negative width of area to 0
569
+ // results range from negative width of area to 0
619
570
  TimelineCoords.prototype.dateToCoord = function (date) {
620
571
  var tDateProfile = this.tDateProfile;
621
572
  var snapCoverage = this.computeDateSnapCoverage(date);
@@ -625,31 +576,43 @@ var TimelineCoords = /** @class */ (function () {
625
576
  var partial = slotCoverage - slotIndex;
626
577
  var _a = this, innerCoordCache = _a.innerCoordCache, outerCoordCache = _a.outerCoordCache;
627
578
  if (this.isRtl) {
628
- return (outerCoordCache.rights[slotIndex] -
629
- (innerCoordCache.getWidth(slotIndex) * partial)) - outerCoordCache.originClientRect.width;
579
+ return outerCoordCache.originClientRect.width - (outerCoordCache.rights[slotIndex] -
580
+ (innerCoordCache.getWidth(slotIndex) * partial));
630
581
  }
631
582
  return (outerCoordCache.lefts[slotIndex] +
632
583
  (innerCoordCache.getWidth(slotIndex) * partial));
633
584
  };
634
- // returned value is between 0 and the number of snaps
635
- TimelineCoords.prototype.computeDateSnapCoverage = function (date) {
636
- return computeDateSnapCoverage(date, this.tDateProfile, this.dateEnv);
585
+ TimelineCoords.prototype.rangeToCoords = function (range) {
586
+ return {
587
+ start: this.dateToCoord(range.start),
588
+ end: this.dateToCoord(range.end),
589
+ };
637
590
  };
638
- TimelineCoords.prototype.computeDurationLeft = function (duration) {
591
+ TimelineCoords.prototype.durationToCoord = function (duration) {
639
592
  var _a = this, dateProfile = _a.dateProfile, tDateProfile = _a.tDateProfile, dateEnv = _a.dateEnv, isRtl = _a.isRtl;
640
- var left = 0;
593
+ var coord = 0;
641
594
  if (dateProfile) {
642
595
  var date = dateEnv.add(dateProfile.activeRange.start, duration);
643
596
  if (!tDateProfile.isTimeScale) {
644
597
  date = common.startOfDay(date);
645
598
  }
646
- left = this.dateToCoord(date);
599
+ coord = this.dateToCoord(date);
647
600
  // hack to overcome the left borders of non-first slat
648
- if (!isRtl && left) {
649
- left += 1;
601
+ if (!isRtl && coord) {
602
+ coord += 1;
650
603
  }
651
604
  }
652
- return left;
605
+ return coord;
606
+ };
607
+ TimelineCoords.prototype.coordFromLeft = function (coord) {
608
+ if (this.isRtl) {
609
+ return this.outerCoordCache.originClientRect.width - coord;
610
+ }
611
+ return coord;
612
+ };
613
+ // returned value is between 0 and the number of snaps
614
+ TimelineCoords.prototype.computeDateSnapCoverage = function (date) {
615
+ return computeDateSnapCoverage(date, this.tDateProfile, this.dateEnv);
653
616
  };
654
617
  return TimelineCoords;
655
618
  }());
@@ -674,6 +637,67 @@ function computeDateSnapCoverage(date, tDateProfile, dateEnv) {
674
637
  }
675
638
  return snapCoverage;
676
639
  }
640
+ function coordToCss(hcoord, isRtl) {
641
+ if (hcoord === null) {
642
+ return { left: '', right: '' };
643
+ }
644
+ if (isRtl) {
645
+ return { right: hcoord, left: '' };
646
+ }
647
+ return { left: hcoord, right: '' };
648
+ }
649
+ function coordsToCss(hcoords, isRtl) {
650
+ if (!hcoords) {
651
+ return { left: '', right: '' };
652
+ }
653
+ if (isRtl) {
654
+ return { right: hcoords.start, left: -hcoords.end };
655
+ }
656
+ return { left: hcoords.start, right: -hcoords.end };
657
+ }
658
+
659
+ var TimelineHeader = /** @class */ (function (_super) {
660
+ tslib.__extends(TimelineHeader, _super);
661
+ function TimelineHeader() {
662
+ var _this = _super !== null && _super.apply(this, arguments) || this;
663
+ _this.rootElRef = common.createRef();
664
+ return _this;
665
+ }
666
+ TimelineHeader.prototype.render = function () {
667
+ var _this = this;
668
+ var _a = this, props = _a.props, context = _a.context;
669
+ // TODO: very repetitive
670
+ // TODO: make part of tDateProfile?
671
+ var timerUnit = common.greatestDurationDenominator(props.tDateProfile.slotDuration).unit;
672
+ // WORKAROUND: make ignore slatCoords when out of sync with dateProfile
673
+ var slatCoords = props.slatCoords && props.slatCoords.dateProfile === props.dateProfile ? props.slatCoords : null;
674
+ return (common.createElement(common.NowTimer, { unit: timerUnit }, function (nowDate, todayRange) { return (common.createElement("div", { className: "fc-timeline-header", ref: _this.rootElRef },
675
+ common.createElement("table", { "aria-hidden": true, className: "fc-scrollgrid-sync-table", style: { minWidth: props.tableMinWidth, width: props.clientWidth } },
676
+ props.tableColGroupNode,
677
+ common.createElement("tbody", null,
678
+ common.createElement(TimelineHeaderRows, { dateProfile: props.dateProfile, tDateProfile: props.tDateProfile, nowDate: nowDate, todayRange: todayRange, rowInnerHeights: props.rowInnerHeights }))),
679
+ context.options.nowIndicator && (
680
+ // need to have a container regardless of whether the current view has a visible now indicator
681
+ // because apparently removal of the element resets the scroll for some reasons (issue #5351).
682
+ // this issue doesn't happen for the timeline body however (
683
+ common.createElement("div", { className: "fc-timeline-now-indicator-container" }, (slatCoords && slatCoords.isDateInRange(nowDate)) && (common.createElement(common.NowIndicatorRoot, { isAxis: true, date: nowDate }, function (rootElRef, classNames, innerElRef, innerContent) { return (common.createElement("div", { ref: rootElRef, className: ['fc-timeline-now-indicator-arrow'].concat(classNames).join(' '), style: coordToCss(slatCoords.dateToCoord(nowDate), context.isRtl) }, innerContent)); })))))); }));
684
+ };
685
+ TimelineHeader.prototype.componentDidMount = function () {
686
+ this.updateSize();
687
+ };
688
+ TimelineHeader.prototype.componentDidUpdate = function () {
689
+ this.updateSize();
690
+ };
691
+ TimelineHeader.prototype.updateSize = function () {
692
+ if (this.props.onMaxCushionWidth) {
693
+ this.props.onMaxCushionWidth(this.computeMaxCushionWidth());
694
+ }
695
+ };
696
+ TimelineHeader.prototype.computeMaxCushionWidth = function () {
697
+ return Math.max.apply(Math, common.findElements(this.rootElRef.current, '.fc-timeline-header-row:last-child .fc-timeline-slot-cushion').map(function (el) { return el.getBoundingClientRect().width; }));
698
+ };
699
+ return TimelineHeader;
700
+ }(common.BaseComponent));
677
701
 
678
702
  var TimelineSlatCell = /** @class */ (function (_super) {
679
703
  tslib.__extends(TimelineSlatCell, _super);
@@ -735,7 +759,7 @@ var TimelineSlats = /** @class */ (function (_super) {
735
759
  var coords = _this.coords;
736
760
  if (onScrollLeftRequest && coords) {
737
761
  if (request.time) {
738
- var scrollLeft = coords.computeDurationLeft(request.time);
762
+ var scrollLeft = coords.coordFromLeft(coords.durationToCoord(request.time));
739
763
  onScrollLeftRequest(scrollLeft);
740
764
  }
741
765
  return true;
@@ -747,7 +771,7 @@ var TimelineSlats = /** @class */ (function (_super) {
747
771
  TimelineSlats.prototype.render = function () {
748
772
  var _a = this, props = _a.props, context = _a.context;
749
773
  return (common.createElement("div", { className: "fc-timeline-slots", ref: this.rootElRef },
750
- common.createElement("table", { className: context.theme.getClass('table'), style: {
774
+ common.createElement("table", { "aria-hidden": true, className: context.theme.getClass('table'), style: {
751
775
  minWidth: props.tableMinWidth,
752
776
  width: props.clientWidth,
753
777
  } },
@@ -775,7 +799,7 @@ var TimelineSlats = /** @class */ (function (_super) {
775
799
  // ^it's possible to have clientWidth immediately after mount (when returning from print view), but w/o scrollResponder
776
800
  ) {
777
801
  var rootEl = this.rootElRef.current;
778
- if (rootEl.offsetWidth) {
802
+ if (rootEl.offsetWidth) { // not hidden by css
779
803
  this.coords = new TimelineCoords(this.rootElRef.current, collectCellEls(this.cellElRefs.currentMap, props.tDateProfile.slotDates), props.dateProfile, props.tDateProfile, context.dateEnv, context.isRtl);
780
804
  if (props.onCoords) {
781
805
  props.onCoords(this.coords);
@@ -819,6 +843,109 @@ function collectCellEls(elMap, slotDates) {
819
843
  });
820
844
  }
821
845
 
846
+ function computeSegHCoords(segs, minWidth, timelineCoords) {
847
+ var hcoords = [];
848
+ if (timelineCoords) {
849
+ for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) {
850
+ var seg = segs_1[_i];
851
+ var res = timelineCoords.rangeToCoords(seg);
852
+ var start = Math.round(res.start); // for barely-overlapping collisions
853
+ var end = Math.round(res.end); //
854
+ if (end - start < minWidth) {
855
+ end = start + minWidth;
856
+ }
857
+ hcoords.push({ start: start, end: end });
858
+ }
859
+ }
860
+ return hcoords;
861
+ }
862
+ function computeFgSegPlacements(segs, segHCoords, // might not have for every seg
863
+ eventInstanceHeights, // might not have for every seg
864
+ moreLinkHeights, // might not have for every more-link
865
+ strictOrder, maxStackCnt) {
866
+ var segInputs = [];
867
+ var crudePlacements = []; // when we don't know dims
868
+ for (var i = 0; i < segs.length; i += 1) {
869
+ var seg = segs[i];
870
+ var instanceId = seg.eventRange.instance.instanceId;
871
+ var height = eventInstanceHeights[instanceId];
872
+ var hcoords = segHCoords[i];
873
+ if (height && hcoords) {
874
+ segInputs.push({
875
+ index: i,
876
+ span: hcoords,
877
+ thickness: height,
878
+ });
879
+ }
880
+ else {
881
+ crudePlacements.push({
882
+ seg: seg,
883
+ hcoords: hcoords,
884
+ top: null,
885
+ });
886
+ }
887
+ }
888
+ var hierarchy = new common.SegHierarchy();
889
+ if (strictOrder != null) {
890
+ hierarchy.strictOrder = strictOrder;
891
+ }
892
+ if (maxStackCnt != null) {
893
+ hierarchy.maxStackCnt = maxStackCnt;
894
+ }
895
+ var hiddenEntries = hierarchy.addSegs(segInputs);
896
+ var hiddenPlacements = hiddenEntries.map(function (entry) { return ({
897
+ seg: segs[entry.index],
898
+ hcoords: entry.span,
899
+ top: null,
900
+ }); });
901
+ var hiddenGroups = common.groupIntersectingEntries(hiddenEntries);
902
+ var moreLinkInputs = [];
903
+ var moreLinkCrudePlacements = [];
904
+ var extractSeg = function (entry) { return segs[entry.index]; };
905
+ for (var i = 0; i < hiddenGroups.length; i += 1) {
906
+ var hiddenGroup = hiddenGroups[i];
907
+ var sortedSegs = hiddenGroup.entries.map(extractSeg);
908
+ var height = moreLinkHeights[common.buildIsoString(common.computeEarliestSegStart(sortedSegs))]; // not optimal :(
909
+ if (height != null) {
910
+ // NOTE: the hiddenGroup's spanStart/spanEnd are already computed by rangeToCoords. computed during input.
911
+ moreLinkInputs.push({
912
+ index: segs.length + i,
913
+ thickness: height,
914
+ span: hiddenGroup.span,
915
+ });
916
+ }
917
+ else {
918
+ moreLinkCrudePlacements.push({
919
+ seg: sortedSegs,
920
+ hcoords: hiddenGroup.span,
921
+ top: null,
922
+ });
923
+ }
924
+ }
925
+ // add more-links into the hierarchy, but don't limit
926
+ hierarchy.maxStackCnt = -1;
927
+ hierarchy.addSegs(moreLinkInputs);
928
+ var visibleRects = hierarchy.toRects();
929
+ var visiblePlacements = [];
930
+ var maxHeight = 0;
931
+ for (var _i = 0, visibleRects_1 = visibleRects; _i < visibleRects_1.length; _i++) {
932
+ var rect = visibleRects_1[_i];
933
+ var segIndex = rect.index;
934
+ visiblePlacements.push({
935
+ seg: segIndex < segs.length
936
+ ? segs[segIndex] // a real seg
937
+ : hiddenGroups[segIndex - segs.length].entries.map(extractSeg),
938
+ hcoords: rect.span,
939
+ top: rect.levelCoord,
940
+ });
941
+ maxHeight = Math.max(maxHeight, rect.levelCoord + rect.thickness);
942
+ }
943
+ return [
944
+ visiblePlacements.concat(crudePlacements, hiddenPlacements, moreLinkCrudePlacements),
945
+ maxHeight,
946
+ ];
947
+ }
948
+
822
949
  var TimelineLaneBg = /** @class */ (function (_super) {
823
950
  tslib.__extends(TimelineLaneBg, _super);
824
951
  function TimelineLaneBg() {
@@ -834,12 +961,12 @@ var TimelineLaneBg = /** @class */ (function (_super) {
834
961
  };
835
962
  TimelineLaneBg.prototype.renderSegs = function (segs, timelineCoords, fillType) {
836
963
  var _a = this.props, todayRange = _a.todayRange, nowDate = _a.nowDate;
837
- var children = segs.map(function (seg) {
838
- var coords = timelineCoords.rangeToCoords(seg); // seg has { start, end }
839
- return (common.createElement("div", { key: common.buildEventRangeKey(seg.eventRange), className: "fc-timeline-bg-harness", style: {
840
- left: coords.left,
841
- right: -coords.right, // outwards from right edge (which is same as left edge)
842
- } }, fillType === 'bg-event' ?
964
+ var isRtl = this.context.isRtl;
965
+ var segHCoords = computeSegHCoords(segs, 0, timelineCoords);
966
+ var children = segs.map(function (seg, i) {
967
+ var hcoords = segHCoords[i];
968
+ var hStyle = coordsToCss(hcoords, isRtl);
969
+ return (common.createElement("div", { key: common.buildEventRangeKey(seg.eventRange), className: "fc-timeline-bg-harness", style: hStyle }, fillType === 'bg-event' ?
843
970
  common.createElement(common.BgEvent, tslib.__assign({ seg: seg }, common.getSegMeta(seg, todayRange, nowDate))) :
844
971
  common.renderFill(fillType)));
845
972
  });
@@ -904,144 +1031,36 @@ var TimelineLaneMoreLink = /** @class */ (function (_super) {
904
1031
  }
905
1032
  TimelineLaneMoreLink.prototype.render = function () {
906
1033
  var _this = this;
907
- var props = this.props;
1034
+ var _a = this, props = _a.props, context = _a.context;
908
1035
  var hiddenSegs = props.hiddenSegs, elRef = props.elRef, placement = props.placement, resourceId = props.resourceId;
1036
+ var top = placement.top, hcoords = placement.hcoords;
1037
+ var isVisible = hcoords && top !== null;
1038
+ var hStyle = coordsToCss(hcoords, context.isRtl);
909
1039
  var extraDateSpan = resourceId ? { resourceId: resourceId } : {};
910
1040
  return (common.createElement(common.MoreLinkRoot, { allDayDate: null, moreCnt: hiddenSegs.length, allSegs: hiddenSegs, hiddenSegs: hiddenSegs, alignmentElRef: this.rootElRef, dateProfile: props.dateProfile, todayRange: props.todayRange, extraDateSpan: extraDateSpan, popoverContent: function () { return (common.createElement(common.Fragment, null, hiddenSegs.map(function (seg) {
911
1041
  var instanceId = seg.eventRange.instance.instanceId;
912
1042
  return (common.createElement("div", { key: instanceId, style: { visibility: props.isForcedInvisible[instanceId] ? 'hidden' : '' } },
913
1043
  common.createElement(TimelineEvent, tslib.__assign({ isTimeScale: props.isTimeScale, seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === props.eventSelection }, common.getSegMeta(seg, props.todayRange, props.nowDate)))));
914
- }))); } }, function (rootElRef, classNames, innerElRef, innerContent, handleClick) { return (common.createElement("a", { ref: function (el) {
1044
+ }))); } }, function (rootElRef, classNames, innerElRef, innerContent, handleClick, title, isExpanded, popoverId) { return (common.createElement("a", { ref: function (el) {
915
1045
  common.setRef(rootElRef, el); // for MoreLinkRoot
916
1046
  common.setRef(elRef, el); // for props props
917
1047
  common.setRef(_this.rootElRef, el); // for this component
918
- }, className: ['fc-timeline-more-link'].concat(classNames).join(' '), style: {
919
- left: placement.left,
920
- right: -placement.right,
921
- top: placement.top,
922
- visibility: placement.isVisible ? '' : 'hidden',
923
- }, onClick: handleClick },
1048
+ }, className: ['fc-timeline-more-link'].concat(classNames).join(' '), style: tslib.__assign({ visibility: isVisible ? '' : 'hidden', top: top || 0 }, hStyle), onClick: handleClick, title: title, "aria-expanded": isExpanded, "aria-controls": popoverId },
924
1049
  common.createElement("div", { ref: innerElRef, className: "fc-timeline-more-link-inner fc-sticky" }, innerContent))); }));
925
1050
  };
926
1051
  return TimelineLaneMoreLink;
927
1052
  }(common.BaseComponent));
928
1053
 
929
- function computeFgSegPlacements(segs, timelineCoords, eventInstanceHeights, moreLinkHeights, minWidth, isRtl, strictOrder, maxStackCnt) {
930
- var segInputs = [];
931
- var crudePlacements = []; // when we don't know height
932
- if (timelineCoords) {
933
- for (var i = 0; i < segs.length; i += 1) {
934
- var seg = segs[i];
935
- var instanceId = seg.eventRange.instance.instanceId;
936
- var height = eventInstanceHeights[instanceId];
937
- var horizontalCoords = timelineCoords.rangeToCoords(seg);
938
- var left = Math.round(horizontalCoords.left); // for barely-overlapping collisions
939
- var right = Math.round(horizontalCoords.right); //
940
- if (right - left < minWidth) {
941
- if (isRtl) {
942
- left = right - minWidth;
943
- }
944
- else {
945
- right = left + minWidth;
946
- }
947
- }
948
- if (height != null) {
949
- segInputs.push({
950
- index: i,
951
- spanStart: left,
952
- spanEnd: right,
953
- thickness: height,
954
- });
955
- }
956
- else {
957
- crudePlacements.push({
958
- seg: seg,
959
- isVisible: false,
960
- left: left,
961
- right: right,
962
- top: 0,
963
- });
964
- }
965
- }
966
- }
967
- var hierarchy = new common.SegHierarchy();
968
- if (strictOrder != null) {
969
- hierarchy.strictOrder = strictOrder;
970
- }
971
- if (maxStackCnt != null) {
972
- hierarchy.maxStackCnt = maxStackCnt;
973
- }
974
- var hiddenEntries = hierarchy.addSegs(segInputs);
975
- var hiddenPlacements = hiddenEntries.map(function (entry) { return ({
976
- seg: segs[entry.segInput.index],
977
- isVisible: false,
978
- left: entry.spanStart,
979
- right: entry.spanEnd,
980
- top: 0,
981
- }); });
982
- var hiddenGroups = common.groupIntersectingEntries(hiddenEntries);
983
- var moreLinkInputs = [];
984
- var moreLinkCrudePlacements = [];
985
- var extractSeg = function (entry) { return segs[entry.segInput.index]; };
986
- for (var i = 0; i < hiddenGroups.length; i += 1) {
987
- var hiddenGroup = hiddenGroups[i];
988
- var sortedSegs = hiddenGroup.entries.map(extractSeg);
989
- var height = moreLinkHeights[common.buildIsoString(common.computeEarliestSegStart(sortedSegs))]; // not optimal :(
990
- if (height != null) {
991
- // NOTE: the hiddenGroup's spanStart/spanEnd are already computed by rangeToCoords. computed during input.
992
- moreLinkInputs.push({
993
- index: segs.length + i,
994
- spanStart: hiddenGroup.spanStart,
995
- spanEnd: hiddenGroup.spanEnd,
996
- thickness: height,
997
- });
998
- }
999
- else {
1000
- moreLinkCrudePlacements.push({
1001
- seg: sortedSegs,
1002
- isVisible: false,
1003
- left: hiddenGroup.spanStart,
1004
- right: hiddenGroup.spanEnd,
1005
- top: 0,
1006
- });
1007
- }
1008
- }
1009
- // add more-links into the hierarchy, but don't limit
1010
- hierarchy.maxStackCnt = -1;
1011
- hierarchy.addSegs(moreLinkInputs);
1012
- var visibleRects = hierarchy.toRects();
1013
- var visiblePlacements = [];
1014
- var maxHeight = 0;
1015
- for (var _i = 0, visibleRects_1 = visibleRects; _i < visibleRects_1.length; _i++) {
1016
- var rect = visibleRects_1[_i];
1017
- var segIndex = rect.segInput.index;
1018
- visiblePlacements.push({
1019
- seg: segIndex < segs.length
1020
- ? segs[segIndex] // a real seg
1021
- : hiddenGroups[segIndex - segs.length].entries.map(extractSeg),
1022
- isVisible: true,
1023
- left: rect.spanStart,
1024
- right: rect.spanEnd,
1025
- top: rect.levelCoord,
1026
- });
1027
- maxHeight = Math.max(maxHeight, rect.levelCoord + rect.thickness);
1028
- }
1029
- return [
1030
- visiblePlacements.concat(crudePlacements, hiddenPlacements, moreLinkCrudePlacements),
1031
- maxHeight,
1032
- ];
1033
- }
1034
-
1035
1054
  var TimelineLane = /** @class */ (function (_super) {
1036
1055
  tslib.__extends(TimelineLane, _super);
1037
1056
  function TimelineLane() {
1038
1057
  var _this = _super !== null && _super.apply(this, arguments) || this;
1039
1058
  _this.slicer = new TimelineLaneSlicer();
1040
1059
  _this.sortEventSegs = common.memoize(common.sortEventSegs);
1041
- _this.computeFgSegPlacements = common.memoize(computeFgSegPlacements);
1042
1060
  _this.harnessElRefs = new common.RefMap();
1043
1061
  _this.moreElRefs = new common.RefMap();
1044
1062
  _this.innerElRef = common.createRef();
1063
+ // TODO: memoize event positioning
1045
1064
  _this.state = {
1046
1065
  eventInstanceHeights: {},
1047
1066
  moreLinkHeights: {},
@@ -1058,7 +1077,8 @@ var TimelineLane = /** @class */ (function (_super) {
1058
1077
  (slicedProps.eventResize ? slicedProps.eventResize.segs : null) ||
1059
1078
  [];
1060
1079
  var fgSegs = this.sortEventSegs(slicedProps.fgEventSegs, options.eventOrder);
1061
- var _b = this.computeFgSegPlacements(fgSegs, props.timelineCoords, state.eventInstanceHeights, state.moreLinkHeights, options.eventMinWidth, context.isRtl, options.eventOrderStrict, options.eventMaxStack), fgPlacements = _b[0], fgHeight = _b[1];
1080
+ var fgSegHCoords = computeSegHCoords(fgSegs, options.eventMinWidth, props.timelineCoords);
1081
+ var _b = computeFgSegPlacements(fgSegs, fgSegHCoords, state.eventInstanceHeights, state.moreLinkHeights, options.eventOrderStrict, options.eventMaxStack), fgPlacements = _b[0], fgHeight = _b[1];
1062
1082
  var isForcedInvisible = // TODO: more convenient
1063
1083
  (slicedProps.eventDrag ? slicedProps.eventDrag.affectedInstances : null) ||
1064
1084
  (slicedProps.eventResize ? slicedProps.eventResize.affectedInstances : null) ||
@@ -1066,7 +1086,7 @@ var TimelineLane = /** @class */ (function (_super) {
1066
1086
  return (common.createElement(common.Fragment, null,
1067
1087
  common.createElement(TimelineLaneBg, { businessHourSegs: slicedProps.businessHourSegs, bgEventSegs: slicedProps.bgEventSegs, timelineCoords: props.timelineCoords, eventResizeSegs: slicedProps.eventResize ? slicedProps.eventResize.segs : [] /* bad new empty array? */, dateSelectionSegs: slicedProps.dateSelectionSegs, nowDate: props.nowDate, todayRange: props.todayRange }),
1068
1088
  common.createElement("div", { className: "fc-timeline-events fc-scrollgrid-sync-inner", ref: this.innerElRef, style: { height: fgHeight } },
1069
- this.renderFgSegs(fgPlacements, isForcedInvisible),
1089
+ this.renderFgSegs(fgPlacements, isForcedInvisible, false, false, false),
1070
1090
  this.renderFgSegs(buildMirrorPlacements(mirrorSegs, props.timelineCoords, fgPlacements), {}, Boolean(slicedProps.eventDrag), Boolean(slicedProps.eventResize), false))));
1071
1091
  };
1072
1092
  TimelineLane.prototype.componentDidMount = function () {
@@ -1099,22 +1119,18 @@ var TimelineLane = /** @class */ (function (_super) {
1099
1119
  }
1100
1120
  };
1101
1121
  TimelineLane.prototype.renderFgSegs = function (segPlacements, isForcedInvisible, isDragging, isResizing, isDateSelecting) {
1102
- var _a = this, harnessElRefs = _a.harnessElRefs, moreElRefs = _a.moreElRefs, props = _a.props;
1122
+ var _a = this, harnessElRefs = _a.harnessElRefs, moreElRefs = _a.moreElRefs, props = _a.props, context = _a.context;
1103
1123
  var isMirror = isDragging || isResizing || isDateSelecting;
1104
1124
  return (common.createElement(common.Fragment, null, segPlacements.map(function (segPlacement) {
1105
- var seg = segPlacement.seg;
1125
+ var seg = segPlacement.seg, hcoords = segPlacement.hcoords, top = segPlacement.top;
1106
1126
  if (Array.isArray(seg)) { // a more-link
1107
1127
  var isoStr = common.buildIsoString(common.computeEarliestSegStart(seg));
1108
1128
  return (common.createElement(TimelineLaneMoreLink, { key: 'm:' + isoStr /* "m" for "more" */, elRef: moreElRefs.createRef(isoStr), hiddenSegs: seg, placement: segPlacement, dateProfile: props.dateProfile, nowDate: props.nowDate, todayRange: props.todayRange, isTimeScale: props.tDateProfile.isTimeScale, eventSelection: props.eventSelection, resourceId: props.resourceId, isForcedInvisible: isForcedInvisible }));
1109
1129
  }
1110
1130
  var instanceId = seg.eventRange.instance.instanceId;
1111
- var isVisible = segPlacement.isVisible && !isForcedInvisible[instanceId];
1112
- return (common.createElement("div", { key: 'e:' + instanceId /* "e" for "event" */, ref: isMirror ? null : harnessElRefs.createRef(instanceId), className: "fc-timeline-event-harness", style: {
1113
- left: segPlacement.left,
1114
- right: -segPlacement.right,
1115
- top: segPlacement.top,
1116
- visibility: isVisible ? '' : 'hidden',
1117
- } },
1131
+ var isVisible = isMirror || Boolean(!isForcedInvisible[instanceId] && hcoords && top !== null);
1132
+ var hStyle = coordsToCss(hcoords, context.isRtl);
1133
+ return (common.createElement("div", { key: 'e:' + instanceId /* "e" for "event" */, ref: isMirror ? null : harnessElRefs.createRef(instanceId), className: "fc-timeline-event-harness", style: tslib.__assign({ visibility: isVisible ? '' : 'hidden', top: top || 0 }, hStyle) },
1118
1134
  common.createElement(TimelineEvent, tslib.__assign({ isTimeScale: props.tDateProfile.isTimeScale, seg: seg, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === props.eventSelection /* TODO: bad for mirror? */ }, common.getSegMeta(seg, props.todayRange, props.nowDate)))));
1119
1135
  })));
1120
1136
  };
@@ -1129,16 +1145,11 @@ function buildMirrorPlacements(mirrorSegs, timelineCoords, fgPlacements) {
1129
1145
  return [];
1130
1146
  }
1131
1147
  var topsByInstanceId = buildAbsoluteTopHash(fgPlacements); // TODO: cache this at first render?
1132
- return mirrorSegs.map(function (seg) {
1133
- var horizontalCoords = timelineCoords.rangeToCoords(seg);
1134
- return {
1135
- seg: seg,
1136
- isVisible: true,
1137
- left: horizontalCoords.left,
1138
- right: horizontalCoords.right,
1139
- top: topsByInstanceId[seg.eventRange.instance.instanceId],
1140
- };
1141
- });
1148
+ return mirrorSegs.map(function (seg) { return ({
1149
+ seg: seg,
1150
+ hcoords: timelineCoords.rangeToCoords(seg),
1151
+ top: topsByInstanceId[seg.eventRange.instance.instanceId],
1152
+ }); });
1142
1153
  }
1143
1154
  function buildAbsoluteTopHash(placements) {
1144
1155
  var topsByInstanceId = {};
@@ -1191,7 +1202,7 @@ var TimelineGrid = /** @class */ (function (_super) {
1191
1202
  common.createElement(TimelineSlats, { ref: _this.slatsRef, dateProfile: dateProfile, tDateProfile: tDateProfile, nowDate: nowDate, todayRange: todayRange, clientWidth: props.clientWidth, tableColGroupNode: props.tableColGroupNode, tableMinWidth: props.tableMinWidth, onCoords: _this.handleCoords, onScrollLeftRequest: props.onScrollLeftRequest }),
1192
1203
  common.createElement(TimelineLane, { dateProfile: dateProfile, tDateProfile: props.tDateProfile, nowDate: nowDate, todayRange: todayRange, nextDayThreshold: options.nextDayThreshold, businessHours: props.businessHours, eventStore: props.eventStore, eventUiBases: props.eventUiBases, dateSelection: props.dateSelection, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, timelineCoords: state.coords }),
1193
1204
  (options.nowIndicator && state.coords && state.coords.isDateInRange(nowDate)) && (common.createElement("div", { className: "fc-timeline-now-indicator-container" },
1194
- common.createElement(common.NowIndicatorRoot, { isAxis: false, date: nowDate }, function (rootElRef, classNames, innerElRef, innerContent) { return (common.createElement("div", { ref: rootElRef, className: ['fc-timeline-now-indicator-line'].concat(classNames).join(' '), style: { left: state.coords.dateToCoord(nowDate) } }, innerContent)); }))))); })));
1205
+ common.createElement(common.NowIndicatorRoot, { isAxis: false, date: nowDate }, function (rootElRef, classNames, innerElRef, innerContent) { return (common.createElement("div", { ref: rootElRef, className: ['fc-timeline-now-indicator-line'].concat(classNames).join(' '), style: coordToCss(state.coords.dateToCoord(nowDate), context.isRtl) }, innerContent)); }))))); })));
1195
1206
  };
1196
1207
  // Hit System
1197
1208
  // ------------------------------------------------------------------------------------------
@@ -1342,4 +1353,6 @@ exports.TimelineSlats = TimelineSlats;
1342
1353
  exports.TimelineView = TimelineView;
1343
1354
  exports.buildSlatCols = buildSlatCols;
1344
1355
  exports.buildTimelineDateProfile = buildTimelineDateProfile;
1356
+ exports.coordToCss = coordToCss;
1357
+ exports.coordsToCss = coordsToCss;
1345
1358
  exports.default = main;
package/main.css CHANGED
@@ -40,6 +40,13 @@ vertical slots in both the header AND the body
40
40
  .fc .fc-timeline-header-row-chrono .fc-timeline-slot-frame {
41
41
  justify-content: flex-start; /* horizontal align left or right */
42
42
  }
43
+ .fc .fc-timeline-header-row:last-child { /* guaranteed NOT to have sticky elements */
44
+ }
45
+ .fc .fc-timeline-header-row:last-child .fc-timeline-slot-frame {
46
+ /* so text doesn't bleed out and cause extra scroll */
47
+ /* (won't work with sticky elements) */
48
+ overflow: hidden;
49
+ }
43
50
  .fc .fc-timeline-slot-cushion {
44
51
  padding: 4px 5px; /* TODO: unify with fc-col-header? */
45
52
  white-space: nowrap;