@fullcalendar/timeline 7.0.0-beta.3 → 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
@@ -464,14 +466,16 @@ class TimelineSlatCell extends internal_cjs.BaseComponent {
464
466
  'fc-timeline-slot-major' :
465
467
  'fc-timeline-slot-minor'), 'fc-timeline-slot-lane fc-cell fc-flex-col fc-align-start', props.borderStart && 'fc-border-s', props.isDay ?
466
468
  internal_cjs.getDayClassName(dateMeta) :
467
- internal_cjs.getSlotClassName(dateMeta)), attrs: {
468
- 'data-date': dateEnv.formatIso(date, {
469
+ internal_cjs.getSlotClassName(dateMeta)), attrs: Object.assign({ 'data-date': dateEnv.formatIso(date, {
469
470
  omitTimeZoneOffset: true,
470
471
  omitTime: !tDateProfile.isTimeScale,
471
- }),
472
- }, style: {
472
+ }) }, (dateMeta.isToday ? { 'aria-current': 'date' } : {})), style: {
473
473
  width: props.width,
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', 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 }))));
475
479
  }
476
480
  componentDidMount() {
477
481
  const innerEl = this.innerElRef.current;
@@ -506,7 +510,7 @@ class TimelineSlats extends internal_cjs.BaseComponent {
506
510
  let { tDateProfile, slotWidth } = props;
507
511
  let { slotDates, isWeekStarts } = tDateProfile;
508
512
  let isDay = !tDateProfile.isTimeScale && !tDateProfile.largeUnit;
509
- return (preact_cjs.createElement("div", { 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) => {
510
514
  let key = slotDate.toISOString();
511
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),
512
516
  // ref
@@ -517,50 +521,132 @@ class TimelineSlats extends internal_cjs.BaseComponent {
517
521
  }
518
522
  }
519
523
 
520
- /*
521
- TODO: rename this file!
522
- */
523
- // returned value is between 0 and the number of snaps
524
- function computeDateSnapCoverage$1(date, tDateProfile, dateEnv) {
525
- let snapDiff = dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.snapDuration);
526
- if (snapDiff < 0) {
527
- 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();
528
531
  }
529
- if (snapDiff >= tDateProfile.snapDiffToIndex.length) {
530
- 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 }))));
531
565
  }
532
- let snapDiffInt = Math.floor(snapDiff);
533
- let snapCoverage = tDateProfile.snapDiffToIndex[snapDiffInt];
534
- if (internal_cjs.isInt(snapCoverage)) { // not an in-between value
535
- 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
+ });
536
578
  }
537
- else {
538
- // a fractional value, meaning the date is not visible
539
- // always round up in this case. works for start AND end dates in a range.
540
- 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);
541
584
  }
542
- return snapCoverage;
543
585
  }
544
- /*
545
- TODO: DRY up with elsewhere?
546
- */
547
- function horizontalsToCss(hcoord, isRtl) {
548
- if (!hcoord) {
549
- return {};
550
- }
551
- if (isRtl) {
552
- return { right: hcoord.start, width: hcoord.size };
553
- }
554
- else {
555
- return { left: hcoord.start, width: hcoord.size };
556
- }
586
+ // Utils
587
+ // -------------------------------------------------------------------------------------------------
588
+ function renderInnerContent(renderProps) {
589
+ return renderProps.text;
557
590
  }
558
- function horizontalCoordToCss(start, isRtl) {
559
- if (isRtl) {
560
- 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
+ };
561
628
  }
562
- else {
563
- 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);
564
650
  }
565
651
  }
566
652
 
@@ -615,13 +701,38 @@ time, dateEnv, dateProfile, tDateProfile, slowWidth) {
615
701
  }
616
702
  function dateToCoord(// pixels
617
703
  date, dateEnv, tDateProfile, slotWidth) {
618
- let snapCoverage = computeDateSnapCoverage(date, tDateProfile, dateEnv);
704
+ let snapCoverage = computeDateSnapCoverage$1(date, tDateProfile, dateEnv);
619
705
  let slotCoverage = snapCoverage / tDateProfile.snapsPerSlot;
620
706
  return slotCoverage * slotWidth;
621
707
  }
622
708
  /*
623
709
  returned value is between 0 and the number of snaps
624
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
625
736
  function computeDateSnapCoverage(date, tDateProfile, dateEnv) {
626
737
  let snapDiff = dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.snapDuration);
627
738
  if (snapDiff < 0) {
@@ -640,7 +751,107 @@ function computeDateSnapCoverage(date, tDateProfile, dateEnv) {
640
751
  // always round up in this case. works for start AND end dates in a range.
641
752
  snapCoverage = Math.ceil(snapCoverage);
642
753
  }
643
- 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
+ }
644
855
  }
645
856
 
646
857
  function computeManySegHorizontals(segs, segMinWidth, dateEnv, tDateProfile, slotWidth) {
@@ -707,83 +918,6 @@ hiddenGroupHeights, strictOrder, maxDepth) {
707
918
  ];
708
919
  }
709
920
 
710
- class TimelineLaneBg extends internal_cjs.BaseComponent {
711
- render() {
712
- let { props } = this;
713
- let highlightSeg = [].concat(props.eventResizeSegs, props.dateSelectionSegs);
714
- return (preact_cjs.createElement(preact_cjs.Fragment, null,
715
- this.renderSegs(props.businessHourSegs || [], 'non-business'),
716
- this.renderSegs(props.bgEventSegs || [], 'bg-event'),
717
- this.renderSegs(highlightSeg, 'highlight')));
718
- }
719
- renderSegs(segs, fillType) {
720
- let { tDateProfile, todayRange, nowDate, slotWidth } = this.props;
721
- let { dateEnv, isRtl } = this.context;
722
- return (preact_cjs.createElement(preact_cjs.Fragment, null, segs.map((seg) => {
723
- let hStyle; // TODO
724
- if (slotWidth != null) {
725
- let segHorizontal = computeSegHorizontals(seg, undefined, dateEnv, tDateProfile, slotWidth);
726
- hStyle = horizontalsToCss(segHorizontal, isRtl);
727
- }
728
- return (preact_cjs.createElement("div", { key: internal_cjs.buildEventRangeKey(seg.eventRange), className: "fc-fill-y", style: hStyle }, fillType === 'bg-event' ?
729
- 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))));
730
- })));
731
- }
732
- }
733
-
734
- class TimelineLaneSlicer extends internal_cjs.Slicer {
735
- sliceRange(origRange, dateProfile, dateProfileGenerator, tDateProfile, dateEnv) {
736
- let normalRange = normalizeRange(origRange, tDateProfile, dateEnv);
737
- let segs = [];
738
- // protect against when the span is entirely in an invalid date region
739
- if (computeDateSnapCoverage$1(normalRange.start, tDateProfile, dateEnv)
740
- < computeDateSnapCoverage$1(normalRange.end, tDateProfile, dateEnv)) {
741
- // intersect the footprint's range with the grid's range
742
- let slicedRange = internal_cjs.intersectRanges(normalRange, tDateProfile.normalizedRange);
743
- if (slicedRange) {
744
- segs.push({
745
- startDate: slicedRange.start,
746
- endDate: slicedRange.end,
747
- isStart: slicedRange.start.valueOf() === normalRange.start.valueOf()
748
- && isValidDate(slicedRange.start, tDateProfile, dateProfile, dateProfileGenerator),
749
- isEnd: slicedRange.end.valueOf() === normalRange.end.valueOf()
750
- && isValidDate(internal_cjs.addMs(slicedRange.end, -1), tDateProfile, dateProfile, dateProfileGenerator),
751
- });
752
- }
753
- }
754
- return segs;
755
- }
756
- }
757
-
758
- const DEFAULT_TIME_FORMAT = internal_cjs.createFormatter({
759
- hour: 'numeric',
760
- minute: '2-digit',
761
- omitZeroMinute: true,
762
- meridiem: 'narrow',
763
- });
764
- class TimelineEvent extends internal_cjs.BaseComponent {
765
- render() {
766
- let { props, context } = this;
767
- let { options } = context;
768
- return (preact_cjs.createElement(internal_cjs.StandardEvent, Object.assign({}, props, { className: internal_cjs.joinClassNames('fc-timeline-event', options.eventOverlap === false // TODO: fix bad default
769
- && 'fc-timeline-event-spacious', 'fc-h-event'), defaultTimeFormat: DEFAULT_TIME_FORMAT, defaultDisplayEventTime: !props.isTimeScale })));
770
- }
771
- }
772
-
773
- class TimelineLaneMoreLink extends internal_cjs.BaseComponent {
774
- render() {
775
- let { props } = this;
776
- let { hiddenSegs, resourceId, forcedInvisibleMap } = props;
777
- let dateSpanProps = resourceId ? { resourceId } : {};
778
- 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) => {
779
- let { eventRange } = seg;
780
- let instanceId = eventRange.instance.instanceId;
781
- return (preact_cjs.createElement("div", { key: instanceId, style: { visibility: forcedInvisibleMap[instanceId] ? 'hidden' : '' } },
782
- 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)))));
783
- }))) }, (InnerContent) => (preact_cjs.createElement(InnerContent, { tag: "div", className: 'fc-timeline-more-link-inner fc-sticky-s' }))));
784
- }
785
- }
786
-
787
921
  /*
788
922
  TODO: make DRY with other Event Harnesses
789
923
  */
@@ -809,10 +943,7 @@ class TimelineEventHarness extends preact_cjs.Component {
809
943
  }
810
944
  }
811
945
 
812
- /*
813
- TODO: split TimelineLaneBg and TimelineLaneFg?
814
- */
815
- class TimelineLane extends internal_cjs.BaseComponent {
946
+ class TimelineFg extends internal_cjs.BaseComponent {
816
947
  constructor() {
817
948
  super(...arguments);
818
949
  // memo
@@ -824,8 +955,6 @@ class TimelineLane extends internal_cjs.BaseComponent {
824
955
  this.moreLinkHeightRefMap = new internal_cjs.RefMap(() => {
825
956
  internal_cjs.afterSize(this.handleMoreLinkHeights);
826
957
  });
827
- // internal
828
- this.slicer = new TimelineLaneSlicer();
829
958
  this.handleMoreLinkHeights = () => {
830
959
  this.setState({ moreLinkHeightRev: this.moreLinkHeightRefMap.rev }); // will trigger rerender
831
960
  };
@@ -839,39 +968,30 @@ class TimelineLane extends internal_cjs.BaseComponent {
839
968
  render() {
840
969
  let { props, context, segHeightRefMap, moreLinkHeightRefMap } = this;
841
970
  let { options } = context;
842
- let { dateProfile, tDateProfile } = props;
843
- 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...
844
- dateProfile, context.dateProfileGenerator, tDateProfile, context.dateEnv);
845
- let mirrorSegs = (slicedProps.eventDrag ? slicedProps.eventDrag.segs : null) ||
846
- (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) ||
847
974
  [];
848
- let fgSegs = this.sortEventSegs(slicedProps.fgEventSegs, options.eventOrder);
975
+ let fgSegs = this.sortEventSegs(props.fgEventSegs, options.eventOrder);
849
976
  let fgSegHorizontals = props.slotWidth != null
850
977
  ? computeManySegHorizontals(fgSegs, options.eventMinWidth, context.dateEnv, tDateProfile, props.slotWidth)
851
978
  : {};
852
979
  let [fgSegTops, hiddenGroups, hiddenGroupTops, totalHeight] = computeFgSegPlacements(fgSegs, fgSegHorizontals, segHeightRefMap.current, moreLinkHeightRefMap.current, options.eventOrderStrict, options.eventMaxStack);
980
+ this.totalHeight = totalHeight;
853
981
  let forcedInvisibleMap = // TODO: more convenient/DRY
854
- (slicedProps.eventDrag ? slicedProps.eventDrag.affectedInstances : null) ||
855
- (slicedProps.eventResize ? slicedProps.eventResize.affectedInstances : null) ||
982
+ (props.eventDrag ? props.eventDrag.affectedInstances : null) ||
983
+ (props.eventResize ? props.eventResize.affectedInstances : null) ||
856
984
  {};
857
- return (preact_cjs.createElement(preact_cjs.Fragment, null,
858
- preact_cjs.createElement(TimelineLaneBg, { tDateProfile: tDateProfile, nowDate: props.nowDate, todayRange: props.todayRange,
859
- // content
860
- bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventResizeSegs: slicedProps.eventResize ? slicedProps.eventResize.segs : [] /* bad new empty array? */,
861
- // dimensions
862
- slotWidth: props.slotWidth }),
863
- preact_cjs.createElement("div", { className: internal_cjs.joinClassNames('fc-timeline-events', options.eventOverlap === false // TODO: fix bad default
864
- ? 'fc-timeline-events-overlap-disabled'
865
- : 'fc-timeline-events-overlap-enabled', 'fc-content-box'), style: { height: totalHeight } },
866
- this.renderFgSegs(fgSegs, fgSegHorizontals, fgSegTops, forcedInvisibleMap, hiddenGroups, hiddenGroupTops, false, // isDragging
867
- false, // isResizing
868
- false),
869
- this.renderFgSegs(mirrorSegs, props.slotWidth // TODO: memoize
870
- ? computeManySegHorizontals(mirrorSegs, options.eventMinWidth, context.dateEnv, tDateProfile, props.slotWidth)
871
- : {}, fgSegTops, {}, // forcedInvisibleMap
872
- [], // hiddenGroups
873
- new Map(), // hiddenGroupTops
874
- 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)));
875
995
  }
876
996
  renderFgSegs(segs, segHorizontals, segTops, forcedInvisibleMap, hiddenGroups, hiddenGroupTops, isDragging, isResizing, isDateSelecting) {
877
997
  let { props, context, segHeightRefMap, moreLinkHeightRefMap } = this;
@@ -893,158 +1013,43 @@ class TimelineLane extends internal_cjs.BaseComponent {
893
1013
  }, context.isRtl)), heightRef: moreLinkHeightRefMap.createRef(hiddenGroup.key) },
894
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 }))))));
895
1015
  }
896
- }
897
-
898
- class TimelineHeaderCell extends internal_cjs.BaseComponent {
899
- constructor() {
900
- super(...arguments);
901
- // memo
902
- this.refineRenderProps = internal_cjs.memoizeObjArg(refineRenderProps);
903
- this.buildCellNavLinkAttrs = internal_cjs.memoize(buildCellNavLinkAttrs);
904
- // ref
905
- this.innerElRef = preact_cjs.createRef();
906
- }
907
- render() {
908
- let { props, context } = this;
909
- let { dateEnv, options } = context;
910
- let { cell, dateProfile, tDateProfile } = props;
911
- // the cell.rowUnit is f'd
912
- // giving 'month' for a 3-day view
913
- // workaround: to infer day, do NOT time
914
- let dateMeta = internal_cjs.getDateMeta(cell.date, props.todayRange, props.nowDate, dateProfile);
915
- let renderProps = this.refineRenderProps({
916
- level: props.rowLevel,
917
- dateMarker: cell.date,
918
- text: cell.text,
919
- dateEnv: context.dateEnv,
920
- viewApi: context.viewApi,
921
- });
922
- 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
923
- 'fc-header-cell fc-cell fc-flex-col fc-justify-center', props.borderStart && 'fc-border-s', props.isCentered ? 'fc-align-center' : 'fc-align-start',
924
- // TODO: so slot classnames for week/month/bigger. see note above about rowUnit
925
- cell.rowUnit === 'time' ?
926
- internal_cjs.getSlotClassName(dateMeta) :
927
- internal_cjs.getDayClassName(dateMeta)), attrs: {
928
- 'data-date': dateEnv.formatIso(cell.date, {
929
- omitTime: !tDateProfile.isTimeScale,
930
- omitTimeZoneOffset: true,
931
- }),
932
- }, 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_cjs.createElement(InnerContent, { tag: "a", attrs: this.buildCellNavLinkAttrs(context, cell.date, cell.rowUnit), 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 buildCellNavLinkAttrs(context, cellDate, rowUnit) {
961
- return (rowUnit && rowUnit !== 'time')
962
- ? internal_cjs.buildNavLinkAttrs(context, cellDate, rowUnit)
963
- : {};
964
- }
965
- function renderInnerContent(renderProps) {
966
- return renderProps.text;
967
- }
968
- function refineRenderProps(input) {
969
- return {
970
- level: input.level,
971
- date: input.dateEnv.toDate(input.dateMarker),
972
- view: input.viewApi,
973
- text: input.text,
974
- };
975
- }
976
-
977
- class TimelineHeaderRow extends internal_cjs.BaseComponent {
978
- constructor() {
979
- super(...arguments);
980
- // refs
981
- this.innerWidthRefMap = new internal_cjs.RefMap(() => {
982
- internal_cjs.afterSize(this.handleInnerWidths);
983
- });
984
- this.innerHeightRefMap = new internal_cjs.RefMap(() => {
985
- internal_cjs.afterSize(this.handleInnerHeights);
986
- });
987
- this.handleInnerWidths = () => {
988
- const innerWidthMap = this.innerWidthRefMap.current;
989
- let max = 0;
990
- for (const innerWidth of innerWidthMap.values()) {
991
- max = Math.max(max, innerWidth);
992
- }
993
- // TODO: ensure not equal?
994
- internal_cjs.setRef(this.props.innerWidthRef, max);
995
- };
996
- this.handleInnerHeights = () => {
997
- const innerHeightMap = this.innerHeightRefMap.current;
998
- let max = 0;
999
- for (const innerHeight of innerHeightMap.values()) {
1000
- max = Math.max(max, innerHeight);
1001
- }
1002
- // TODO: ensure not equal?
1003
- internal_cjs.setRef(this.props.innerHeighRef, max);
1004
- };
1016
+ /*
1017
+ componentDidMount(): void {
1018
+ // might want to do firedTotalHeight, but won't be ready on first render
1005
1019
  }
1006
- render() {
1007
- const { props, innerWidthRefMap, innerHeightRefMap } = this;
1008
- const isCentered = !(props.tDateProfile.isTimeScale && props.isLastRow);
1009
- const isSticky = !props.isLastRow;
1010
- return (preact_cjs.createElement("div", { className: internal_cjs.joinClassNames('fc-flex-row fc-grow', // TODO: move fc-grow to parent?
1011
- !props.isLastRow && 'fc-border-b') }, props.cells.map((cell, cellI) => {
1012
- // TODO: make this part of the cell obj?
1013
- // TODO: rowUnit seems wrong sometimes. says 'month' when it should be day
1014
- // TODO: rowUnit is relevant to whole row. put it on a row object, not the cells
1015
- // TODO: use rowUnit to key the Row itself?
1016
- const key = cell.rowUnit + ':' + cell.date.toISOString();
1017
- 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),
1018
- // refs
1019
- innerWidthRef: innerWidthRefMap.createRef(key), innerHeightRef: innerHeightRefMap.createRef(key),
1020
- // dimensions
1021
- slotWidth: props.slotWidth }));
1022
- })));
1020
+ */
1021
+ componentDidUpdate() {
1022
+ if (this.totalHeight !== this.firedTotalHeight) {
1023
+ this.firedTotalHeight = this.totalHeight;
1024
+ internal_cjs.setRef(this.props.heightRef, this.totalHeight);
1025
+ }
1023
1026
  }
1024
1027
  componentWillUnmount() {
1025
- internal_cjs.setRef(this.props.innerWidthRef, null);
1026
- internal_cjs.setRef(this.props.innerHeighRef, null);
1028
+ internal_cjs.setRef(this.props.heightRef, null);
1027
1029
  }
1028
1030
  }
1029
1031
 
1030
- class TimelineNowIndicatorLine extends internal_cjs.BaseComponent {
1032
+ class TimelineBg extends internal_cjs.BaseComponent {
1031
1033
  render() {
1032
- const { props, context } = this;
1033
- return (preact_cjs.createElement("div", { className: "fc-timeline-now-indicator-container" },
1034
- preact_cjs.createElement(internal_cjs.NowIndicatorContainer // TODO: make separate component?
1035
- , { className: 'fc-timeline-now-indicator-line', style: props.slotWidth != null
1036
- ? horizontalCoordToCss(dateToCoord(props.nowDate, context.dateEnv, props.tDateProfile, props.slotWidth), context.isRtl)
1037
- : {}, 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')));
1038
1040
  }
1039
- }
1040
-
1041
- class TimelineNowIndicatorArrow extends internal_cjs.BaseComponent {
1042
- render() {
1043
- const { props, context } = this;
1044
- return (preact_cjs.createElement("div", { className: "fc-timeline-now-indicator-container" },
1045
- preact_cjs.createElement(internal_cjs.NowIndicatorContainer, { className: 'fc-timeline-now-indicator-arrow', style: props.slotWidth != null
1046
- ? horizontalCoordToCss(dateToCoord(props.nowDate, context.dateEnv, props.tDateProfile, props.slotWidth), context.isRtl)
1047
- : {}, 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
+ })));
1048
1053
  }
1049
1054
  }
1050
1055
 
@@ -1062,6 +1067,7 @@ class TimelineView extends internal_cjs.DateComponent {
1062
1067
  internal_cjs.afterSize(this.handleSlotInnerWidths);
1063
1068
  });
1064
1069
  this.scrollTime = null;
1070
+ this.slicer = new TimelineLaneSlicer();
1065
1071
  // Sizing
1066
1072
  // -----------------------------------------------------------------------------------------------
1067
1073
  this.handleBodySlotInnerWidth = (innerWidth) => {
@@ -1069,39 +1075,34 @@ class TimelineView extends internal_cjs.DateComponent {
1069
1075
  internal_cjs.afterSize(this.handleSlotInnerWidths);
1070
1076
  };
1071
1077
  this.handleSlotInnerWidths = () => {
1072
- const { state } = this;
1073
- const slotInnerWidth = Math.max(this.headerRowInnerWidthMap.current.get(this.tDateProfile.cellRows.length - 1) || 0, this.bodySlotInnerWidth);
1074
- if (state.slotInnerWidth !== slotInnerWidth) {
1075
- 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
+ }
1076
1085
  }
1077
1086
  };
1078
- this.handleClientWidth = (clientWidth) => {
1087
+ this.handleTotalWidth = (totalWidth) => {
1079
1088
  this.setState({
1080
- clientWidth,
1089
+ totalWidth,
1081
1090
  });
1082
1091
  };
1083
- this.handleEndScrollbarWidth = (endScrollbarWidth) => {
1092
+ this.handleClientWidth = (clientWidth) => {
1084
1093
  this.setState({
1085
- endScrollbarWidth
1094
+ clientWidth,
1086
1095
  });
1087
1096
  };
1088
- this.handleTimeScroll = (scrollTime) => {
1097
+ this.handleTimeScrollRequest = (scrollTime) => {
1089
1098
  this.scrollTime = scrollTime;
1090
- this.updateScroll();
1099
+ this.applyTimeScroll();
1091
1100
  };
1092
- this.updateScroll = () => {
1093
- const { props, context, tDateProfile, scrollTime, slotWidth } = this;
1094
- if (scrollTime != null && slotWidth != null) {
1095
- let x = timeToCoord(scrollTime, context.dateEnv, props.dateProfile, tDateProfile, slotWidth);
1096
- if (x) {
1097
- x += 1; // overcome border. TODO: DRY this up
1098
- }
1099
- this.syncedScroller.scrollTo({ x });
1101
+ this.handleTimeScrollEnd = (isUser) => {
1102
+ if (isUser) {
1103
+ this.scrollTime = null;
1100
1104
  }
1101
1105
  };
1102
- this.clearScroll = () => {
1103
- this.scrollTime = null;
1104
- };
1105
1106
  // Hit System
1106
1107
  // -----------------------------------------------------------------------------------------------
1107
1108
  this.handeBodyEl = (el) => {
@@ -1117,6 +1118,10 @@ class TimelineView extends internal_cjs.DateComponent {
1117
1118
  render() {
1118
1119
  const { props, state, context } = this;
1119
1120
  const { options } = context;
1121
+ const { totalWidth, clientWidth } = state;
1122
+ const endScrollbarWidth = (totalWidth != null && clientWidth != null)
1123
+ ? totalWidth - clientWidth
1124
+ : undefined;
1120
1125
  /* date */
1121
1126
  const tDateProfile = this.tDateProfile = this.buildTimelineDateProfile(props.dateProfile, context.dateEnv, options, context.dateProfileGenerator);
1122
1127
  const { cellRows } = tDateProfile;
@@ -1127,8 +1132,11 @@ class TimelineView extends internal_cjs.DateComponent {
1127
1132
  const stickyFooterScrollbar = !props.forPrint && internal_cjs.getStickyFooterScrollbar(options);
1128
1133
  /* table positions */
1129
1134
  const [canvasWidth, slotWidth] = this.computeSlotWidth(tDateProfile.slotCnt, tDateProfile.slotsPerLabel, options.slotMinWidth, state.slotInnerWidth, // is ACTUALLY the label width. rename?
1130
- state.clientWidth);
1135
+ clientWidth);
1131
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);
1132
1140
  return (preact_cjs.createElement(internal_cjs.NowTimer, { unit: timerUnit }, (nowDate, todayRange) => {
1133
1141
  const enableNowIndicator = // TODO: DRY
1134
1142
  options.nowIndicator &&
@@ -1148,18 +1156,30 @@ class TimelineView extends internal_cjs.DateComponent {
1148
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) }));
1149
1157
  }),
1150
1158
  enableNowIndicator && (preact_cjs.createElement(TimelineNowIndicatorArrow, { tDateProfile: tDateProfile, nowDate: nowDate, slotWidth: slotWidth }))),
1151
- Boolean(state.endScrollbarWidth) && (preact_cjs.createElement("div", { className: 'fc-border-s fc-filler', style: { minWidth: state.endScrollbarWidth } }))),
1152
- 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 },
1153
- preact_cjs.createElement("div", { className: "fc-rel fc-grow", style: { width: canvasWidth }, ref: this.handeBodyEl },
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 },
1163
+ preact_cjs.createElement("div", { "aria-label": options.eventsHint, className: "fc-rel fc-grow", style: { width: canvasWidth }, ref: this.handeBodyEl },
1154
1164
  preact_cjs.createElement(TimelineSlats, { dateProfile: props.dateProfile, tDateProfile: tDateProfile, nowDate: nowDate, todayRange: todayRange,
1155
1165
  // ref
1156
1166
  innerWidthRef: this.handleBodySlotInnerWidth,
1157
1167
  // dimensions
1158
1168
  slotWidth: slotWidth }),
1159
- 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' }),
1160
1180
  enableNowIndicator && (preact_cjs.createElement(TimelineNowIndicatorLine, { tDateProfile: tDateProfile, nowDate: nowDate, slotWidth: slotWidth })))),
1161
- stickyFooterScrollbar && (preact_cjs.createElement(internal_cjs.Scroller, { ref: this.footerScrollerRef, horizontal: true },
1162
- 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 })));
1163
1183
  }));
1164
1184
  }
1165
1185
  // Lifecycle
@@ -1168,8 +1188,8 @@ class TimelineView extends internal_cjs.DateComponent {
1168
1188
  this.syncedScroller = new internal_cjs$1.ScrollerSyncer(true); // horizontal=true
1169
1189
  this.updateSyncedScroller();
1170
1190
  this.resetScroll();
1171
- this.context.emitter.on('_timeScrollRequest', this.handleTimeScroll);
1172
- this.syncedScroller.addScrollEndListener(this.clearScroll);
1191
+ this.context.emitter.on('_timeScrollRequest', this.handleTimeScrollRequest);
1192
+ this.syncedScroller.addScrollEndListener(this.handleTimeScrollEnd);
1173
1193
  }
1174
1194
  componentDidUpdate(prevProps) {
1175
1195
  this.updateSyncedScroller();
@@ -1178,13 +1198,13 @@ class TimelineView extends internal_cjs.DateComponent {
1178
1198
  }
1179
1199
  else {
1180
1200
  // TODO: inefficient to update so often
1181
- this.updateScroll();
1201
+ this.applyTimeScroll();
1182
1202
  }
1183
1203
  }
1184
1204
  componentWillUnmount() {
1185
1205
  this.syncedScroller.destroy();
1186
- this.context.emitter.off('_timeScrollRequest', this.handleTimeScroll);
1187
- this.syncedScroller.removeScrollEndListener(this.clearScroll);
1206
+ this.context.emitter.off('_timeScrollRequest', this.handleTimeScrollRequest);
1207
+ this.syncedScroller.removeScrollEndListener(this.handleTimeScrollEnd);
1188
1208
  }
1189
1209
  // Scrolling
1190
1210
  // -----------------------------------------------------------------------------------------------
@@ -1196,7 +1216,17 @@ class TimelineView extends internal_cjs.DateComponent {
1196
1216
  ]);
1197
1217
  }
1198
1218
  resetScroll() {
1199
- this.handleTimeScroll(this.context.options.scrollTime);
1219
+ this.handleTimeScrollRequest(this.context.options.scrollTime);
1220
+ }
1221
+ applyTimeScroll() {
1222
+ const { props, context, tDateProfile, scrollTime, slotWidth } = this;
1223
+ if (scrollTime != null && slotWidth != null) {
1224
+ let x = timeToCoord(scrollTime, context.dateEnv, props.dateProfile, tDateProfile, slotWidth);
1225
+ if (x) {
1226
+ x += 1; // overcome border. TODO: DRY this up
1227
+ }
1228
+ this.syncedScroller.scrollTo({ x });
1229
+ }
1200
1230
  }
1201
1231
  queryHit(positionLeft, positionTop, elWidth, elHeight) {
1202
1232
  const { props, context, tDateProfile, slotWidth } = this;
@@ -1234,8 +1264,7 @@ class TimelineView extends internal_cjs.DateComponent {
1234
1264
  top: 0,
1235
1265
  bottom: elHeight,
1236
1266
  },
1237
- // HACK. TODO: This is expensive to do every hit-query
1238
- dayEl: this.bodyEl.querySelectorAll('.fc-timeline-slot')[slatIndex],
1267
+ getDayEl: () => getTimelineSlotEl(this.bodyEl, slatIndex),
1239
1268
  layer: 0,
1240
1269
  };
1241
1270
  }
@@ -1243,12 +1272,12 @@ class TimelineView extends internal_cjs.DateComponent {
1243
1272
  }
1244
1273
  }
1245
1274
 
1246
- 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}";
1247
1276
  internal_cjs.injectStyles(css_248z);
1248
1277
 
1278
+ exports.TimelineBg = TimelineBg;
1279
+ exports.TimelineFg = TimelineFg;
1249
1280
  exports.TimelineHeaderRow = TimelineHeaderRow;
1250
- exports.TimelineLane = TimelineLane;
1251
- exports.TimelineLaneBg = TimelineLaneBg;
1252
1281
  exports.TimelineLaneSlicer = TimelineLaneSlicer;
1253
1282
  exports.TimelineNowIndicatorArrow = TimelineNowIndicatorArrow;
1254
1283
  exports.TimelineNowIndicatorLine = TimelineNowIndicatorLine;
@@ -1258,4 +1287,5 @@ exports.buildTimelineDateProfile = buildTimelineDateProfile;
1258
1287
  exports.computeSlotWidth = computeSlotWidth;
1259
1288
  exports.createHorizontalStyle = createHorizontalStyle;
1260
1289
  exports.createVerticalStyle = createVerticalStyle;
1290
+ exports.getTimelineSlotEl = getTimelineSlotEl;
1261
1291
  exports.timeToCoord = timeToCoord;