Bladeren bron

refactor: interactions, timegrid

Adam Shaw 6 jaren geleden
bovenliggende
commit
cfa564ed7b

+ 1 - 1
packages/core/src/interactions/EventClicking.ts

@@ -14,7 +14,7 @@ export default class EventClicking extends Interaction {
     let { component } = settings
     let { component } = settings
 
 
     this.destroy = listenBySelector(
     this.destroy = listenBySelector(
-      component.el,
+      component.rootEl,
       'click',
       'click',
       component.fgSegSelector + ',' + component.bgSegSelector,
       component.fgSegSelector + ',' + component.bgSegSelector,
       this.handleSegClick
       this.handleSegClick

+ 1 - 1
packages/core/src/interactions/EventHovering.ts

@@ -17,7 +17,7 @@ export default class EventHovering extends Interaction {
     let { component } = settings
     let { component } = settings
 
 
     this.removeHoverListeners = listenToHoverBySelector(
     this.removeHoverListeners = listenToHoverBySelector(
-      component.el,
+      component.rootEl,
       component.fgSegSelector + ',' + component.bgSegSelector,
       component.fgSegSelector + ',' + component.bgSegSelector,
       this.handleSegEnter,
       this.handleSegEnter,
       this.handleSegLeave
       this.handleSegLeave

+ 1 - 1
packages/interaction/src/interactions/DateClicking.ts

@@ -16,7 +16,7 @@ export default class DateClicking extends Interaction {
     let { component } = settings
     let { component } = settings
 
 
     // we DO want to watch pointer moves because otherwise finalHit won't get populated
     // we DO want to watch pointer moves because otherwise finalHit won't get populated
-    this.dragging = new FeaturefulElementDragging(component.el)
+    this.dragging = new FeaturefulElementDragging(component.rootEl)
     this.dragging.autoScroller.isEnabled = false
     this.dragging.autoScroller.isEnabled = false
 
 
     let hitDragging = this.hitDragging = new HitDragging(this.dragging, interactionSettingsToStore(settings))
     let hitDragging = this.hitDragging = new HitDragging(this.dragging, interactionSettingsToStore(settings))

+ 1 - 1
packages/interaction/src/interactions/DateSelecting.ts

@@ -22,7 +22,7 @@ export default class DateSelecting extends Interaction {
     let { component } = settings
     let { component } = settings
     let { options } = component.context
     let { options } = component.context
 
 
-    let dragging = this.dragging = new FeaturefulElementDragging(component.el)
+    let dragging = this.dragging = new FeaturefulElementDragging(component.rootEl)
     dragging.touchScrollAllowed = false
     dragging.touchScrollAllowed = false
     dragging.minDistance = options.selectMinDistance || 0
     dragging.minDistance = options.selectMinDistance || 0
     dragging.autoScroller.isEnabled = options.dragScroll
     dragging.autoScroller.isEnabled = options.dragScroll

+ 1 - 1
packages/interaction/src/interactions/EventDragging.ts

@@ -41,7 +41,7 @@ export default class EventDragging extends Interaction { // TODO: rename to Even
     let { component } = this
     let { component } = this
     let { options } = component.context
     let { options } = component.context
 
 
-    let dragging = this.dragging = new FeaturefulElementDragging(component.el)
+    let dragging = this.dragging = new FeaturefulElementDragging(component.rootEl)
     dragging.pointer.selector = EventDragging.SELECTOR
     dragging.pointer.selector = EventDragging.SELECTOR
     dragging.touchScrollAllowed = false
     dragging.touchScrollAllowed = false
     dragging.autoScroller.isEnabled = options.dragScroll
     dragging.autoScroller.isEnabled = options.dragScroll

+ 1 - 1
packages/interaction/src/interactions/EventResizing.ts

@@ -34,7 +34,7 @@ export default class EventDragging extends Interaction {
     super(settings)
     super(settings)
     let { component } = settings
     let { component } = settings
 
 
-    let dragging = this.dragging = new FeaturefulElementDragging(component.el)
+    let dragging = this.dragging = new FeaturefulElementDragging(component.rootEl)
     dragging.pointer.selector = '.fc-resizer'
     dragging.pointer.selector = '.fc-resizer'
     dragging.touchScrollAllowed = false
     dragging.touchScrollAllowed = false
     dragging.autoScroller.isEnabled = component.context.options.dragScroll
     dragging.autoScroller.isEnabled = component.context.options.dragScroll

+ 162 - 0
packages/timegrid/src/DayTimeCols.ts

@@ -0,0 +1,162 @@
+import {
+  DateComponent,
+  DateProfile,
+  EventStore,
+  EventUiHash,
+  EventInteractionState,
+  DateSpan,
+  memoize,
+  intersectRanges, DateRange,
+  DayTableModel,
+  DateEnv,
+  DateMarker,
+  Slicer,
+  Hit,
+  ComponentContext,
+  renderer
+} from '@fullcalendar/core'
+import TimeCols, { TimeColsSeg, TimeColsRenderProps } from './TimeCols'
+
+export interface DayTimeColsProps {
+  renderProps: TimeColsRenderProps
+  dateProfile: DateProfile | null
+  dayTableModel: DayTableModel
+  businessHours: EventStore
+  eventStore: EventStore
+  eventUiBases: EventUiHash
+  dateSelection: DateSpan | null
+  eventSelection: string
+  eventDrag: EventInteractionState | null
+  eventResize: EventInteractionState | null
+}
+
+export default class DayTimeCols extends DateComponent<DayTimeColsProps> {
+
+  private buildDayRanges = memoize(buildDayRanges)
+  private renderTimeCols = renderer(TimeCols)
+  private registerInteractive = renderer(this._registerInteractive, this._unregisterInteractive)
+
+  private dayRanges: DateRange[] // for now indicator
+  private slicer = new DayTimeColsSlicer()
+  timeCols: TimeCols
+
+
+  render(props: DayTimeColsProps, context: ComponentContext) {
+    let { dateEnv } = context
+    let { dateProfile, dayTableModel } = props
+
+    let dayRanges = this.buildDayRanges(dayTableModel, dateProfile, dateEnv)
+
+    let timeCols = this.renderTimeCols(true, {
+      ...this.slicer.sliceProps(props, dateProfile, null, context.calendar, dayRanges),
+      renderProps: props.renderProps,
+      dateProfile,
+      cells: dayTableModel.cells[0] // give the first row
+    })
+
+    this.registerInteractive(true, { el: timeCols.rootEl })
+
+    this.dayRanges = dayRanges
+    this.timeCols = timeCols
+
+    return timeCols
+  }
+
+
+  _registerInteractive({ el }: { el: HTMLElement }, context: ComponentContext) {
+    context.calendar.registerInteractiveComponent(this, { el })
+  }
+
+
+  _unregisterInteractive(funcState: void, context: ComponentContext) {
+    context.calendar.unregisterInteractiveComponent(this)
+  }
+
+
+  updateSize(isResize: boolean) {
+    this.timeCols.updateSize(isResize)
+  }
+
+
+  getNowIndicatorUnit() {
+    return this.timeCols.getNowIndicatorUnit()
+  }
+
+
+  renderNowIndicator(date: DateMarker) {
+    this.timeCols.renderNowIndicator(
+      this.slicer.sliceNowDate(date, this.context.calendar, this.dayRanges),
+      date
+    )
+  }
+
+
+  unrenderNowIndicator() {
+    this.timeCols.unrenderNowIndicator()
+  }
+
+
+  buildPositionCaches() {
+    this.timeCols.buildPositionCaches()
+  }
+
+
+  queryHit(positionLeft: number, positionTop: number): Hit {
+    let rawHit = this.timeCols.positionToHit(positionLeft, positionTop)
+
+    if (rawHit) {
+      return {
+        component: this,
+        dateSpan: rawHit.dateSpan,
+        dayEl: rawHit.dayEl,
+        rect: {
+          left: rawHit.relativeRect.left,
+          right: rawHit.relativeRect.right,
+          top: rawHit.relativeRect.top,
+          bottom: rawHit.relativeRect.bottom
+        },
+        layer: 0
+      }
+    }
+  }
+
+}
+
+
+export function buildDayRanges(dayTableModel: DayTableModel, dateProfile: DateProfile, dateEnv: DateEnv): DateRange[] {
+  let ranges: DateRange[] = []
+
+  for (let date of dayTableModel.headerDates) {
+    ranges.push({
+      start: dateEnv.add(date, dateProfile.minTime),
+      end: dateEnv.add(date, dateProfile.maxTime)
+    })
+  }
+
+  return ranges
+}
+
+
+export class DayTimeColsSlicer extends Slicer<TimeColsSeg, [DateRange[]]> {
+
+  sliceRange(range: DateRange, dayRanges: DateRange[]): TimeColsSeg[] {
+    let segs: TimeColsSeg[] = []
+
+    for (let col = 0; col < dayRanges.length; col++) {
+      let segRange = intersectRanges(range, dayRanges[col])
+
+      if (segRange) {
+        segs.push({
+          start: segRange.start,
+          end: segRange.end,
+          isStart: segRange.start.valueOf() === range.start.valueOf(),
+          isEnd: segRange.end.valueOf() === range.end.valueOf(),
+          col
+        })
+      }
+    }
+
+    return segs
+  }
+
+}

+ 106 - 0
packages/timegrid/src/DayTimeColsView.ts

@@ -0,0 +1,106 @@
+import {
+  DateProfileGenerator, DateProfile,
+  ComponentContext,
+  DayHeader,
+  DaySeries,
+  DayTableModel,
+  memoize,
+  ViewProps,
+  renderer
+} from '@fullcalendar/core'
+import { DayTable } from '@fullcalendar/daygrid'
+import TimeColsView from './TimeColsView'
+import DayTimeCols from './DayTimeCols'
+
+
+export default class DayTimeColsView extends TimeColsView {
+
+  private buildDayTableModel = memoize(buildDayTableModel)
+  private renderDayHeader = renderer(DayHeader)
+  private renderDayTable = renderer(DayTable)
+  private renderDayTimeCols = renderer(DayTimeCols)
+
+  private allDayTable: DayTable
+  private timeCols: DayTimeCols
+
+
+  render(props: ViewProps, context: ComponentContext) {
+    let { dateProfile, dateProfileGenerator } = props
+    let { nextDayThreshold } = context
+    let dayTableModel = this.buildDayTableModel(dateProfile, dateProfileGenerator)
+    let splitProps = this.allDaySplitter.splitProps(props)
+
+    let {
+      rootEl,
+      headerWrapEl,
+      contentWrapEl
+    } = this.renderLayout({ type: props.viewSpec.type }, context)
+
+    this.renderDayHeader(headerWrapEl, { // might be null
+      dateProfile,
+      dates: dayTableModel.headerDates,
+      datesRepDistinctDays: true,
+      renderIntroHtml: this.renderHeadIntroHtml
+    })
+
+    let allDayTable = this.renderDayTable({ parent: contentWrapEl, prepend: true }, { // might be null... TODO: make sure API handles this!!!
+      ...splitProps['allDay'],
+      dateProfile,
+      dayTableModel,
+      nextDayThreshold,
+      isRigid: false,
+      renderProps: this.tableRenderProps
+    })
+
+    let timeCols = this.renderDayTimeCols(contentWrapEl, {
+      ...splitProps['timed'],
+      dateProfile,
+      dayTableModel,
+      renderProps: this.timeColsRenderProps
+    })
+
+    this.startNowIndicator(dateProfile, dateProfileGenerator)
+
+    this.allDayTable = allDayTable
+    this.timeCols = timeCols
+
+    return rootEl
+  }
+
+
+  updateSize(isResize: boolean, viewHeight: number, isAuto: boolean) {
+
+    if (isResize || this.isLayoutSizeDirty()) {
+      this.updateLayoutSize(
+        this.timeCols.timeCols,
+        this.allDayTable ? this.allDayTable.table : null,
+        viewHeight,
+        isAuto
+      )
+    }
+
+    if (this.allDayTable) {
+      this.allDayTable.updateSize(isResize)
+    }
+
+    this.timeCols.updateSize(isResize)
+  }
+
+
+  getAllDayTableObj() {
+    return this.allDayTable
+  }
+
+
+  getTimeColsObj() {
+    return this.timeCols
+  }
+
+}
+
+
+export function buildDayTableModel(dateProfile: DateProfile, dateProfileGenerator: DateProfileGenerator) {
+  let daySeries = new DaySeries(dateProfile.renderRange, dateProfileGenerator)
+
+  return new DayTableModel(daySeries, false)
+}

+ 0 - 138
packages/timegrid/src/SimpleTimeGrid.ts

@@ -1,138 +0,0 @@
-import {
-  DateComponent,
-  DateProfile,
-  EventStore,
-  EventUiHash,
-  EventInteractionState,
-  DateSpan,
-  memoize,
-  intersectRanges, DateRange,
-  DayTable,
-  DateEnv,
-  DateMarker,
-  Slicer,
-  Hit,
-  ComponentContext
-} from '@fullcalendar/core'
-import TimeGrid, { TimeGridSeg } from './TimeGrid'
-
-export interface SimpleTimeGridProps {
-  dateProfile: DateProfile | null
-  dayTable: DayTable
-  businessHours: EventStore
-  eventStore: EventStore
-  eventUiBases: EventUiHash
-  dateSelection: DateSpan | null
-  eventSelection: string
-  eventDrag: EventInteractionState | null
-  eventResize: EventInteractionState | null
-}
-
-export default class SimpleTimeGrid extends DateComponent<SimpleTimeGridProps> {
-
-  timeGrid: TimeGrid
-
-  private buildDayRanges = memoize(buildDayRanges)
-  private dayRanges: DateRange[] // for now indicator
-  private slicer = new TimeGridSlicer()
-
-  constructor(timeGrid: TimeGrid) {
-    super(timeGrid.el)
-
-    this.timeGrid = timeGrid
-  }
-
-  firstContext(context: ComponentContext) {
-    context.calendar.registerInteractiveComponent(this, {
-      el: this.timeGrid.el
-    })
-  }
-
-  destroy() {
-    super.destroy()
-
-    this.context.calendar.unregisterInteractiveComponent(this)
-  }
-
-  render(props: SimpleTimeGridProps, context: ComponentContext) {
-    let { dateEnv } = this.context
-    let { dateProfile, dayTable } = props
-    let dayRanges = this.dayRanges = this.buildDayRanges(dayTable, dateProfile, dateEnv)
-
-    this.timeGrid.receiveProps({
-      ...this.slicer.sliceProps(props, dateProfile, null, context.calendar, this.timeGrid, dayRanges),
-      dateProfile,
-      cells: dayTable.cells[0]
-    }, context)
-  }
-
-  renderNowIndicator(date: DateMarker) {
-    this.timeGrid.renderNowIndicator(
-      this.slicer.sliceNowDate(date, this.timeGrid, this.dayRanges),
-      date
-    )
-  }
-
-  buildPositionCaches() {
-    this.timeGrid.buildPositionCaches()
-  }
-
-  queryHit(positionLeft: number, positionTop: number): Hit {
-    let rawHit = this.timeGrid.positionToHit(positionLeft, positionTop)
-
-    if (rawHit) {
-      return {
-        component: this.timeGrid,
-        dateSpan: rawHit.dateSpan,
-        dayEl: rawHit.dayEl,
-        rect: {
-          left: rawHit.relativeRect.left,
-          right: rawHit.relativeRect.right,
-          top: rawHit.relativeRect.top,
-          bottom: rawHit.relativeRect.bottom
-        },
-        layer: 0
-      }
-    }
-  }
-
-}
-
-
-export function buildDayRanges(dayTable: DayTable, dateProfile: DateProfile, dateEnv: DateEnv): DateRange[] {
-  let ranges: DateRange[] = []
-
-  for (let date of dayTable.headerDates) {
-    ranges.push({
-      start: dateEnv.add(date, dateProfile.minTime),
-      end: dateEnv.add(date, dateProfile.maxTime)
-    })
-  }
-
-  return ranges
-}
-
-
-export class TimeGridSlicer extends Slicer<TimeGridSeg, [DateRange[]]> {
-
-  sliceRange(range: DateRange, dayRanges: DateRange[]): TimeGridSeg[] {
-    let segs: TimeGridSeg[] = []
-
-    for (let col = 0; col < dayRanges.length; col++) {
-      let segRange = intersectRanges(range, dayRanges[col])
-
-      if (segRange) {
-        segs.push({
-          start: segRange.start,
-          end: segRange.end,
-          isStart: segRange.start.valueOf() === range.start.valueOf(),
-          isEnd: segRange.end.valueOf() === range.end.valueOf(),
-          col
-        })
-      }
-    }
-
-    return segs
-  }
-
-}

+ 77 - 71
packages/timegrid/src/TimeGrid.ts → packages/timegrid/src/TimeCols.ts

@@ -18,7 +18,7 @@ import {
   createFormatter,
   createFormatter,
   formatIsoTimeString,
   formatIsoTimeString,
   ComponentContext,
   ComponentContext,
-  DateComponent,
+  Component,
   Seg,
   Seg,
   EventSegUiInteractionState,
   EventSegUiInteractionState,
   DateProfile,
   DateProfile,
@@ -26,10 +26,10 @@ import {
   memoize,
   memoize,
   renderer,
   renderer,
 } from '@fullcalendar/core'
 } from '@fullcalendar/core'
-import { DayBgRow } from '@fullcalendar/daygrid'
-import TimeGridEventRenderer from './TimeGridEventRenderer'
-import TimeGridMirrorRenderer from './TimeGridMirrorRenderer'
-import TimeGridFillRenderer from './TimeGridFillRenderer'
+import { renderDayBgRowHtml } from '@fullcalendar/daygrid'
+import TimeColsEvents from './TimeColsEvents'
+import TimeColsMirrorEvents from './TimeColsMirrorEvents'
+import TimeColsFills from './TimeColsFills'
 
 
 
 
 /* A component that renders one or more columns of vertical time slots
 /* A component that renders one or more columns of vertical time slots
@@ -37,7 +37,7 @@ import TimeGridFillRenderer from './TimeGridFillRenderer'
 
 
 // potential nice values for the slot-duration and interval-duration
 // potential nice values for the slot-duration and interval-duration
 // from largest to smallest
 // from largest to smallest
-const AGENDA_STOCK_SUB_DURATIONS = [
+const STOCK_SUB_DURATIONS = [
   { hours: 1 },
   { hours: 1 },
   { minutes: 30 },
   { minutes: 30 },
   { minutes: 15 },
   { minutes: 15 },
@@ -45,36 +45,47 @@ const AGENDA_STOCK_SUB_DURATIONS = [
   { seconds: 15 }
   { seconds: 15 }
 ]
 ]
 
 
-export interface RenderProps {
+export interface TimeColsRenderProps {
   renderBgIntroHtml: () => string
   renderBgIntroHtml: () => string
   renderIntroHtml: () => string
   renderIntroHtml: () => string
 }
 }
 
 
-export interface TimeGridSeg extends Seg {
+export interface TimeColsSeg extends Seg {
   col: number
   col: number
   start: DateMarker
   start: DateMarker
   end: DateMarker
   end: DateMarker
 }
 }
 
 
-export interface TimeGridCell {
+export interface TimeColsCell {
   date: DateMarker
   date: DateMarker
   htmlAttrs?: string
   htmlAttrs?: string
 }
 }
 
 
-export interface TimeGridProps {
-  renderProps: RenderProps
+export interface TimeColsProps {
+  renderProps: TimeColsRenderProps
   dateProfile: DateProfile
   dateProfile: DateProfile
-  cells: TimeGridCell[]
-  businessHourSegs: TimeGridSeg[]
-  bgEventSegs: TimeGridSeg[]
-  fgEventSegs: TimeGridSeg[]
-  dateSelectionSegs: TimeGridSeg[]
+  cells: TimeColsCell[]
+  businessHourSegs: TimeColsSeg[]
+  bgEventSegs: TimeColsSeg[]
+  fgEventSegs: TimeColsSeg[]
+  dateSelectionSegs: TimeColsSeg[]
   eventSelection: string
   eventSelection: string
   eventDrag: EventSegUiInteractionState | null
   eventDrag: EventSegUiInteractionState | null
   eventResize: EventSegUiInteractionState | null
   eventResize: EventSegUiInteractionState | null
 }
 }
 
 
-export default class TimeGrid extends DateComponent<TimeGridProps> {
+export default class TimeCols extends Component<TimeColsProps> {
+
+  processOptions = memoize(this._processOptions)
+  renderSkeleton = renderer(renderSkeleton)
+  renderSlats = renderer(this._renderSlats)
+  renderBgColumns = renderer(this._renderBgColumns)
+  renderContentSkeleton = renderer(renderContentSkeleton)
+  renderMirrorEvents = renderer(TimeColsMirrorEvents)
+  renderFgEvents = renderer(TimeColsEvents)
+  renderBgEvents = renderer(TimeColsFills)
+  renderBusinessHours = renderer(TimeColsFills)
+  renderDateSelection = renderer(TimeColsFills)
 
 
   // computed options
   // computed options
   slotDuration: Duration // duration of a "slot", a distinct time segment on given day, visualized by lines
   slotDuration: Duration // duration of a "slot", a distinct time segment on given day, visualized by lines
@@ -97,19 +108,7 @@ export default class TimeGrid extends DateComponent<TimeGridProps> {
   contentSkeletonEl: HTMLElement
   contentSkeletonEl: HTMLElement
   colContainerEls: HTMLElement[] // containers for each column
   colContainerEls: HTMLElement[] // containers for each column
 
 
-  processOptions = memoize(this._processOptions)
-  renderSkeleton = renderer(renderSkeleton)
-  renderSlats = renderer(this._renderSlats)
-  renderBgColumns = renderer(this._renderBgColumns)
-  renderDayBgRow = renderer(DayBgRow)
-  renderContentSkeleton = renderer(renderContentSkeleton)
-  renderMirrorEvents = renderer(TimeGridMirrorRenderer)
-  renderFgEvents = renderer(TimeGridEventRenderer)
-  renderBgEvents = renderer(TimeGridFillRenderer)
-  renderBusinessHours = renderer(TimeGridFillRenderer)
-  renderDateSelection = renderer(TimeGridFillRenderer)
-
-  segRenderers: (TimeGridEventRenderer | TimeGridFillRenderer)[]
+  segRenderers: (TimeColsEvents | TimeColsFills | null)[]
 
 
 
 
   /* Options
   /* Options
@@ -162,7 +161,7 @@ export default class TimeGrid extends DateComponent<TimeGridProps> {
   ------------------------------------------------------------------------------------------------------------------*/
   ------------------------------------------------------------------------------------------------------------------*/
 
 
 
 
-  render(props: TimeGridProps, context: ComponentContext) {
+  render(props: TimeColsProps, context: ComponentContext) {
     let { options } = context
     let { options } = context
     this.processOptions(options)
     this.processOptions(options)
 
 
@@ -172,7 +171,7 @@ export default class TimeGrid extends DateComponent<TimeGridProps> {
       contentSkeletonEl,
       contentSkeletonEl,
       bottomRuleEl,
       bottomRuleEl,
       slatContainerEl
       slatContainerEl
-    } = this.renderSkeleton()
+    } = this.renderSkeleton(true)
 
 
     this.renderBgColumns(rootBgContainerEl, {
     this.renderBgColumns(rootBgContainerEl, {
       rootEl,
       rootEl,
@@ -199,35 +198,35 @@ export default class TimeGrid extends DateComponent<TimeGridProps> {
     })
     })
 
 
     let segRenderers = [
     let segRenderers = [
-      this.renderBusinessHours({
+      this.renderBusinessHours(true, {
         type: 'businessHours',
         type: 'businessHours',
         containerEls: businessContainerEls,
         containerEls: businessContainerEls,
         segs: props.businessHourSegs,
         segs: props.businessHourSegs,
       }),
       }),
-      this.renderDateSelection({
+
+      this.renderDateSelection(true, {
         type: 'highlight',
         type: 'highlight',
         containerEls: highlightContainerEls,
         containerEls: highlightContainerEls,
-        segs: options.selectMirror ? null : props.dateSelectionSegs
+        segs: options.selectMirror ? null : props.dateSelectionSegs // do highlight if NO mirror
       }),
       }),
-      this.renderBgEvents({
+
+      this.renderBgEvents(true, {
         type: 'bgEvent',
         type: 'bgEvent',
         containerEls: bgContainerEls,
         containerEls: bgContainerEls,
         segs: props.bgEventSegs
         segs: props.bgEventSegs
       }),
       }),
-      this.renderFgEvents({
+
+      this.renderFgEvents(true, {
         containerEls: fgContainerEls,
         containerEls: fgContainerEls,
         segs: props.fgEventSegs,
         segs: props.fgEventSegs,
-        selectedInstanceId: props.eventSelection, // TODO: rename
+        selectedInstanceId: props.eventSelection,
         hiddenInstances: // TODO: more convenient
         hiddenInstances: // TODO: more convenient
           (props.eventDrag ? props.eventDrag.affectedInstances : null) ||
           (props.eventDrag ? props.eventDrag.affectedInstances : null) ||
           (props.eventResize ? props.eventResize.affectedInstances : null)
           (props.eventResize ? props.eventResize.affectedInstances : null)
-      })
-    ]
+      }),
 
 
-    let mirrorRenderer = this.handleMirror(props, mirrorContainerEls, options)
-    if (mirrorRenderer) {
-      segRenderers.push(mirrorRenderer)
-    }
+      this.handleMirror(props, mirrorContainerEls, options)
+    ]
 
 
     this.segRenderers = segRenderers
     this.segRenderers = segRenderers
     this.contentSkeletonEl = contentSkeletonEl
     this.contentSkeletonEl = contentSkeletonEl
@@ -238,29 +237,29 @@ export default class TimeGrid extends DateComponent<TimeGridProps> {
   }
   }
 
 
 
 
-  handleMirror(props: TimeGridProps, mirrorContainerEls: HTMLElement[], options): TimeGridEventRenderer | null {
-
-    if (props.dateSelectionSegs && options.selectMirror) { // can use non-existent like this!?
-      return this.renderMirrorEvents({
-        containerEls: mirrorContainerEls,
-        segs: props.dateSelectionSegs,
-        mirrorInfo: { isSelecting: true }
-      })
+  handleMirror(props: TimeColsProps, mirrorContainerEls: HTMLElement[], options): TimeColsEvents | null {
 
 
-    } else if (props.eventDrag) {
-      return this.renderMirrorEvents({
+    if (props.eventDrag) {
+      return this.renderMirrorEvents(true, {
         containerEls: mirrorContainerEls,
         containerEls: mirrorContainerEls,
         segs: props.eventDrag.segs,
         segs: props.eventDrag.segs,
         mirrorInfo: { isDragging: true, sourceSeg: props.eventDrag.sourceSeg }
         mirrorInfo: { isDragging: true, sourceSeg: props.eventDrag.sourceSeg }
       })
       })
 
 
     } else if (props.eventResize) {
     } else if (props.eventResize) {
-      return this.renderMirrorEvents({
+      return this.renderMirrorEvents(true, {
         containerEls: mirrorContainerEls,
         containerEls: mirrorContainerEls,
         segs: props.eventResize.segs,
         segs: props.eventResize.segs,
         mirrorInfo: { isDragging: true, sourceSeg: props.eventResize.sourceSeg }
         mirrorInfo: { isDragging: true, sourceSeg: props.eventResize.sourceSeg }
       })
       })
 
 
+    } else if (options.selectMirror) {
+      return this.renderMirrorEvents(true, {
+        containerEls: mirrorContainerEls,
+        segs: props.dateSelectionSegs,
+        mirrorInfo: { isSelecting: true }
+      })
+
     } else {
     } else {
       return this.renderMirrorEvents(false)
       return this.renderMirrorEvents(false)
     }
     }
@@ -281,11 +280,15 @@ export default class TimeGrid extends DateComponent<TimeGridProps> {
     }
     }
 
 
     for (let segRenderer of segRenderers) {
     for (let segRenderer of segRenderers) {
-      segRenderer.computeSizes(isResize, this)
+      if (segRenderer) {
+        segRenderer.computeSizes(isResize, this)
+      }
     }
     }
 
 
     for (let segRenderer of segRenderers) {
     for (let segRenderer of segRenderers) {
-      segRenderer.assignSizes(isResize, this)
+      if (segRenderer) {
+        segRenderer.assignSizes(isResize, this)
+      }
     }
     }
   }
   }
 
 
@@ -359,21 +362,22 @@ export default class TimeGrid extends DateComponent<TimeGridProps> {
 
 
   // goes behind the slats
   // goes behind the slats
   _renderBgColumns(
   _renderBgColumns(
-    { rootEl, cells, dateProfile, renderProps }: { rootEl: HTMLElement, cells: TimeGridCell[], dateProfile: DateProfile, renderProps: any },
+    { rootEl, cells, dateProfile, renderProps }: { rootEl: HTMLElement, cells: TimeColsCell[], dateProfile: DateProfile, renderProps: any },
     context: ComponentContext
     context: ComponentContext
   ) {
   ) {
     let { calendar, view, isRtl, theme, dateEnv } = context
     let { calendar, view, isRtl, theme, dateEnv } = context
 
 
-    let tableEl = createElement('table', { className: theme.getClass('tableGrid') }, '<tbody />')
-    let tbodyEl = tableEl.querySelector('tbody')
-
-    this.renderDayBgRow(tbodyEl, {
-      cells,
-      dateProfile,
-      renderIntroHtml: renderProps.renderBgIntroHtml
-    })
+    let tableEl = createElement(
+      'table',
+      { className: theme.getClass('tableGrid') },
+      renderDayBgRowHtml({
+        cells,
+        dateProfile,
+        renderIntroHtml: renderProps.renderBgIntroHtml
+      }, context)
+    )
 
 
-    let colEls = this.colEls = findElements(tbodyEl, '.fc-day, .fc-disabled-day')
+    let colEls = this.colEls = findElements(tableEl, '.fc-day, .fc-disabled-day')
 
 
     for (let col = 0; col < cells.length; col++) {
     for (let col = 0; col < cells.length; col++) {
       calendar.publiclyTrigger('dayRender', [
       calendar.publiclyTrigger('dayRender', [
@@ -410,7 +414,7 @@ export default class TimeGrid extends DateComponent<TimeGridProps> {
   }
   }
 
 
 
 
-  renderNowIndicator(segs: TimeGridSeg[], date) {
+  renderNowIndicator(segs: TimeColsSeg[], date) {
 
 
     // HACK: if date columns not ready for some reason (scheduler)
     // HACK: if date columns not ready for some reason (scheduler)
     if (!this.colContainerEls) {
     if (!this.colContainerEls) {
@@ -612,8 +616,8 @@ function computeLabelInterval(slotDuration) {
   let slotsPerLabel
   let slotsPerLabel
 
 
   // find the smallest stock label interval that results in more than one slots-per-label
   // find the smallest stock label interval that results in more than one slots-per-label
-  for (i = AGENDA_STOCK_SUB_DURATIONS.length - 1; i >= 0; i--) {
-    labelInterval = createDuration(AGENDA_STOCK_SUB_DURATIONS[i])
+  for (i = STOCK_SUB_DURATIONS.length - 1; i >= 0; i--) {
+    labelInterval = createDuration(STOCK_SUB_DURATIONS[i])
     slotsPerLabel = wholeDivideDurations(labelInterval, slotDuration)
     slotsPerLabel = wholeDivideDurations(labelInterval, slotDuration)
     if (slotsPerLabel !== null && slotsPerLabel > 1) {
     if (slotsPerLabel !== null && slotsPerLabel > 1) {
       return labelInterval
       return labelInterval
@@ -724,10 +728,12 @@ export function attachSegs({ segs, containerEls }: { segs: Seg[], containerEls:
       containerEls[col].appendChild(seg.el)
       containerEls[col].appendChild(seg.el)
     }
     }
   }
   }
+
+  return segs
 }
 }
 
 
 
 
-export function detachSegs({ segs, containerEls }: { segs: Seg[], containerEls: HTMLElement[] }) {
+export function detachSegs(segs: Seg[]) {
   segs.forEach(function(seg) {
   segs.forEach(function(seg) {
     removeElement(seg.el)
     removeElement(seg.el)
   })
   })

+ 10 - 10
packages/timegrid/src/TimeGridEventRenderer.ts → packages/timegrid/src/TimeColsEvents.ts

@@ -6,17 +6,17 @@ import {
   Seg, isMultiDayRange, compareByFieldSpecs,
   Seg, isMultiDayRange, compareByFieldSpecs,
   computeEventDraggable, computeEventStartResizable, computeEventEndResizable, ComponentContext, BaseFgEventRendererProps, renderer
   computeEventDraggable, computeEventStartResizable, computeEventEndResizable, ComponentContext, BaseFgEventRendererProps, renderer
 } from '@fullcalendar/core'
 } from '@fullcalendar/core'
-import TimeGrid, { attachSegs, detachSegs } from './TimeGrid'
+import TimeCols, { attachSegs, detachSegs } from './TimeCols'
 
 
-export interface TimeGridEventRendererProps extends BaseFgEventRendererProps {
+export interface TimeColsEventsProps extends BaseFgEventRendererProps {
   containerEls: HTMLElement[]
   containerEls: HTMLElement[]
 }
 }
 
 
 /*
 /*
 Only handles foreground segs.
 Only handles foreground segs.
-Does not own rendering. Use for low-level util methods by TimeGrid.
+Does not own rendering. Use for low-level util methods by TimeCols.
 */
 */
-export default class TimeGridEventRenderer extends FgEventRenderer<TimeGridEventRendererProps> {
+export default class TimeColsEvents extends FgEventRenderer<TimeColsEventsProps> {
 
 
   attachSegs = renderer(attachSegs, detachSegs)
   attachSegs = renderer(attachSegs, detachSegs)
 
 
@@ -38,7 +38,7 @@ export default class TimeGridEventRenderer extends FgEventRenderer<TimeGridEvent
   }
   }
 
 
 
 
-  render(props: TimeGridEventRendererProps, context: ComponentContext) {
+  render(props: TimeColsEventsProps, context: ComponentContext) {
     let segs = this.renderSegs({
     let segs = this.renderSegs({
       segs: props.segs,
       segs: props.segs,
       mirrorInfo: props.mirrorInfo,
       mirrorInfo: props.mirrorInfo,
@@ -46,14 +46,14 @@ export default class TimeGridEventRenderer extends FgEventRenderer<TimeGridEvent
       hiddenInstances: props.hiddenInstances
       hiddenInstances: props.hiddenInstances
     }, context)
     }, context)
 
 
-    this.segsByCol = this.attachSegs({
+    this.segsByCol = this.attachSegs(true, {
       segs,
       segs,
       containerEls: props.containerEls
       containerEls: props.containerEls
     })
     })
   }
   }
 
 
 
 
-  computeSegSizes(allSegs: Seg[], timeGrid: TimeGrid) {
+  computeSegSizes(allSegs: Seg[], timeGrid: TimeCols) {
     let { segsByCol } = this
     let { segsByCol } = this
     let colCnt = timeGrid.props.cells.length
     let colCnt = timeGrid.props.cells.length
 
 
@@ -65,7 +65,7 @@ export default class TimeGridEventRenderer extends FgEventRenderer<TimeGridEvent
   }
   }
 
 
 
 
-  assignSegSizes(allSegs: Seg[], timeGrid: TimeGrid) {
+  assignSegSizes(allSegs: Seg[], timeGrid: TimeCols) {
     let { segsByCol } = this
     let { segsByCol } = this
     let colCnt = timeGrid.props.cells.length
     let colCnt = timeGrid.props.cells.length
 
 
@@ -79,7 +79,7 @@ export default class TimeGridEventRenderer extends FgEventRenderer<TimeGridEvent
 
 
   // Given foreground event segments that have already had their position coordinates computed,
   // Given foreground event segments that have already had their position coordinates computed,
   // assigns position-related CSS values to their elements.
   // assigns position-related CSS values to their elements.
-  assignSegCss(segs: Seg[], timeGrid: TimeGrid) {
+  assignSegCss(segs: Seg[], timeGrid: TimeCols) {
 
 
     for (let seg of segs) {
     for (let seg of segs) {
       applyStyle(seg.el, this.generateSegCss(seg, timeGrid))
       applyStyle(seg.el, this.generateSegCss(seg, timeGrid))
@@ -99,7 +99,7 @@ export default class TimeGridEventRenderer extends FgEventRenderer<TimeGridEvent
 
 
   // Generates an object with CSS properties/values that should be applied to an event segment element.
   // Generates an object with CSS properties/values that should be applied to an event segment element.
   // Contains important positioning-related properties that should be applied to any event element, customized or not.
   // Contains important positioning-related properties that should be applied to any event element, customized or not.
-  generateSegCss(seg: Seg, timeGrid: TimeGrid) {
+  generateSegCss(seg: Seg, timeGrid: TimeCols) {
     let { isRtl, options } = this.context
     let { isRtl, options } = this.context
     let shouldOverlap = options.slotEventOverlap
     let shouldOverlap = options.slotEventOverlap
     let backwardCoord = seg.backwardCoord // the left side if LTR. the right side if RTL. floating-point
     let backwardCoord = seg.backwardCoord // the left side if LTR. the right side if RTL. floating-point

+ 37 - 0
packages/timegrid/src/TimeColsFills.ts

@@ -0,0 +1,37 @@
+import {
+  FillRenderer, Seg, renderer, BaseFillRendererProps
+} from '@fullcalendar/core'
+import TimeCols, { attachSegs, detachSegs } from './TimeCols'
+
+export interface TimeColsFillsProps extends BaseFillRendererProps {
+  containerEls: HTMLElement[]
+}
+
+export default class TimeColsFills extends FillRenderer<TimeColsFillsProps> {
+
+  private attachSegs = renderer(attachSegs, detachSegs)
+
+
+  render(props: TimeColsFillsProps) {
+    let segs = this.renderSegs(true, {
+      type: props.type,
+      segs: props.segs
+    })
+
+    this.attachSegs(true, {
+      segs,
+      containerEls: props.containerEls
+    })
+  }
+
+
+  computeSegSizes(segs: Seg[], timeGrid: TimeCols) {
+    timeGrid.computeSegVerticals(segs)
+  }
+
+
+  assignSegSizes(segs: Seg[], timeGrid: TimeCols) {
+    timeGrid.assignSegVerticals(segs)
+  }
+
+}

+ 4 - 4
packages/timegrid/src/TimeGridMirrorRenderer.ts → packages/timegrid/src/TimeColsMirrorEvents.ts

@@ -1,12 +1,12 @@
 import { Seg } from '@fullcalendar/core'
 import { Seg } from '@fullcalendar/core'
-import TimeGridEventRenderer from './TimeGridEventRenderer'
-import TimeGrid from './TimeGrid'
+import TimeColsEvents from './TimeColsEvents'
+import TimeCols from './TimeCols'
 
 
 
 
-export default class TimeGridMirrorRenderer extends TimeGridEventRenderer {
+export default class TimeColsMirrorEvents extends TimeColsEvents {
 
 
 
 
-  generateSegCss(seg: Seg, timeGrid: TimeGrid) {
+  generateSegCss(seg: Seg, timeGrid: TimeCols) {
     let cssProps = super.generateSegCss(seg, timeGrid)
     let cssProps = super.generateSegCss(seg, timeGrid)
     let { sourceSeg } = this.props.mirrorInfo
     let { sourceSeg } = this.props.mirrorInfo
 
 

+ 97 - 124
packages/timegrid/src/AbstractTimeGridView.ts → packages/timegrid/src/TimeColsView.ts

@@ -1,119 +1,70 @@
 import {
 import {
-  findElements, createElement, htmlEscape,
+  findElements, htmlEscape,
   matchCellWidths, uncompensateScroll, compensateScroll, subtractInnerElHeight,
   matchCellWidths, uncompensateScroll, compensateScroll, subtractInnerElHeight,
-  ScrollComponent,
+  Scroller,
   View,
   View,
   ComponentContext,
   ComponentContext,
   createFormatter, diffDays,
   createFormatter, diffDays,
-  buildGotoAnchorHtml, getAllDayHtml, Duration, ViewProps,
-  memoizeRendering
+  buildGotoAnchorHtml, getAllDayHtml, Duration,
+  DateMarker,
+  renderViewEl,
+  renderer
 } from '@fullcalendar/core'
 } from '@fullcalendar/core'
-import { DayGrid } from '@fullcalendar/daygrid'
-import TimeGrid from './TimeGrid'
+import { TimeColsRenderProps } from './TimeCols'
+import Table, { TableRenderProps } from 'packages/daygrid/src/Table'
+import { TimeCols } from './main'
 import AllDaySplitter from './AllDaySplitter'
 import AllDaySplitter from './AllDaySplitter'
 
 
-const TIMEGRID_ALL_DAY_EVENT_LIMIT = 5
+const ALL_DAY_EVENT_LIMIT = 5
 const WEEK_HEADER_FORMAT = createFormatter({ week: 'short' })
 const WEEK_HEADER_FORMAT = createFormatter({ week: 'short' })
 
 
 
 
 /* An abstract class for all timegrid-related views. Displays one more columns with time slots running vertically.
 /* An abstract class for all timegrid-related views. Displays one more columns with time slots running vertically.
 ----------------------------------------------------------------------------------------------------------------------*/
 ----------------------------------------------------------------------------------------------------------------------*/
-// Is a manager for the TimeGrid subcomponent and possibly the DayGrid subcomponent (if allDaySlot is on).
+// Is a manager for the TimeCols subcomponent and possibly the DayGrid subcomponent (if allDaySlot is on).
 // Responsible for managing width/height.
 // Responsible for managing width/height.
 
 
-export default abstract class AbstractTimeGridView extends View {
+export default abstract class TimeColsView extends View {
 
 
-  timeGrid: TimeGrid // the main time-grid subcomponent of this view
-  dayGrid: DayGrid // the "all-day" subcomponent. if all-day is turned off, this will be null
+  private renderSkeleton = renderer(this._renderSkeleton)
+  private renderScroller = renderer(Scroller)
 
 
-  scroller: ScrollComponent
-  axisWidth: any // the width of the time axis running down the side
+  protected allDaySplitter = new AllDaySplitter() // for use by subclasses
+  private scroller: Scroller
+  private axisWidth: any // the width of the time axis running down the side
+  private dividerEl: HTMLElement
 
 
-  protected splitter = new AllDaySplitter()
-  private renderSkeleton = memoizeRendering(this._renderSkeleton, this._unrenderSkeleton)
 
 
+  abstract getAllDayTableObj(): { table: Table } | null
 
 
-  render(props: ViewProps, context: ComponentContext) {
-    super.render(props, context)
-
-    this.renderSkeleton(context)
-  }
-
-
-  destroy() {
-    super.destroy()
-
-    this.renderSkeleton.unrender()
-  }
-
-
-  _renderSkeleton(context: ComponentContext) {
-
-    this.el.classList.add('fc-timeGrid-view')
-    this.el.innerHTML = this.renderSkeletonHtml()
-
-    this.scroller = new ScrollComponent(
-      'hidden', // overflow x
-      'auto' // overflow y
-    )
-
-    let timeGridWrapEl = this.scroller.el
-    this.el.querySelector('.fc-body > tr > td').appendChild(timeGridWrapEl)
-    timeGridWrapEl.classList.add('fc-time-grid-container')
-    let timeGridEl = createElement('div', { className: 'fc-time-grid' })
-    timeGridWrapEl.appendChild(timeGridEl)
-
-    this.timeGrid = new TimeGrid(
-      timeGridEl,
-      {
-        renderBgIntroHtml: this.renderTimeGridBgIntroHtml,
-        renderIntroHtml: this.renderTimeGridIntroHtml
-      }
-    )
-
-    if (context.options.allDaySlot) { // should we display the "all-day" area?
-
-      this.dayGrid = new DayGrid( // the all-day subcomponent of this view
-        this.el.querySelector('.fc-day-grid'),
-        {
-          renderNumberIntroHtml: this.renderDayGridIntroHtml, // don't want numbers
-          renderBgIntroHtml: this.renderDayGridBgIntroHtml,
-          renderIntroHtml: this.renderDayGridIntroHtml,
-          colWeekNumbersVisible: false,
-          cellWeekNumbersVisible: false
-        }
-      )
-
-      // have the day-grid extend it's coordinate area over the <hr> dividing the two grids
-      let dividerEl = this.el.querySelector('.fc-divider') as HTMLElement
-      this.dayGrid.bottomCoordPadding = dividerEl.getBoundingClientRect().height
-    }
+  abstract getTimeColsObj(): {
+    timeCols: TimeCols,
+    getNowIndicatorUnit: () => string,
+    renderNowIndicator: (d: DateMarker) => void,
+    unrenderNowIndicator: () => void
   }
   }
 
 
 
 
-  _unrenderSkeleton() {
-    this.el.classList.remove('fc-timeGrid-view')
+  renderLayout(props: { type: string }, context: ComponentContext) {
+    let res = this.renderSkeleton(true, { type: props.type })
 
 
-    this.timeGrid.destroy()
+    let scroller = this.renderScroller(res.contentWrapEl, {
+      overflowX: 'hidden',
+      overflowY: 'auto'
+    })
 
 
-    if (this.dayGrid) {
-      this.dayGrid.destroy()
-    }
+    this.scroller = scroller
 
 
-    this.scroller.destroy()
+    return res
   }
   }
 
 
 
 
-  /* Rendering
-  ------------------------------------------------------------------------------------------------------------------*/
-
-
-  // Builds the HTML skeleton for the view.
-  // The day-grid and time-grid components will render inside containers defined by this HTML.
-  renderSkeletonHtml() {
-    let { theme, options } = this.context
+  _renderSkeleton(props: { type: string }, context: ComponentContext) {
+    let { theme, options } = context
 
 
-    return '' +
+    let el = renderViewEl(props.type)
+    el.classList.add('fc-timeGrid-view')
+    el.innerHTML = '' +
       '<table class="' + theme.getClass('tableGrid') + '">' +
       '<table class="' + theme.getClass('tableGrid') + '">' +
         (options.columnHeader ?
         (options.columnHeader ?
           '<thead class="fc-head">' +
           '<thead class="fc-head">' +
@@ -127,7 +78,6 @@ export default abstract class AbstractTimeGridView extends View {
           '<tr>' +
           '<tr>' +
             '<td class="' + theme.getClass('widgetContent') + '">' +
             '<td class="' + theme.getClass('widgetContent') + '">' +
               (options.allDaySlot ?
               (options.allDaySlot ?
-                '<div class="fc-day-grid"></div>' +
                 '<hr class="fc-divider ' + theme.getClass('widgetHeader') + '" />' :
                 '<hr class="fc-divider ' + theme.getClass('widgetHeader') + '" />' :
                 ''
                 ''
                 ) +
                 ) +
@@ -135,6 +85,23 @@ export default abstract class AbstractTimeGridView extends View {
           '</tr>' +
           '</tr>' +
         '</tbody>' +
         '</tbody>' +
       '</table>'
       '</table>'
+
+    this.dividerEl = options.allDaySlot ? (el.querySelector('.fc-divider') as HTMLElement) : null
+
+    return {
+      rootEl: el,
+      headerWrapEl: options.columnHeader ? (el.querySelector('.fc-head-container') as HTMLElement) : null,
+      contentWrapEl: el.querySelector('.fc-body > tr > td') as HTMLElement
+    }
+  }
+
+
+  componentDidMount() {
+    let allDayTable = this.getAllDayTableObj()
+
+    if (allDayTable) {
+      allDayTable.table.bottomCoordPadding = this.dividerEl.getBoundingClientRect().height
+    }
   }
   }
 
 
 
 
@@ -143,17 +110,17 @@ export default abstract class AbstractTimeGridView extends View {
 
 
 
 
   getNowIndicatorUnit() {
   getNowIndicatorUnit() {
-    return this.timeGrid.getNowIndicatorUnit()
+    return this.getTimeColsObj().getNowIndicatorUnit()
   }
   }
 
 
 
 
-  // subclasses should implement
-  // renderNowIndicator(date: DateMarker) {
-  // }
+  renderNowIndicator(date) {
+    this.getTimeColsObj().renderNowIndicator(date)
+  }
 
 
 
 
   unrenderNowIndicator() {
   unrenderNowIndicator() {
-    this.timeGrid.unrenderNowIndicator()
+    this.getTimeColsObj().unrenderNowIndicator()
   }
   }
 
 
 
 
@@ -161,29 +128,21 @@ export default abstract class AbstractTimeGridView extends View {
   ------------------------------------------------------------------------------------------------------------------*/
   ------------------------------------------------------------------------------------------------------------------*/
 
 
 
 
-  updateSize(isResize: boolean, viewHeight: number, isAuto: boolean) {
-    super.updateSize(isResize, viewHeight, isAuto) // will call updateBaseSize. important that executes first
-
-    this.timeGrid.updateSize(isResize)
-
-    if (this.dayGrid) {
-      this.dayGrid.updateSize(isResize)
-    }
-  }
+  abstract updateSize(isResize: boolean, viewHeight: number, isAuto: boolean)
 
 
 
 
   // Adjusts the vertical dimensions of the view to the specified values
   // Adjusts the vertical dimensions of the view to the specified values
-  updateBaseSize(isResize, viewHeight, isAuto) {
+  updateLayoutSize(timeCols: TimeCols, table: Table | null, viewHeight, isAuto) {
     let eventLimit
     let eventLimit
     let scrollerHeight
     let scrollerHeight
     let scrollbarWidths
     let scrollbarWidths
 
 
     // make all axis cells line up
     // make all axis cells line up
-    this.axisWidth = matchCellWidths(findElements(this.el, '.fc-axis'))
+    this.axisWidth = matchCellWidths(findElements(this.rootEl, '.fc-axis'))
 
 
     // hack to give the view some height prior to timeGrid's columns being rendered
     // hack to give the view some height prior to timeGrid's columns being rendered
     // TODO: separate setting height from scroller VS timeGrid.
     // TODO: separate setting height from scroller VS timeGrid.
-    if (!this.timeGrid.colEls) {
+    if (!timeCols.colEls) {
       if (!isAuto) {
       if (!isAuto) {
         scrollerHeight = this.computeScrollerHeight(viewHeight)
         scrollerHeight = this.computeScrollerHeight(viewHeight)
         this.scroller.setHeight(scrollerHeight)
         this.scroller.setHeight(scrollerHeight)
@@ -192,25 +151,24 @@ export default abstract class AbstractTimeGridView extends View {
     }
     }
 
 
     // set of fake row elements that must compensate when scroller has scrollbars
     // set of fake row elements that must compensate when scroller has scrollbars
-    let noScrollRowEls: HTMLElement[] = findElements(this.el, '.fc-row').filter((node) => {
+    let noScrollRowEls: HTMLElement[] = findElements(this.rootEl, '.fc-row').filter((node) => {
       return !this.scroller.el.contains(node)
       return !this.scroller.el.contains(node)
     })
     })
 
 
     // reset all dimensions back to the original state
     // reset all dimensions back to the original state
-    this.timeGrid.bottomRuleEl.style.display = 'none' // will be shown later if this <hr> is necessary
+    timeCols.bottomRuleEl.style.display = 'none' // will be shown later if this <hr> is necessary
     this.scroller.clear() // sets height to 'auto' and clears overflow
     this.scroller.clear() // sets height to 'auto' and clears overflow
     noScrollRowEls.forEach(uncompensateScroll)
     noScrollRowEls.forEach(uncompensateScroll)
 
 
     // limit number of events in the all-day area
     // limit number of events in the all-day area
-    if (this.dayGrid) {
-      this.dayGrid.removeSegPopover() // kill the "more" popover if displayed
+    if (table) {
 
 
       eventLimit = this.context.options.eventLimit
       eventLimit = this.context.options.eventLimit
       if (eventLimit && typeof eventLimit !== 'number') {
       if (eventLimit && typeof eventLimit !== 'number') {
-        eventLimit = TIMEGRID_ALL_DAY_EVENT_LIMIT // make sure "auto" goes to a real number
+        eventLimit = ALL_DAY_EVENT_LIMIT // make sure "auto" goes to a real number
       }
       }
       if (eventLimit) {
       if (eventLimit) {
-        this.dayGrid.limitRows(eventLimit)
+        table.limitRows(eventLimit)
       }
       }
     }
     }
 
 
@@ -238,8 +196,8 @@ export default abstract class AbstractTimeGridView extends View {
 
 
       // if there's any space below the slats, show the horizontal rule.
       // if there's any space below the slats, show the horizontal rule.
       // this won't cause any new overflow, because lockOverflow already called.
       // this won't cause any new overflow, because lockOverflow already called.
-      if (this.timeGrid.getTotalSlatHeight() < scrollerHeight) {
-        this.timeGrid.bottomRuleEl.style.display = ''
+      if (timeCols.getTotalSlatHeight() < scrollerHeight) {
+        timeCols.bottomRuleEl.style.display = ''
       }
       }
     }
     }
   }
   }
@@ -248,7 +206,7 @@ export default abstract class AbstractTimeGridView extends View {
   // given a desired total height of the view, returns what the height of the scroller should be
   // given a desired total height of the view, returns what the height of the scroller should be
   computeScrollerHeight(viewHeight) {
   computeScrollerHeight(viewHeight) {
     return viewHeight -
     return viewHeight -
-      subtractInnerElHeight(this.el, this.scroller.el) // everything that's NOT the scroller
+      subtractInnerElHeight(this.rootEl, this.scroller.el) // everything that's NOT the scroller
   }
   }
 
 
 
 
@@ -258,7 +216,7 @@ export default abstract class AbstractTimeGridView extends View {
 
 
   // Computes the initial pre-configured scroll state prior to allowing the user to change it
   // Computes the initial pre-configured scroll state prior to allowing the user to change it
   computeDateScroll(duration: Duration) {
   computeDateScroll(duration: Duration) {
-    let top = this.timeGrid.computeTimeTop(duration)
+    let top = this.getTimeColsObj().timeCols.computeTimeTop(duration)
 
 
     // zoom can give weird floating-point values. rather scroll a little bit further
     // zoom can give weird floating-point values. rather scroll a little bit further
     top = Math.ceil(top)
     top = Math.ceil(top)
@@ -272,13 +230,13 @@ export default abstract class AbstractTimeGridView extends View {
 
 
 
 
   queryDateScroll() {
   queryDateScroll() {
-    return { top: this.scroller.getScrollTop() }
+    return { top: this.scroller.controller.getScrollTop() }
   }
   }
 
 
 
 
   applyDateScroll(scroll) {
   applyDateScroll(scroll) {
     if (scroll.top !== undefined) {
     if (scroll.top !== undefined) {
-      this.scroller.setScrollTop(scroll.top)
+      this.scroller.controller.setScrollTop(scroll.top)
     }
     }
   }
   }
 
 
@@ -321,12 +279,12 @@ export default abstract class AbstractTimeGridView extends View {
   }
   }
 
 
 
 
-  /* Time Grid Render Methods
+  /* TimeCols Render Methods
   ------------------------------------------------------------------------------------------------------------------*/
   ------------------------------------------------------------------------------------------------------------------*/
 
 
 
 
-  // Generates the HTML that goes before the bg of the TimeGrid slot area. Long vertical column.
-  renderTimeGridBgIntroHtml = () => {
+  // Generates the HTML that goes before the bg of the TimeCols slot area. Long vertical column.
+  renderTimeColsBgIntroHtml = () => {
     let { theme } = this.context
     let { theme } = this.context
 
 
     return '<td class="fc-axis ' + theme.getClass('widgetContent') + '" ' + this.axisStyleAttr() + '></td>'
     return '<td class="fc-axis ' + theme.getClass('widgetContent') + '" ' + this.axisStyleAttr() + '></td>'
@@ -335,17 +293,23 @@ export default abstract class AbstractTimeGridView extends View {
 
 
   // Generates the HTML that goes before all other types of cells.
   // Generates the HTML that goes before all other types of cells.
   // Affects content-skeleton, mirror-skeleton, highlight-skeleton for both the time-grid and day-grid.
   // Affects content-skeleton, mirror-skeleton, highlight-skeleton for both the time-grid and day-grid.
-  renderTimeGridIntroHtml = () => {
+  renderTimeColsIntroHtml = () => {
     return '<td class="fc-axis" ' + this.axisStyleAttr() + '></td>'
     return '<td class="fc-axis" ' + this.axisStyleAttr() + '></td>'
   }
   }
 
 
 
 
-  /* Day Grid Render Methods
+  timeColsRenderProps: TimeColsRenderProps = {
+    renderBgIntroHtml: this.renderTimeColsBgIntroHtml,
+    renderIntroHtml: this.renderTimeColsIntroHtml
+  }
+
+
+  /* Table Component Render Methods
   ------------------------------------------------------------------------------------------------------------------*/
   ------------------------------------------------------------------------------------------------------------------*/
 
 
 
 
   // Generates the HTML that goes before the all-day cells
   // Generates the HTML that goes before the all-day cells
-  renderDayGridBgIntroHtml = () => {
+  renderTableBgIntroHtml = () => {
     let { theme, options } = this.context
     let { theme, options } = this.context
 
 
     return '' +
     return '' +
@@ -359,10 +323,19 @@ export default abstract class AbstractTimeGridView extends View {
 
 
   // Generates the HTML that goes before all other types of cells.
   // Generates the HTML that goes before all other types of cells.
   // Affects content-skeleton, mirror-skeleton, highlight-skeleton for both the time-grid and day-grid.
   // Affects content-skeleton, mirror-skeleton, highlight-skeleton for both the time-grid and day-grid.
-  renderDayGridIntroHtml = () => {
+  renderTableIntroHtml = () => {
     return '<td class="fc-axis" ' + this.axisStyleAttr() + '></td>'
     return '<td class="fc-axis" ' + this.axisStyleAttr() + '></td>'
   }
   }
 
 
+
+  tableRenderProps: TableRenderProps = {
+    renderNumberIntroHtml: this.renderTableIntroHtml, // don't want numbers
+    renderBgIntroHtml: this.renderTableBgIntroHtml,
+    renderIntroHtml: this.renderTableIntroHtml,
+    colWeekNumbersVisible: false,
+    cellWeekNumbersVisible: false
+  }
+
 }
 }
 
 
-AbstractTimeGridView.prototype.usesMinMaxTime = true // indicates that minTime/maxTime affects rendering
+TimeColsView.prototype.usesMinMaxTime = true // indicates that minTime/maxTime affects rendering

+ 0 - 37
packages/timegrid/src/TimeGridFillRenderer.ts

@@ -1,37 +0,0 @@
-import {
-  FillRenderer, Seg, renderer, BaseFillRendererProps
-} from '@fullcalendar/core'
-import TimeGrid, { attachSegs, detachSegs } from './TimeGrid'
-
-export interface TimeGridFillRendererProps extends BaseFillRendererProps {
-  containerEls: HTMLElement[]
-}
-
-export default class TimeGridFillRenderer extends FillRenderer<TimeGridFillRendererProps> {
-
-  private attachSegs = renderer(attachSegs, detachSegs)
-
-
-  render(props: TimeGridFillRendererProps) {
-    let segs = this.renderSegs({
-      type: props.type,
-      segs: props.segs
-    })
-
-    this.attachSegs({
-      segs,
-      containerEls: props.containerEls
-    })
-  }
-
-
-  computeSegSizes(segs: Seg[], timeGrid: TimeGrid) {
-    timeGrid.computeSegVerticals(segs)
-  }
-
-
-  assignSegSizes(segs: Seg[], timeGrid: TimeGrid) {
-    timeGrid.assignSegVerticals(segs)
-  }
-
-}

+ 0 - 104
packages/timegrid/src/TimeGridView.ts

@@ -1,104 +0,0 @@
-import {
-  DateProfileGenerator, DateProfile,
-  ComponentContext,
-  DayHeader,
-  DaySeries,
-  DayTable,
-  memoize,
-  ViewProps
-} from '@fullcalendar/core'
-import { SimpleDayGrid } from '@fullcalendar/daygrid'
-import SimpleTimeGrid from './SimpleTimeGrid'
-import AbstractTimeGridView from './AbstractTimeGridView'
-
-
-export default class TimeGridView extends AbstractTimeGridView {
-
-  header: DayHeader
-  simpleDayGrid: SimpleDayGrid
-  simpleTimeGrid: SimpleTimeGrid
-
-  private buildDayTable = memoize(buildDayTable)
-
-
-  render(props: ViewProps, context: ComponentContext) {
-    super.render(props, context) // for flags for updateSize. also _renderSkeleton/_unrenderSkeleton
-
-    let { dateProfile, dateProfileGenerator } = this.props
-    let { nextDayThreshold } = context
-    let dayTable = this.buildDayTable(dateProfile, dateProfileGenerator)
-    let splitProps = this.splitter.splitProps(props)
-
-    if (this.header) {
-      this.header.receiveProps({
-        dateProfile,
-        dates: dayTable.headerDates,
-        datesRepDistinctDays: true,
-        renderIntroHtml: this.renderHeadIntroHtml
-      }, context)
-    }
-
-    this.simpleTimeGrid.receiveProps({
-      ...splitProps['timed'],
-      dateProfile,
-      dayTable
-    }, context)
-
-    if (this.simpleDayGrid) {
-      this.simpleDayGrid.receiveProps({
-        ...splitProps['allDay'],
-        dateProfile,
-        dayTable,
-        nextDayThreshold,
-        isRigid: false
-      }, context)
-    }
-
-    this.startNowIndicator(dateProfile, dateProfileGenerator)
-  }
-
-
-  _renderSkeleton(context: ComponentContext) {
-    super._renderSkeleton(context)
-
-    if (context.options.columnHeader) {
-      this.header = new DayHeader(
-        this.el.querySelector('.fc-head-container')
-      )
-    }
-
-    this.simpleTimeGrid = new SimpleTimeGrid(this.timeGrid)
-
-    if (this.dayGrid) {
-      this.simpleDayGrid = new SimpleDayGrid(this.dayGrid)
-    }
-  }
-
-
-  _unrenderSkeleton() {
-    super._unrenderSkeleton()
-
-    if (this.header) {
-      this.header.destroy()
-    }
-
-    this.simpleTimeGrid.destroy()
-
-    if (this.simpleDayGrid) {
-      this.simpleDayGrid.destroy()
-    }
-  }
-
-
-  renderNowIndicator(date) {
-    this.simpleTimeGrid.renderNowIndicator(date)
-  }
-
-}
-
-
-export function buildDayTable(dateProfile: DateProfile, dateProfileGenerator: DateProfileGenerator): DayTable {
-  let daySeries = new DaySeries(dateProfile.renderRange, dateProfileGenerator)
-
-  return new DayTable(daySeries, false)
-}

+ 7 - 7
packages/timegrid/src/main.ts

@@ -1,18 +1,18 @@
 import { createPlugin } from '@fullcalendar/core'
 import { createPlugin } from '@fullcalendar/core'
-import AbstractTimeGridView from './AbstractTimeGridView'
-import TimeGridView, { buildDayTable } from './TimeGridView'
-import { TimeGridSeg } from './TimeGrid'
-import { TimeGridSlicer, buildDayRanges } from './SimpleTimeGrid'
+import TimeColsView from './TimeColsView'
+import DayTimeColsView, { buildDayTableModel } from './DayTimeColsView'
+import { TimeColsSeg, TimeColsRenderProps } from './TimeCols'
+import { DayTimeColsSlicer, buildDayRanges } from './DayTimeCols'
 
 
-export { TimeGridView, AbstractTimeGridView, buildDayTable, buildDayRanges, TimeGridSlicer, TimeGridSeg }
-export { default as TimeGrid } from './TimeGrid'
+export { DayTimeColsView, TimeColsView, buildDayTableModel, buildDayRanges, DayTimeColsSlicer, TimeColsSeg, TimeColsRenderProps }
+export { default as TimeCols } from './TimeCols'
 
 
 export default createPlugin({
 export default createPlugin({
   defaultView: 'timeGridWeek',
   defaultView: 'timeGridWeek',
   views: {
   views: {
 
 
     timeGrid: {
     timeGrid: {
-      class: TimeGridView,
+      class: DayTimeColsView,
       allDaySlot: true,
       allDaySlot: true,
       slotDuration: '00:30:00',
       slotDuration: '00:30:00',
       slotEventOverlap: true // a bad name. confused with overlap/constraint system
       slotEventOverlap: true // a bad name. confused with overlap/constraint system