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