@fullcalendar/timeline 7.0.0-beta.4 → 7.0.0-rc.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,5 +1,5 @@
1
1
  /*!
2
- FullCalendar Timeline Plugin v7.0.0-beta.4
2
+ FullCalendar Timeline Plugin v7.0.0-rc.0
3
3
  Docs & License: https://fullcalendar.io/docs/timeline-view-no-resources
4
4
  (c) 2024 Adam Shaw
5
5
  */
@@ -451,6 +451,8 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
451
451
  class TimelineSlatCell extends internal$1.BaseComponent {
452
452
  constructor() {
453
453
  super(...arguments);
454
+ // memo
455
+ this.getPublicDate = internal$1.memoize((dateEnv, date) => dateEnv.toDate(date));
454
456
  // ref
455
457
  this.innerElRef = preact.createRef();
456
458
  }
@@ -459,7 +461,7 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
459
461
  let { dateEnv, options } = context;
460
462
  let { date, tDateProfile, isEm } = props;
461
463
  let dateMeta = internal$1.getDateMeta(props.date, props.todayRange, props.nowDate, props.dateProfile);
462
- let renderProps = Object.assign(Object.assign({ date: dateEnv.toDate(props.date) }, dateMeta), { view: context.viewApi });
464
+ let renderProps = Object.assign(Object.assign({ date: this.getPublicDate(dateEnv, props.date) }, dateMeta), { view: context.viewApi });
463
465
  return (preact.createElement(internal$1.ContentContainer, { tag: "div",
464
466
  // fc-align-start shrinks width of InnerContent
465
467
  // TODO: document this semantic className fc-timeline-slot-em
@@ -473,7 +475,11 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
473
475
  omitTime: !tDateProfile.isTimeScale,
474
476
  }) }, (dateMeta.isToday ? { 'aria-current': 'date' } : {})), style: {
475
477
  width: props.width,
476
- }, renderProps: renderProps, generatorName: "slotLaneContent", customGenerator: options.slotLaneContent, classNameGenerator: options.slotLaneClassNames, didMount: options.slotLaneDidMount, willUnmount: options.slotLaneWillUnmount }, (InnerContent) => (preact.createElement(InnerContent, { tag: "div", className: 'fc-cell-inner', elRef: this.innerElRef }))));
478
+ }, renderProps: renderProps, generatorName: "slotLaneContent", customGenerator: options.slotLaneContent, classNameGenerator: options.slotLaneClassNames, didMount: options.slotLaneDidMount, willUnmount: options.slotLaneWillUnmount }, (InnerContent) => (preact.createElement(InnerContent, { tag: "div", className: 'fc-cell-inner', style: {
479
+ // HACK for Safari 16.4,
480
+ // which can't use ResizeObserver on elements with natural width 0
481
+ minWidth: 1,
482
+ }, elRef: this.innerElRef }))));
477
483
  }
478
484
  componentDidMount() {
479
485
  const innerEl = this.innerElRef.current;
@@ -508,7 +514,7 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
508
514
  let { tDateProfile, slotWidth } = props;
509
515
  let { slotDates, isWeekStarts } = tDateProfile;
510
516
  let isDay = !tDateProfile.isTimeScale && !tDateProfile.largeUnit;
511
- return (preact.createElement("div", { "aria-hidden": true, className: "fc-timeline-slots fc-fill fc-flex-row", style: { height: props.height } }, slotDates.map((slotDate, i) => {
517
+ return (preact.createElement("div", { "aria-hidden": true, className: "fc-timeline-slots fc-flex-row fc-fill", style: { height: props.height } }, slotDates.map((slotDate, i) => {
512
518
  let key = slotDate.toISOString();
513
519
  return (preact.createElement(TimelineSlatCell, { key: key, date: slotDate, dateProfile: props.dateProfile, tDateProfile: tDateProfile, nowDate: props.nowDate, todayRange: props.todayRange, isEm: isWeekStarts[i], isDay: isDay, borderStart: Boolean(i),
514
520
  // ref
@@ -519,50 +525,132 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
519
525
  }
520
526
  }
521
527
 
522
- /*
523
- TODO: rename this file!
524
- */
525
- // returned value is between 0 and the number of snaps
526
- function computeDateSnapCoverage$1(date, tDateProfile, dateEnv) {
527
- let snapDiff = dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.snapDuration);
528
- if (snapDiff < 0) {
529
- return 0;
528
+ class TimelineHeaderCell extends internal$1.BaseComponent {
529
+ constructor() {
530
+ super(...arguments);
531
+ // memo
532
+ this.refineRenderProps = internal$1.memoizeObjArg(refineRenderProps);
533
+ // ref
534
+ this.innerElRef = preact.createRef();
530
535
  }
531
- if (snapDiff >= tDateProfile.snapDiffToIndex.length) {
532
- return tDateProfile.snapCnt;
536
+ render() {
537
+ let { props, context } = this;
538
+ let { dateEnv, options } = context;
539
+ let { cell, dateProfile, tDateProfile } = props;
540
+ // the cell.rowUnit is f'd
541
+ // giving 'month' for a 3-day view
542
+ // workaround: to infer day, do NOT time
543
+ let dateMeta = internal$1.getDateMeta(cell.date, props.todayRange, props.nowDate, dateProfile);
544
+ let renderProps = this.refineRenderProps({
545
+ level: props.rowLevel,
546
+ dateMarker: cell.date,
547
+ text: cell.text,
548
+ dateEnv: context.dateEnv,
549
+ viewApi: context.viewApi,
550
+ });
551
+ let isNavLink = !dateMeta.isDisabled && (cell.rowUnit && cell.rowUnit !== 'time');
552
+ return (preact.createElement(internal$1.ContentContainer, { tag: "div", className: internal$1.joinClassNames('fc-timeline-slot-label fc-timeline-slot', cell.isWeekStart && 'fc-timeline-slot-em', // TODO: document this semantic className
553
+ 'fc-header-cell fc-cell fc-flex-col fc-justify-center', props.borderStart && 'fc-border-s', props.isCentered ? 'fc-align-center' : 'fc-align-start',
554
+ // TODO: so slot classnames for week/month/bigger. see note above about rowUnit
555
+ cell.rowUnit === 'time' ?
556
+ internal$1.getSlotClassName(dateMeta) :
557
+ internal$1.getDayClassName(dateMeta)), attrs: Object.assign({ 'data-date': dateEnv.formatIso(cell.date, {
558
+ omitTime: !tDateProfile.isTimeScale,
559
+ omitTimeZoneOffset: true,
560
+ }) }, (dateMeta.isToday ? { 'aria-current': 'date' } : {})), style: {
561
+ width: props.slotWidth != null
562
+ ? props.slotWidth * cell.colspan
563
+ : undefined,
564
+ }, renderProps: renderProps, generatorName: "slotLabelContent", customGenerator: options.slotLabelContent, defaultGenerator: renderInnerContent, classNameGenerator: options.slotLabelClassNames, didMount: options.slotLabelDidMount, willUnmount: options.slotLabelWillUnmount }, (InnerContent) => (preact.createElement(InnerContent, { tag: 'div', attrs: isNavLink
565
+ // not tabbable because parent is aria-hidden
566
+ ? internal$1.buildNavLinkAttrs(context, cell.date, cell.rowUnit, undefined, /* isTabbable = */ false)
567
+ : {} // don't bother with aria-hidden because parent already hidden
568
+ , className: internal$1.joinClassNames('fc-cell-inner fc-padding-md', props.isSticky && 'fc-sticky-s'), elRef: this.innerElRef }))));
533
569
  }
534
- let snapDiffInt = Math.floor(snapDiff);
535
- let snapCoverage = tDateProfile.snapDiffToIndex[snapDiffInt];
536
- if (internal$1.isInt(snapCoverage)) { // not an in-between value
537
- snapCoverage += snapDiff - snapDiffInt; // add the remainder
570
+ componentDidMount() {
571
+ const { props } = this;
572
+ const innerEl = this.innerElRef.current; // TODO: make dynamic with useEffect
573
+ this.detachSize = internal$1.watchSize(innerEl, (width, height) => {
574
+ internal$1.setRef(props.innerWidthRef, width);
575
+ internal$1.setRef(props.innerHeightRef, height);
576
+ // HACK for sticky-centering
577
+ innerEl.style.left = innerEl.style.right =
578
+ (props.isCentered && props.isSticky)
579
+ ? `calc(50% - ${width / 2}px)`
580
+ : '';
581
+ });
538
582
  }
539
- else {
540
- // a fractional value, meaning the date is not visible
541
- // always round up in this case. works for start AND end dates in a range.
542
- snapCoverage = Math.ceil(snapCoverage);
583
+ componentWillUnmount() {
584
+ const { props } = this;
585
+ this.detachSize();
586
+ internal$1.setRef(props.innerWidthRef, null);
587
+ internal$1.setRef(props.innerHeightRef, null);
543
588
  }
544
- return snapCoverage;
545
589
  }
546
- /*
547
- TODO: DRY up with elsewhere?
548
- */
549
- function horizontalsToCss(hcoord, isRtl) {
550
- if (!hcoord) {
551
- return {};
552
- }
553
- if (isRtl) {
554
- return { right: hcoord.start, width: hcoord.size };
555
- }
556
- else {
557
- return { left: hcoord.start, width: hcoord.size };
558
- }
590
+ // Utils
591
+ // -------------------------------------------------------------------------------------------------
592
+ function renderInnerContent(renderProps) {
593
+ return renderProps.text;
559
594
  }
560
- function horizontalCoordToCss(start, isRtl) {
561
- if (isRtl) {
562
- return { right: start };
595
+ function refineRenderProps(input) {
596
+ return {
597
+ level: input.level,
598
+ date: input.dateEnv.toDate(input.dateMarker),
599
+ view: input.viewApi,
600
+ text: input.text,
601
+ };
602
+ }
603
+
604
+ class TimelineHeaderRow extends internal$1.BaseComponent {
605
+ constructor() {
606
+ super(...arguments);
607
+ // refs
608
+ this.innerWidthRefMap = new internal$1.RefMap(() => {
609
+ internal$1.afterSize(this.handleInnerWidths);
610
+ });
611
+ this.innerHeightRefMap = new internal$1.RefMap(() => {
612
+ internal$1.afterSize(this.handleInnerHeights);
613
+ });
614
+ this.handleInnerWidths = () => {
615
+ const innerWidthMap = this.innerWidthRefMap.current;
616
+ let max = 0;
617
+ for (const innerWidth of innerWidthMap.values()) {
618
+ max = Math.max(max, innerWidth);
619
+ }
620
+ // TODO: ensure not equal?
621
+ internal$1.setRef(this.props.innerWidthRef, max);
622
+ };
623
+ this.handleInnerHeights = () => {
624
+ const innerHeightMap = this.innerHeightRefMap.current;
625
+ let max = 0;
626
+ for (const innerHeight of innerHeightMap.values()) {
627
+ max = Math.max(max, innerHeight);
628
+ }
629
+ // TODO: ensure not equal?
630
+ internal$1.setRef(this.props.innerHeighRef, max);
631
+ };
563
632
  }
564
- else {
565
- return { left: start };
633
+ render() {
634
+ const { props, innerWidthRefMap, innerHeightRefMap } = this;
635
+ const isCentered = !(props.tDateProfile.isTimeScale && props.isLastRow);
636
+ const isSticky = !props.isLastRow;
637
+ return (preact.createElement("div", { className: internal$1.joinClassNames('fc-flex-row fc-grow', // TODO: move fc-grow to parent?
638
+ !props.isLastRow && 'fc-border-b') }, props.cells.map((cell, cellI) => {
639
+ // TODO: make this part of the cell obj?
640
+ // TODO: rowUnit seems wrong sometimes. says 'month' when it should be day
641
+ // TODO: rowUnit is relevant to whole row. put it on a row object, not the cells
642
+ // TODO: use rowUnit to key the Row itself?
643
+ const key = cell.rowUnit + ':' + cell.date.toISOString();
644
+ return (preact.createElement(TimelineHeaderCell, { key: key, cell: cell, rowLevel: props.rowLevel, dateProfile: props.dateProfile, tDateProfile: props.tDateProfile, todayRange: props.todayRange, nowDate: props.nowDate, isCentered: isCentered, isSticky: isSticky, borderStart: Boolean(cellI),
645
+ // refs
646
+ innerWidthRef: innerWidthRefMap.createRef(key), innerHeightRef: innerHeightRefMap.createRef(key),
647
+ // dimensions
648
+ slotWidth: props.slotWidth }));
649
+ })));
650
+ }
651
+ componentWillUnmount() {
652
+ internal$1.setRef(this.props.innerWidthRef, null);
653
+ internal$1.setRef(this.props.innerHeighRef, null);
566
654
  }
567
655
  }
568
656
 
@@ -617,13 +705,38 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
617
705
  }
618
706
  function dateToCoord(// pixels
619
707
  date, dateEnv, tDateProfile, slotWidth) {
620
- let snapCoverage = computeDateSnapCoverage(date, tDateProfile, dateEnv);
708
+ let snapCoverage = computeDateSnapCoverage$1(date, tDateProfile, dateEnv);
621
709
  let slotCoverage = snapCoverage / tDateProfile.snapsPerSlot;
622
710
  return slotCoverage * slotWidth;
623
711
  }
624
712
  /*
625
713
  returned value is between 0 and the number of snaps
626
714
  */
715
+ function computeDateSnapCoverage$1(date, tDateProfile, dateEnv) {
716
+ let snapDiff = dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.snapDuration);
717
+ if (snapDiff < 0) {
718
+ return 0;
719
+ }
720
+ if (snapDiff >= tDateProfile.snapDiffToIndex.length) {
721
+ return tDateProfile.snapCnt;
722
+ }
723
+ let snapDiffInt = Math.floor(snapDiff);
724
+ let snapCoverage = tDateProfile.snapDiffToIndex[snapDiffInt];
725
+ if (internal$1.isInt(snapCoverage)) { // not an in-between value
726
+ snapCoverage += snapDiff - snapDiffInt; // add the remainder
727
+ }
728
+ else {
729
+ // a fractional value, meaning the date is not visible
730
+ // always round up in this case. works for start AND end dates in a range.
731
+ snapCoverage = Math.ceil(snapCoverage);
732
+ }
733
+ return snapCoverage;
734
+ }
735
+
736
+ /*
737
+ TODO: rename this file!
738
+ */
739
+ // returned value is between 0 and the number of snaps
627
740
  function computeDateSnapCoverage(date, tDateProfile, dateEnv) {
628
741
  let snapDiff = dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.snapDuration);
629
742
  if (snapDiff < 0) {
@@ -642,7 +755,107 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
642
755
  // always round up in this case. works for start AND end dates in a range.
643
756
  snapCoverage = Math.ceil(snapCoverage);
644
757
  }
645
- return snapCoverage;
758
+ return snapCoverage;
759
+ }
760
+ /*
761
+ TODO: DRY up with elsewhere?
762
+ */
763
+ function horizontalsToCss(hcoord, isRtl) {
764
+ if (!hcoord) {
765
+ return {};
766
+ }
767
+ if (isRtl) {
768
+ return { right: hcoord.start, width: hcoord.size };
769
+ }
770
+ else {
771
+ return { left: hcoord.start, width: hcoord.size };
772
+ }
773
+ }
774
+ function horizontalCoordToCss(start, isRtl) {
775
+ if (isRtl) {
776
+ return { right: start };
777
+ }
778
+ else {
779
+ return { left: start };
780
+ }
781
+ }
782
+
783
+ class TimelineNowIndicatorLine extends internal$1.BaseComponent {
784
+ render() {
785
+ const { props, context } = this;
786
+ return (preact.createElement("div", { className: "fc-timeline-now-indicator-container" },
787
+ preact.createElement(internal$1.NowIndicatorContainer // TODO: make separate component?
788
+ , { className: 'fc-timeline-now-indicator-line', style: props.slotWidth != null
789
+ ? horizontalCoordToCss(dateToCoord(props.nowDate, context.dateEnv, props.tDateProfile, props.slotWidth), context.isRtl)
790
+ : {}, isAxis: false, date: props.nowDate })));
791
+ }
792
+ }
793
+
794
+ class TimelineNowIndicatorArrow extends internal$1.BaseComponent {
795
+ render() {
796
+ const { props, context } = this;
797
+ return (preact.createElement("div", { className: "fc-timeline-now-indicator-container" },
798
+ preact.createElement(internal$1.NowIndicatorContainer, { className: 'fc-timeline-now-indicator-arrow', style: props.slotWidth != null
799
+ ? horizontalCoordToCss(dateToCoord(props.nowDate, context.dateEnv, props.tDateProfile, props.slotWidth), context.isRtl)
800
+ : {}, isAxis: true, date: props.nowDate })));
801
+ }
802
+ }
803
+
804
+ function getTimelineSlotEl(parentEl, index) {
805
+ return parentEl.querySelectorAll('.fc-timeline-slot')[index];
806
+ }
807
+
808
+ class TimelineLaneSlicer extends internal$1.Slicer {
809
+ sliceRange(origRange, dateProfile, dateProfileGenerator, tDateProfile, dateEnv) {
810
+ let normalRange = normalizeRange(origRange, tDateProfile, dateEnv);
811
+ let segs = [];
812
+ // protect against when the span is entirely in an invalid date region
813
+ if (computeDateSnapCoverage(normalRange.start, tDateProfile, dateEnv)
814
+ < computeDateSnapCoverage(normalRange.end, tDateProfile, dateEnv)) {
815
+ // intersect the footprint's range with the grid's range
816
+ let slicedRange = internal$1.intersectRanges(normalRange, tDateProfile.normalizedRange);
817
+ if (slicedRange) {
818
+ segs.push({
819
+ startDate: slicedRange.start,
820
+ endDate: slicedRange.end,
821
+ isStart: slicedRange.start.valueOf() === normalRange.start.valueOf()
822
+ && isValidDate(slicedRange.start, tDateProfile, dateProfile, dateProfileGenerator),
823
+ isEnd: slicedRange.end.valueOf() === normalRange.end.valueOf()
824
+ && isValidDate(internal$1.addMs(slicedRange.end, -1), tDateProfile, dateProfile, dateProfileGenerator),
825
+ });
826
+ }
827
+ }
828
+ return segs;
829
+ }
830
+ }
831
+
832
+ const DEFAULT_TIME_FORMAT = internal$1.createFormatter({
833
+ hour: 'numeric',
834
+ minute: '2-digit',
835
+ omitZeroMinute: true,
836
+ meridiem: 'narrow',
837
+ });
838
+ class TimelineEvent extends internal$1.BaseComponent {
839
+ render() {
840
+ let { props, context } = this;
841
+ let { options } = context;
842
+ return (preact.createElement(internal$1.StandardEvent, Object.assign({}, props, { className: internal$1.joinClassNames('fc-timeline-event', options.eventOverlap === false // TODO: fix bad default
843
+ && 'fc-timeline-event-spacious', 'fc-h-event'), defaultTimeFormat: DEFAULT_TIME_FORMAT, defaultDisplayEventTime: !props.isTimeScale })));
844
+ }
845
+ }
846
+
847
+ class TimelineLaneMoreLink extends internal$1.BaseComponent {
848
+ render() {
849
+ let { props } = this;
850
+ let { hiddenSegs, resourceId, forcedInvisibleMap } = props;
851
+ let dateSpanProps = resourceId ? { resourceId } : {};
852
+ return (preact.createElement(internal$1.MoreLinkContainer, { className: 'fc-timeline-more-link', allDayDate: null, segs: hiddenSegs, hiddenSegs: hiddenSegs, dateProfile: props.dateProfile, todayRange: props.todayRange, dateSpanProps: dateSpanProps, popoverContent: () => (preact.createElement(preact.Fragment, null, hiddenSegs.map((seg) => {
853
+ let { eventRange } = seg;
854
+ let instanceId = eventRange.instance.instanceId;
855
+ return (preact.createElement("div", { key: instanceId, style: { visibility: forcedInvisibleMap[instanceId] ? 'hidden' : '' } },
856
+ preact.createElement(TimelineEvent, Object.assign({ isTimeScale: props.isTimeScale, eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === props.eventSelection }, internal$1.getEventRangeMeta(eventRange, props.todayRange, props.nowDate)))));
857
+ }))) }, (InnerContent) => (preact.createElement(InnerContent, { tag: "div", className: 'fc-timeline-more-link-inner fc-sticky-s' }))));
858
+ }
646
859
  }
647
860
 
648
861
  function computeManySegHorizontals(segs, segMinWidth, dateEnv, tDateProfile, slotWidth) {
@@ -709,83 +922,6 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
709
922
  ];
710
923
  }
711
924
 
712
- class TimelineLaneBg extends internal$1.BaseComponent {
713
- render() {
714
- let { props } = this;
715
- let highlightSeg = [].concat(props.eventResizeSegs, props.dateSelectionSegs);
716
- return (preact.createElement(preact.Fragment, null,
717
- this.renderSegs(props.businessHourSegs || [], 'non-business'),
718
- this.renderSegs(props.bgEventSegs || [], 'bg-event'),
719
- this.renderSegs(highlightSeg, 'highlight')));
720
- }
721
- renderSegs(segs, fillType) {
722
- let { tDateProfile, todayRange, nowDate, slotWidth } = this.props;
723
- let { dateEnv, isRtl } = this.context;
724
- return (preact.createElement(preact.Fragment, null, segs.map((seg) => {
725
- let hStyle; // TODO
726
- if (slotWidth != null) {
727
- let segHorizontal = computeSegHorizontals(seg, undefined, dateEnv, tDateProfile, slotWidth);
728
- hStyle = horizontalsToCss(segHorizontal, isRtl);
729
- }
730
- return (preact.createElement("div", { key: internal$1.buildEventRangeKey(seg.eventRange), className: "fc-fill-y", style: hStyle }, fillType === 'bg-event' ?
731
- preact.createElement(internal$1.BgEvent, Object.assign({ eventRange: seg.eventRange, isStart: seg.isStart, isEnd: seg.isEnd }, internal$1.getEventRangeMeta(seg.eventRange, todayRange, nowDate))) : (internal$1.renderFill(fillType))));
732
- })));
733
- }
734
- }
735
-
736
- class TimelineLaneSlicer extends internal$1.Slicer {
737
- sliceRange(origRange, dateProfile, dateProfileGenerator, tDateProfile, dateEnv) {
738
- let normalRange = normalizeRange(origRange, tDateProfile, dateEnv);
739
- let segs = [];
740
- // protect against when the span is entirely in an invalid date region
741
- if (computeDateSnapCoverage$1(normalRange.start, tDateProfile, dateEnv)
742
- < computeDateSnapCoverage$1(normalRange.end, tDateProfile, dateEnv)) {
743
- // intersect the footprint's range with the grid's range
744
- let slicedRange = internal$1.intersectRanges(normalRange, tDateProfile.normalizedRange);
745
- if (slicedRange) {
746
- segs.push({
747
- startDate: slicedRange.start,
748
- endDate: slicedRange.end,
749
- isStart: slicedRange.start.valueOf() === normalRange.start.valueOf()
750
- && isValidDate(slicedRange.start, tDateProfile, dateProfile, dateProfileGenerator),
751
- isEnd: slicedRange.end.valueOf() === normalRange.end.valueOf()
752
- && isValidDate(internal$1.addMs(slicedRange.end, -1), tDateProfile, dateProfile, dateProfileGenerator),
753
- });
754
- }
755
- }
756
- return segs;
757
- }
758
- }
759
-
760
- const DEFAULT_TIME_FORMAT = internal$1.createFormatter({
761
- hour: 'numeric',
762
- minute: '2-digit',
763
- omitZeroMinute: true,
764
- meridiem: 'narrow',
765
- });
766
- class TimelineEvent extends internal$1.BaseComponent {
767
- render() {
768
- let { props, context } = this;
769
- let { options } = context;
770
- return (preact.createElement(internal$1.StandardEvent, Object.assign({}, props, { className: internal$1.joinClassNames('fc-timeline-event', options.eventOverlap === false // TODO: fix bad default
771
- && 'fc-timeline-event-spacious', 'fc-h-event'), defaultTimeFormat: DEFAULT_TIME_FORMAT, defaultDisplayEventTime: !props.isTimeScale })));
772
- }
773
- }
774
-
775
- class TimelineLaneMoreLink extends internal$1.BaseComponent {
776
- render() {
777
- let { props } = this;
778
- let { hiddenSegs, resourceId, forcedInvisibleMap } = props;
779
- let dateSpanProps = resourceId ? { resourceId } : {};
780
- return (preact.createElement(internal$1.MoreLinkContainer, { className: 'fc-timeline-more-link', allDayDate: null, segs: hiddenSegs, hiddenSegs: hiddenSegs, dateProfile: props.dateProfile, todayRange: props.todayRange, dateSpanProps: dateSpanProps, popoverContent: () => (preact.createElement(preact.Fragment, null, hiddenSegs.map((seg) => {
781
- let { eventRange } = seg;
782
- let instanceId = eventRange.instance.instanceId;
783
- return (preact.createElement("div", { key: instanceId, style: { visibility: forcedInvisibleMap[instanceId] ? 'hidden' : '' } },
784
- preact.createElement(TimelineEvent, Object.assign({ isTimeScale: props.isTimeScale, eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === props.eventSelection }, internal$1.getEventRangeMeta(eventRange, props.todayRange, props.nowDate)))));
785
- }))) }, (InnerContent) => (preact.createElement(InnerContent, { tag: "div", className: 'fc-timeline-more-link-inner fc-sticky-s' }))));
786
- }
787
- }
788
-
789
925
  /*
790
926
  TODO: make DRY with other Event Harnesses
791
927
  */
@@ -811,10 +947,7 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
811
947
  }
812
948
  }
813
949
 
814
- /*
815
- TODO: split TimelineLaneBg and TimelineLaneFg?
816
- */
817
- class TimelineLane extends internal$1.BaseComponent {
950
+ class TimelineFg extends internal$1.BaseComponent {
818
951
  constructor() {
819
952
  super(...arguments);
820
953
  // memo
@@ -826,8 +959,6 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
826
959
  this.moreLinkHeightRefMap = new internal$1.RefMap(() => {
827
960
  internal$1.afterSize(this.handleMoreLinkHeights);
828
961
  });
829
- // internal
830
- this.slicer = new TimelineLaneSlicer();
831
962
  this.handleMoreLinkHeights = () => {
832
963
  this.setState({ moreLinkHeightRev: this.moreLinkHeightRefMap.rev }); // will trigger rerender
833
964
  };
@@ -841,39 +972,30 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
841
972
  render() {
842
973
  let { props, context, segHeightRefMap, moreLinkHeightRefMap } = this;
843
974
  let { options } = context;
844
- let { dateProfile, tDateProfile } = props;
845
- let slicedProps = this.slicer.sliceProps(props, dateProfile, tDateProfile.isTimeScale ? null : props.nextDayThreshold, context, // wish we didn't have to pass in the rest of the args...
846
- dateProfile, context.dateProfileGenerator, tDateProfile, context.dateEnv);
847
- let mirrorSegs = (slicedProps.eventDrag ? slicedProps.eventDrag.segs : null) ||
848
- (slicedProps.eventResize ? slicedProps.eventResize.segs : null) ||
975
+ let { tDateProfile } = props;
976
+ let mirrorSegs = (props.eventDrag ? props.eventDrag.segs : null) ||
977
+ (props.eventResize ? props.eventResize.segs : null) ||
849
978
  [];
850
- let fgSegs = this.sortEventSegs(slicedProps.fgEventSegs, options.eventOrder);
979
+ let fgSegs = this.sortEventSegs(props.fgEventSegs, options.eventOrder);
851
980
  let fgSegHorizontals = props.slotWidth != null
852
981
  ? computeManySegHorizontals(fgSegs, options.eventMinWidth, context.dateEnv, tDateProfile, props.slotWidth)
853
982
  : {};
854
983
  let [fgSegTops, hiddenGroups, hiddenGroupTops, totalHeight] = computeFgSegPlacements(fgSegs, fgSegHorizontals, segHeightRefMap.current, moreLinkHeightRefMap.current, options.eventOrderStrict, options.eventMaxStack);
984
+ this.totalHeight = totalHeight;
855
985
  let forcedInvisibleMap = // TODO: more convenient/DRY
856
- (slicedProps.eventDrag ? slicedProps.eventDrag.affectedInstances : null) ||
857
- (slicedProps.eventResize ? slicedProps.eventResize.affectedInstances : null) ||
986
+ (props.eventDrag ? props.eventDrag.affectedInstances : null) ||
987
+ (props.eventResize ? props.eventResize.affectedInstances : null) ||
858
988
  {};
859
- return (preact.createElement(preact.Fragment, null,
860
- preact.createElement(TimelineLaneBg, { tDateProfile: tDateProfile, nowDate: props.nowDate, todayRange: props.todayRange,
861
- // content
862
- bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventResizeSegs: slicedProps.eventResize ? slicedProps.eventResize.segs : [] /* bad new empty array? */,
863
- // dimensions
864
- slotWidth: props.slotWidth }),
865
- preact.createElement("div", { className: internal$1.joinClassNames('fc-timeline-events', options.eventOverlap === false // TODO: fix bad default
866
- ? 'fc-timeline-events-overlap-disabled'
867
- : 'fc-timeline-events-overlap-enabled', 'fc-content-box'), style: { height: totalHeight } },
868
- this.renderFgSegs(fgSegs, fgSegHorizontals, fgSegTops, forcedInvisibleMap, hiddenGroups, hiddenGroupTops, false, // isDragging
869
- false, // isResizing
870
- false),
871
- this.renderFgSegs(mirrorSegs, props.slotWidth // TODO: memoize
872
- ? computeManySegHorizontals(mirrorSegs, options.eventMinWidth, context.dateEnv, tDateProfile, props.slotWidth)
873
- : {}, fgSegTops, {}, // forcedInvisibleMap
874
- [], // hiddenGroups
875
- new Map(), // hiddenGroupTops
876
- Boolean(slicedProps.eventDrag), Boolean(slicedProps.eventResize), false))));
989
+ return (preact.createElement("div", { className: 'fc-timeline-events fc-rel', style: { height: totalHeight } },
990
+ this.renderFgSegs(fgSegs, fgSegHorizontals, fgSegTops, forcedInvisibleMap, hiddenGroups, hiddenGroupTops, false, // isDragging
991
+ false, // isResizing
992
+ false),
993
+ this.renderFgSegs(mirrorSegs, props.slotWidth // TODO: memoize
994
+ ? computeManySegHorizontals(mirrorSegs, options.eventMinWidth, context.dateEnv, tDateProfile, props.slotWidth)
995
+ : {}, fgSegTops, {}, // forcedInvisibleMap
996
+ [], // hiddenGroups
997
+ new Map(), // hiddenGroupTops
998
+ Boolean(props.eventDrag), Boolean(props.eventResize), false)));
877
999
  }
878
1000
  renderFgSegs(segs, segHorizontals, segTops, forcedInvisibleMap, hiddenGroups, hiddenGroupTops, isDragging, isResizing, isDateSelecting) {
879
1001
  let { props, context, segHeightRefMap, moreLinkHeightRefMap } = this;
@@ -895,155 +1017,43 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
895
1017
  }, context.isRtl)), heightRef: moreLinkHeightRefMap.createRef(hiddenGroup.key) },
896
1018
  preact.createElement(TimelineLaneMoreLink, { hiddenSegs: hiddenGroup.segs, dateProfile: props.dateProfile, nowDate: props.nowDate, todayRange: props.todayRange, isTimeScale: props.tDateProfile.isTimeScale, eventSelection: props.eventSelection, resourceId: props.resourceId, forcedInvisibleMap: forcedInvisibleMap }))))));
897
1019
  }
898
- }
899
-
900
- class TimelineHeaderCell extends internal$1.BaseComponent {
901
- constructor() {
902
- super(...arguments);
903
- // memo
904
- this.refineRenderProps = internal$1.memoizeObjArg(refineRenderProps);
905
- // ref
906
- this.innerElRef = preact.createRef();
907
- }
908
- render() {
909
- let { props, context } = this;
910
- let { dateEnv, options } = context;
911
- let { cell, dateProfile, tDateProfile } = props;
912
- // the cell.rowUnit is f'd
913
- // giving 'month' for a 3-day view
914
- // workaround: to infer day, do NOT time
915
- let dateMeta = internal$1.getDateMeta(cell.date, props.todayRange, props.nowDate, dateProfile);
916
- let renderProps = this.refineRenderProps({
917
- level: props.rowLevel,
918
- dateMarker: cell.date,
919
- text: cell.text,
920
- dateEnv: context.dateEnv,
921
- viewApi: context.viewApi,
922
- });
923
- let isNavLink = !dateMeta.isDisabled && (cell.rowUnit && cell.rowUnit !== 'time');
924
- return (preact.createElement(internal$1.ContentContainer, { tag: "div", className: internal$1.joinClassNames('fc-timeline-slot-label fc-timeline-slot', cell.isWeekStart && 'fc-timeline-slot-em', // TODO: document this semantic className
925
- 'fc-header-cell fc-cell fc-flex-col fc-justify-center', props.borderStart && 'fc-border-s', props.isCentered ? 'fc-align-center' : 'fc-align-start',
926
- // TODO: so slot classnames for week/month/bigger. see note above about rowUnit
927
- cell.rowUnit === 'time' ?
928
- internal$1.getSlotClassName(dateMeta) :
929
- internal$1.getDayClassName(dateMeta)), attrs: Object.assign({ 'data-date': dateEnv.formatIso(cell.date, {
930
- omitTime: !tDateProfile.isTimeScale,
931
- omitTimeZoneOffset: true,
932
- }) }, (dateMeta.isToday ? { 'aria-current': 'date' } : {})), style: {
933
- width: props.slotWidth != null
934
- ? props.slotWidth * cell.colspan
935
- : undefined,
936
- }, renderProps: renderProps, generatorName: "slotLabelContent", customGenerator: options.slotLabelContent, defaultGenerator: renderInnerContent, classNameGenerator: options.slotLabelClassNames, didMount: options.slotLabelDidMount, willUnmount: options.slotLabelWillUnmount }, (InnerContent) => (preact.createElement(InnerContent, { tag: 'div', attrs: isNavLink
937
- // not tabbable because parent is aria-hidden
938
- ? internal$1.buildNavLinkAttrs(context, cell.date, cell.rowUnit, undefined, /* isTabbable = */ false)
939
- : {} // don't bother with aria-hidden because parent already hidden
940
- , className: internal$1.joinClassNames('fc-cell-inner fc-padding-md', props.isSticky && 'fc-sticky-s'), elRef: this.innerElRef }))));
941
- }
942
- componentDidMount() {
943
- const { props } = this;
944
- const innerEl = this.innerElRef.current; // TODO: make dynamic with useEffect
945
- this.detachSize = internal$1.watchSize(innerEl, (width, height) => {
946
- internal$1.setRef(props.innerWidthRef, width);
947
- internal$1.setRef(props.innerHeightRef, height);
948
- // HACK for sticky-centering
949
- innerEl.style.left = innerEl.style.right =
950
- (props.isCentered && props.isSticky)
951
- ? `calc(50% - ${width / 2}px)`
952
- : '';
953
- });
954
- }
955
- componentWillUnmount() {
956
- const { props } = this;
957
- this.detachSize();
958
- internal$1.setRef(props.innerWidthRef, null);
959
- internal$1.setRef(props.innerHeightRef, null);
960
- }
961
- }
962
- // Utils
963
- // -------------------------------------------------------------------------------------------------
964
- function renderInnerContent(renderProps) {
965
- return renderProps.text;
966
- }
967
- function refineRenderProps(input) {
968
- return {
969
- level: input.level,
970
- date: input.dateEnv.toDate(input.dateMarker),
971
- view: input.viewApi,
972
- text: input.text,
973
- };
974
- }
975
-
976
- class TimelineHeaderRow extends internal$1.BaseComponent {
977
- constructor() {
978
- super(...arguments);
979
- // refs
980
- this.innerWidthRefMap = new internal$1.RefMap(() => {
981
- internal$1.afterSize(this.handleInnerWidths);
982
- });
983
- this.innerHeightRefMap = new internal$1.RefMap(() => {
984
- internal$1.afterSize(this.handleInnerHeights);
985
- });
986
- this.handleInnerWidths = () => {
987
- const innerWidthMap = this.innerWidthRefMap.current;
988
- let max = 0;
989
- for (const innerWidth of innerWidthMap.values()) {
990
- max = Math.max(max, innerWidth);
991
- }
992
- // TODO: ensure not equal?
993
- internal$1.setRef(this.props.innerWidthRef, max);
994
- };
995
- this.handleInnerHeights = () => {
996
- const innerHeightMap = this.innerHeightRefMap.current;
997
- let max = 0;
998
- for (const innerHeight of innerHeightMap.values()) {
999
- max = Math.max(max, innerHeight);
1000
- }
1001
- // TODO: ensure not equal?
1002
- internal$1.setRef(this.props.innerHeighRef, max);
1003
- };
1020
+ /*
1021
+ componentDidMount(): void {
1022
+ // might want to do firedTotalHeight, but won't be ready on first render
1004
1023
  }
1005
- render() {
1006
- const { props, innerWidthRefMap, innerHeightRefMap } = this;
1007
- const isCentered = !(props.tDateProfile.isTimeScale && props.isLastRow);
1008
- const isSticky = !props.isLastRow;
1009
- return (preact.createElement("div", { className: internal$1.joinClassNames('fc-flex-row fc-grow', // TODO: move fc-grow to parent?
1010
- !props.isLastRow && 'fc-border-b') }, props.cells.map((cell, cellI) => {
1011
- // TODO: make this part of the cell obj?
1012
- // TODO: rowUnit seems wrong sometimes. says 'month' when it should be day
1013
- // TODO: rowUnit is relevant to whole row. put it on a row object, not the cells
1014
- // TODO: use rowUnit to key the Row itself?
1015
- const key = cell.rowUnit + ':' + cell.date.toISOString();
1016
- return (preact.createElement(TimelineHeaderCell, { key: key, cell: cell, rowLevel: props.rowLevel, dateProfile: props.dateProfile, tDateProfile: props.tDateProfile, todayRange: props.todayRange, nowDate: props.nowDate, isCentered: isCentered, isSticky: isSticky, borderStart: Boolean(cellI),
1017
- // refs
1018
- innerWidthRef: innerWidthRefMap.createRef(key), innerHeightRef: innerHeightRefMap.createRef(key),
1019
- // dimensions
1020
- slotWidth: props.slotWidth }));
1021
- })));
1024
+ */
1025
+ componentDidUpdate() {
1026
+ if (this.totalHeight !== this.firedTotalHeight) {
1027
+ this.firedTotalHeight = this.totalHeight;
1028
+ internal$1.setRef(this.props.heightRef, this.totalHeight);
1029
+ }
1022
1030
  }
1023
1031
  componentWillUnmount() {
1024
- internal$1.setRef(this.props.innerWidthRef, null);
1025
- internal$1.setRef(this.props.innerHeighRef, null);
1032
+ internal$1.setRef(this.props.heightRef, null);
1026
1033
  }
1027
1034
  }
1028
1035
 
1029
- class TimelineNowIndicatorLine extends internal$1.BaseComponent {
1036
+ class TimelineBg extends internal$1.BaseComponent {
1030
1037
  render() {
1031
- const { props, context } = this;
1032
- return (preact.createElement("div", { className: "fc-timeline-now-indicator-container" },
1033
- preact.createElement(internal$1.NowIndicatorContainer // TODO: make separate component?
1034
- , { className: 'fc-timeline-now-indicator-line', style: props.slotWidth != null
1035
- ? horizontalCoordToCss(dateToCoord(props.nowDate, context.dateEnv, props.tDateProfile, props.slotWidth), context.isRtl)
1036
- : {}, isAxis: false, date: props.nowDate })));
1038
+ let { props } = this;
1039
+ let highlightSeg = [].concat(props.eventResizeSegs || [], props.dateSelectionSegs);
1040
+ return (preact.createElement(preact.Fragment, null,
1041
+ this.renderSegs(props.businessHourSegs || [], 'non-business'),
1042
+ this.renderSegs(props.bgEventSegs || [], 'bg-event'),
1043
+ this.renderSegs(highlightSeg, 'highlight')));
1037
1044
  }
1038
- }
1039
-
1040
- class TimelineNowIndicatorArrow extends internal$1.BaseComponent {
1041
- render() {
1042
- const { props, context } = this;
1043
- return (preact.createElement("div", { className: "fc-timeline-now-indicator-container" },
1044
- preact.createElement(internal$1.NowIndicatorContainer, { className: 'fc-timeline-now-indicator-arrow', style: props.slotWidth != null
1045
- ? horizontalCoordToCss(dateToCoord(props.nowDate, context.dateEnv, props.tDateProfile, props.slotWidth), context.isRtl)
1046
- : {}, isAxis: true, date: props.nowDate })));
1045
+ renderSegs(segs, fillType) {
1046
+ let { tDateProfile, todayRange, nowDate, slotWidth } = this.props;
1047
+ let { dateEnv, isRtl } = this.context;
1048
+ return (preact.createElement(preact.Fragment, null, segs.map((seg) => {
1049
+ let hStyle; // TODO
1050
+ if (slotWidth != null) {
1051
+ let segHorizontal = computeSegHorizontals(seg, undefined, dateEnv, tDateProfile, slotWidth);
1052
+ hStyle = horizontalsToCss(segHorizontal, isRtl);
1053
+ }
1054
+ return (preact.createElement("div", { key: internal$1.buildEventRangeKey(seg.eventRange), className: "fc-fill-y", style: hStyle }, fillType === 'bg-event' ?
1055
+ preact.createElement(internal$1.BgEvent, Object.assign({ eventRange: seg.eventRange, isStart: seg.isStart, isEnd: seg.isEnd }, internal$1.getEventRangeMeta(seg.eventRange, todayRange, nowDate))) : (internal$1.renderFill(fillType))));
1056
+ })));
1047
1057
  }
1048
1058
  }
1049
1059
 
@@ -1061,6 +1071,7 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
1061
1071
  internal$1.afterSize(this.handleSlotInnerWidths);
1062
1072
  });
1063
1073
  this.scrollTime = null;
1074
+ this.slicer = new TimelineLaneSlicer();
1064
1075
  // Sizing
1065
1076
  // -----------------------------------------------------------------------------------------------
1066
1077
  this.handleBodySlotInnerWidth = (innerWidth) => {
@@ -1068,27 +1079,30 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
1068
1079
  internal$1.afterSize(this.handleSlotInnerWidths);
1069
1080
  };
1070
1081
  this.handleSlotInnerWidths = () => {
1071
- const { state } = this;
1072
- const slotInnerWidth = Math.max(this.headerRowInnerWidthMap.current.get(this.tDateProfile.cellRows.length - 1) || 0, this.bodySlotInnerWidth);
1073
- if (state.slotInnerWidth !== slotInnerWidth) {
1074
- this.setState({ slotInnerWidth });
1082
+ const headerSlotInnerWidth = this.headerRowInnerWidthMap.current.get(this.tDateProfile.cellRows.length - 1);
1083
+ const { bodySlotInnerWidth } = this;
1084
+ if (headerSlotInnerWidth != null && bodySlotInnerWidth != null) {
1085
+ const slotInnerWidth = Math.max(headerSlotInnerWidth, bodySlotInnerWidth);
1086
+ if (slotInnerWidth !== this.state.slotInnerWidth) {
1087
+ this.setState({ slotInnerWidth });
1088
+ }
1075
1089
  }
1076
1090
  };
1077
- this.handleClientWidth = (clientWidth) => {
1091
+ this.handleTotalWidth = (totalWidth) => {
1078
1092
  this.setState({
1079
- clientWidth,
1093
+ totalWidth,
1080
1094
  });
1081
1095
  };
1082
- this.handleEndScrollbarWidth = (endScrollbarWidth) => {
1096
+ this.handleClientWidth = (clientWidth) => {
1083
1097
  this.setState({
1084
- endScrollbarWidth
1098
+ clientWidth,
1085
1099
  });
1086
1100
  };
1087
1101
  this.handleTimeScrollRequest = (scrollTime) => {
1088
1102
  this.scrollTime = scrollTime;
1089
1103
  this.applyTimeScroll();
1090
1104
  };
1091
- this.handleTimeScrollEnd = ({ isUser }) => {
1105
+ this.handleTimeScrollEnd = (isUser) => {
1092
1106
  if (isUser) {
1093
1107
  this.scrollTime = null;
1094
1108
  }
@@ -1108,6 +1122,10 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
1108
1122
  render() {
1109
1123
  const { props, state, context } = this;
1110
1124
  const { options } = context;
1125
+ const { totalWidth, clientWidth } = state;
1126
+ const endScrollbarWidth = (totalWidth != null && clientWidth != null)
1127
+ ? totalWidth - clientWidth
1128
+ : undefined;
1111
1129
  /* date */
1112
1130
  const tDateProfile = this.tDateProfile = this.buildTimelineDateProfile(props.dateProfile, context.dateEnv, options, context.dateProfileGenerator);
1113
1131
  const { cellRows } = tDateProfile;
@@ -1118,8 +1136,11 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
1118
1136
  const stickyFooterScrollbar = !props.forPrint && internal$1.getStickyFooterScrollbar(options);
1119
1137
  /* table positions */
1120
1138
  const [canvasWidth, slotWidth] = this.computeSlotWidth(tDateProfile.slotCnt, tDateProfile.slotsPerLabel, options.slotMinWidth, state.slotInnerWidth, // is ACTUALLY the label width. rename?
1121
- state.clientWidth);
1139
+ clientWidth);
1122
1140
  this.slotWidth = slotWidth;
1141
+ /* sliced */
1142
+ let slicedProps = this.slicer.sliceProps(props, props.dateProfile, tDateProfile.isTimeScale ? null : options.nextDayThreshold, context, // wish we didn't have to pass in the rest of the args...
1143
+ props.dateProfile, context.dateProfileGenerator, tDateProfile, context.dateEnv);
1123
1144
  return (preact.createElement(internal$1.NowTimer, { unit: timerUnit }, (nowDate, todayRange) => {
1124
1145
  const enableNowIndicator = // TODO: DRY
1125
1146
  options.nowIndicator &&
@@ -1139,18 +1160,30 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
1139
1160
  return (preact.createElement(TimelineHeaderRow, { key: rowLevel, dateProfile: props.dateProfile, tDateProfile: tDateProfile, nowDate: nowDate, todayRange: todayRange, rowLevel: rowLevel, isLastRow: isLast, cells: cells, slotWidth: slotWidth, innerWidthRef: this.headerRowInnerWidthMap.createRef(rowLevel) }));
1140
1161
  }),
1141
1162
  enableNowIndicator && (preact.createElement(TimelineNowIndicatorArrow, { tDateProfile: tDateProfile, nowDate: nowDate, slotWidth: slotWidth }))),
1142
- Boolean(state.endScrollbarWidth) && (preact.createElement("div", { className: 'fc-border-s fc-filler', style: { minWidth: state.endScrollbarWidth } }))),
1143
- preact.createElement(internal$1.Scroller, { vertical: verticalScrolling, horizontal: true, hideScrollbars: props.forPrint, className: internal$1.joinClassNames('fc-timeline-body fc-flex-col', verticalScrolling && 'fc-liquid'), ref: this.bodyScrollerRef, clientWidthRef: this.handleClientWidth, endScrollbarWidthRef: this.handleEndScrollbarWidth },
1163
+ Boolean(endScrollbarWidth) && (preact.createElement("div", { className: 'fc-border-s fc-filler', style: { minWidth: endScrollbarWidth } }))),
1164
+ preact.createElement(internal$1.Scroller, { vertical: verticalScrolling, horizontal: true, hideScrollbars: stickyFooterScrollbar ||
1165
+ props.forPrint // prevents blank space in print-view on Safari
1166
+ , className: internal$1.joinClassNames('fc-timeline-body fc-flex-col', verticalScrolling && 'fc-liquid'), ref: this.bodyScrollerRef, clientWidthRef: this.handleClientWidth },
1144
1167
  preact.createElement("div", { "aria-label": options.eventsHint, className: "fc-rel fc-grow", style: { width: canvasWidth }, ref: this.handeBodyEl },
1145
1168
  preact.createElement(TimelineSlats, { dateProfile: props.dateProfile, tDateProfile: tDateProfile, nowDate: nowDate, todayRange: todayRange,
1146
1169
  // ref
1147
1170
  innerWidthRef: this.handleBodySlotInnerWidth,
1148
1171
  // dimensions
1149
1172
  slotWidth: slotWidth }),
1150
- preact.createElement(TimelineLane, { dateProfile: props.dateProfile, tDateProfile: tDateProfile, nowDate: nowDate, todayRange: todayRange, nextDayThreshold: options.nextDayThreshold, eventStore: props.eventStore, eventUiBases: props.eventUiBases, businessHours: props.businessHours, dateSelection: props.dateSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection, slotWidth: slotWidth }),
1173
+ preact.createElement(TimelineBg, { tDateProfile: tDateProfile, nowDate: nowDate, todayRange: todayRange,
1174
+ // content
1175
+ bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventResizeSegs: slicedProps.eventResize ? slicedProps.eventResize.segs : null,
1176
+ // dimensions
1177
+ slotWidth: slotWidth }),
1178
+ preact.createElement(TimelineFg, { dateProfile: props.dateProfile, tDateProfile: tDateProfile, nowDate: nowDate, todayRange: todayRange,
1179
+ // content
1180
+ fgEventSegs: slicedProps.fgEventSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection,
1181
+ // dimensions
1182
+ slotWidth: slotWidth }),
1183
+ preact.createElement("div", { className: 'fc-timeline-lane-footer' }),
1151
1184
  enableNowIndicator && (preact.createElement(TimelineNowIndicatorLine, { tDateProfile: tDateProfile, nowDate: nowDate, slotWidth: slotWidth })))),
1152
- stickyFooterScrollbar && (preact.createElement(internal$1.Scroller, { ref: this.footerScrollerRef, horizontal: true },
1153
- preact.createElement("div", { style: { width: canvasWidth } })))));
1185
+ Boolean(stickyFooterScrollbar) && (preact.createElement(internal$1.FooterScrollbar, { isSticky: true, canvasWidth: canvasWidth, scrollerRef: this.footerScrollerRef })),
1186
+ preact.createElement(internal$1.Ruler, { widthRef: this.handleTotalWidth })));
1154
1187
  }));
1155
1188
  }
1156
1189
  // Lifecycle
@@ -1235,8 +1268,7 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
1235
1268
  top: 0,
1236
1269
  bottom: elHeight,
1237
1270
  },
1238
- // HACK. TODO: This is expensive to do every hit-query
1239
- dayEl: this.bodyEl.querySelectorAll('.fc-timeline-slot')[slatIndex],
1271
+ getDayEl: () => getTimelineSlotEl(this.bodyEl, slatIndex),
1240
1272
  layer: 0,
1241
1273
  };
1242
1274
  }
@@ -1244,12 +1276,12 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
1244
1276
  }
1245
1277
  }
1246
1278
 
1247
- var css_248z = ".fc-timeline-slots{z-index:1}.fc-timeline-events{position:relative;z-index:2}.fc-timeline-slot-minor{border-style:dotted}.fc-timeline-events-overlap-enabled{padding-bottom:10px}.fc-timeline-event{border-radius:0;font-size:var(--fc-small-font-size);margin-bottom:1px}.fc-direction-ltr .fc-timeline-event.fc-event-end{margin-right:1px}.fc-direction-rtl .fc-timeline-event.fc-event-end{margin-left:1px}.fc-timeline-event .fc-event-inner{align-items:center;display:flex;flex-direction:row;padding:2px 1px}.fc-timeline-event-spacious .fc-event-inner{padding-bottom:5px;padding-top:5px}.fc-timeline-event .fc-event-time{font-weight:700}.fc-timeline-event .fc-event-time,.fc-timeline-event .fc-event-title{padding:0 2px}.fc-timeline-event:not(.fc-event-end) .fc-event-inner:after,.fc-timeline-event:not(.fc-event-start) .fc-event-inner:before{border-color:transparent #000;border-style:solid;border-width:5px;content:\"\";flex-grow:0;flex-shrink:0;height:0;margin:0 1px;opacity:.5;width:0}.fc-direction-ltr .fc-timeline-event:not(.fc-event-start) .fc-event-inner:before,.fc-direction-rtl .fc-timeline-event:not(.fc-event-end) .fc-event-inner:after{border-left:0}.fc-direction-ltr .fc-timeline-event:not(.fc-event-end) .fc-event-inner:after,.fc-direction-rtl .fc-timeline-event:not(.fc-event-start) .fc-event-inner:before{border-right:0}.fc-timeline-more-link{align-items:flex-start;background:var(--fc-more-link-bg-color);color:var(--fc-more-link-text-color);cursor:pointer;display:flex;flex-direction:column;font-size:var(--fc-small-font-size);padding:1px}.fc-direction-ltr .fc-timeline-more-link{margin-right:1px}.fc-direction-rtl .fc-timeline-more-link{margin-left:1px}.fc-timeline-more-link-inner{padding:2px}.fc-timeline-now-indicator-container{bottom:0;left:0;overflow:hidden;pointer-events:none;position:absolute;right:0;top:0;z-index:4}.fc-timeline-now-indicator-arrow{border-bottom-style:solid;border-bottom-width:0;border-color:var(--fc-now-indicator-color);border-left:5px solid transparent;border-right:5px solid transparent;border-top-style:solid;border-top-width:6px;height:0;margin:0 -5px;position:absolute;top:0;width:0}.fc-timeline-now-indicator-line{border-left:1px solid var(--fc-now-indicator-color);bottom:0;position:absolute;top:0}";
1279
+ var css_248z = ".fc-timeline-lane-footer{padding-bottom:10px}.fc-timeline-overlap-disabled .fc-timeline-lane-footer{padding-bottom:0}.fc-timeline-slot-minor{border-style:dotted}.fc-timeline-event{border-radius:0;font-size:var(--fc-small-font-size);margin-bottom:1px}.fc-direction-ltr .fc-timeline-event.fc-event-end{margin-right:1px}.fc-direction-rtl .fc-timeline-event.fc-event-end{margin-left:1px}.fc-timeline-event .fc-event-inner{align-items:center;display:flex;flex-direction:row;padding:2px 1px}.fc-timeline-event-spacious .fc-event-inner{padding-bottom:5px;padding-top:5px}.fc-timeline-event .fc-event-time{font-weight:700}.fc-timeline-event .fc-event-time,.fc-timeline-event .fc-event-title{padding:0 2px}.fc-timeline-event:not(.fc-event-end) .fc-event-inner:after,.fc-timeline-event:not(.fc-event-start) .fc-event-inner:before{border-color:transparent #000;border-style:solid;border-width:5px;content:\"\";flex-grow:0;flex-shrink:0;height:0;margin:0 1px;opacity:.5;width:0}.fc-direction-ltr .fc-timeline-event:not(.fc-event-start) .fc-event-inner:before,.fc-direction-rtl .fc-timeline-event:not(.fc-event-end) .fc-event-inner:after{border-left:0}.fc-direction-ltr .fc-timeline-event:not(.fc-event-end) .fc-event-inner:after,.fc-direction-rtl .fc-timeline-event:not(.fc-event-start) .fc-event-inner:before{border-right:0}.fc-timeline-more-link{align-items:flex-start;background:var(--fc-more-link-bg-color);color:var(--fc-more-link-text-color);cursor:pointer;display:flex;flex-direction:column;font-size:var(--fc-small-font-size);padding:1px}.fc-direction-ltr .fc-timeline-more-link{margin-right:1px}.fc-direction-rtl .fc-timeline-more-link{margin-left:1px}.fc-timeline-more-link-inner{padding:2px}.fc-timeline-now-indicator-container{bottom:0;left:0;overflow:hidden;pointer-events:none;position:absolute;right:0;top:0;z-index:2}.fc-timeline-now-indicator-arrow{border-bottom-style:solid;border-bottom-width:0;border-color:var(--fc-now-indicator-color);border-left:5px solid transparent;border-right:5px solid transparent;border-top-style:solid;border-top-width:6px;height:0;margin:0 -5px;position:absolute;top:0;width:0}.fc-timeline-now-indicator-line{border-left:1px solid var(--fc-now-indicator-color);bottom:0;position:absolute;top:0}";
1248
1280
  internal$1.injectStyles(css_248z);
1249
1281
 
1250
1282
  var plugin = core.createPlugin({
1251
1283
  name: '@fullcalendar/timeline',
1252
- premiumReleaseDate: '2025-01-09',
1284
+ premiumReleaseDate: '2025-02-21',
1253
1285
  deps: [premiumCommonPlugin__default["default"]],
1254
1286
  initialView: 'timelineDay',
1255
1287
  views: {
@@ -1280,8 +1312,8 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
1280
1312
  var internal = {
1281
1313
  __proto__: null,
1282
1314
  TimelineView: TimelineView,
1283
- TimelineLane: TimelineLane,
1284
- TimelineLaneBg: TimelineLaneBg,
1315
+ TimelineFg: TimelineFg,
1316
+ TimelineBg: TimelineBg,
1285
1317
  TimelineSlats: TimelineSlats,
1286
1318
  buildTimelineDateProfile: buildTimelineDateProfile,
1287
1319
  createVerticalStyle: createVerticalStyle,
@@ -1291,7 +1323,8 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
1291
1323
  TimelineLaneSlicer: TimelineLaneSlicer,
1292
1324
  TimelineHeaderRow: TimelineHeaderRow,
1293
1325
  TimelineNowIndicatorArrow: TimelineNowIndicatorArrow,
1294
- TimelineNowIndicatorLine: TimelineNowIndicatorLine
1326
+ TimelineNowIndicatorLine: TimelineNowIndicatorLine,
1327
+ getTimelineSlotEl: getTimelineSlotEl
1295
1328
  };
1296
1329
 
1297
1330
  core.globalPlugins.push(plugin);