Skip to content

Commit

Permalink
feat(allDayMaxRows): Allow for more granular control
Browse files Browse the repository at this point in the history
Allows for more granular control over the number of events display in the all day row
at the top of the TimeGrid
Co-authored-by: Arturo Fornes <arturo.fornes@nextiva.com>

Closes jquense#2386
  • Loading branch information
fornesarturo committed Jun 2, 2023
1 parent 0b27f58 commit 36871bf
Show file tree
Hide file tree
Showing 13 changed files with 369 additions and 16 deletions.
4 changes: 2 additions & 2 deletions src/BackgroundCells.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import clsx from 'clsx'

import { notify } from './utils/helpers'
import { dateCellSelection, getSlotAtX, pointInBox } from './utils/selection'
import Selection, { getBoundsForNode, isEvent } from './Selection'
import Selection, { getBoundsForNode, isEvent, isShowMore } from './Selection'

class BackgroundCells extends React.Component {
constructor(props, context) {
Expand Down Expand Up @@ -77,7 +77,7 @@ class BackgroundCells extends React.Component {
}))

let selectorClicksHandler = (point, actionType) => {
if (!isEvent(node, point)) {
if (!isEvent(node, point) && !isShowMore(node, point)) {
let rowBox = getBoundsForNode(node)
let { range, rtl } = this.props

Expand Down
10 changes: 10 additions & 0 deletions src/Calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,15 @@ class Calendar extends React.Component {
*/
showMultiDayTimes: PropTypes.bool,

/**
* Determines a maximum amount of rows of events to display in the all day
* section for Week and Day views, will display `showMore` button if
* events excede this number.
*
* Defaults to `Infinity`
*/
allDayMaxRows: PropTypes.number,

/**
* Constrains the minimum _time_ of the Day and Week views.
*/
Expand Down Expand Up @@ -865,6 +874,7 @@ class Calendar extends React.Component {
views: [views.MONTH, views.WEEK, views.DAY, views.AGENDA],
step: 30,
length: 30,
allDayMaxRows: Infinity,

doShowMoreDrillDown: true,
drilldownView: views.DAY,
Expand Down
56 changes: 55 additions & 1 deletion src/Day.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import PropTypes from 'prop-types'
import React from 'react'

import { navigate } from './utils/constants'
import { DayLayoutAlgorithmPropType } from './utils/propTypes'

import TimeGrid from './TimeGrid'

class Day extends React.Component {
Expand Down Expand Up @@ -39,11 +41,63 @@ class Day extends React.Component {

Day.propTypes = {
date: PropTypes.instanceOf(Date).isRequired,
localizer: PropTypes.any,

events: PropTypes.array.isRequired,
backgroundEvents: PropTypes.array.isRequired,
resources: PropTypes.array,

step: PropTypes.number,
timeslots: PropTypes.number,
range: PropTypes.arrayOf(PropTypes.instanceOf(Date)),
min: PropTypes.instanceOf(Date),
max: PropTypes.instanceOf(Date),
getNow: PropTypes.func.isRequired,

scrollToTime: PropTypes.instanceOf(Date),
enableAutoScroll: PropTypes.bool,
showMultiDayTimes: PropTypes.bool,

rtl: PropTypes.bool,
resizable: PropTypes.bool,
width: PropTypes.number,

accessors: PropTypes.object.isRequired,
components: PropTypes.object.isRequired,
getters: PropTypes.object.isRequired,
localizer: PropTypes.object.isRequired,

allDayMaxRows: PropTypes.number,

selected: PropTypes.object,
selectable: PropTypes.oneOf([true, false, 'ignoreEvents']),
longPressThreshold: PropTypes.number,

onNavigate: PropTypes.func,
onSelectSlot: PropTypes.func,
onSelectEnd: PropTypes.func,
onSelectStart: PropTypes.func,
onSelectEvent: PropTypes.func,
onDoubleClickEvent: PropTypes.func,
onKeyPressEvent: PropTypes.func,
onShowMore: PropTypes.func,
onDrillDown: PropTypes.func,
getDrilldownView: PropTypes.func.isRequired,

dayLayoutAlgorithm: DayLayoutAlgorithmPropType,

showAllEvents: PropTypes.bool,
doShowMoreDrillDown: PropTypes.bool,

popup: PropTypes.bool,
handleDragStart: PropTypes.func,

popupOffset: PropTypes.oneOfType([
PropTypes.number,
PropTypes.shape({
x: PropTypes.number,
y: PropTypes.number,
}),
]),
}

Day.range = (date, { localizer }) => {
Expand Down
2 changes: 1 addition & 1 deletion src/EventEndingRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class EventEndingRow extends React.Component {
type="button"
key={'sm_' + slot}
className={clsx('rbc-button-link', 'rbc-show-more')}
onClick={e => this.showMore(slot, e)}
onClick={(e) => this.showMore(slot, e)}
>
{localizer.messages.showMore(count)}
</button>
Expand Down
23 changes: 17 additions & 6 deletions src/Selection.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,19 @@ export function getEventNodeFromPoint(node, { clientX, clientY }) {
return closest(target, '.rbc-event', node)
}

export function getShowMoreNodeFromPoint(node, { clientX, clientY }) {
let target = document.elementFromPoint(clientX, clientY)
return closest(target, '.rbc-show-more', node)
}

export function isEvent(node, bounds) {
return !!getEventNodeFromPoint(node, bounds)
}

export function isShowMore(node, bounds) {
return !!getShowMoreNodeFromPoint(node, bounds)
}

function getEventCoordinates(e) {
let target = e

Expand All @@ -38,7 +47,10 @@ const clickTolerance = 5
const clickInterval = 250

class Selection {
constructor(node, { global = false, longPressThreshold = 250, validContainers = [] } = {}) {
constructor(
node,
{ global = false, longPressThreshold = 250, validContainers = [] } = {}
) {
this.isDetached = false
this.container = node
this.globalMouse = !node || global
Expand Down Expand Up @@ -307,15 +319,14 @@ class Selection {
// Check whether provided event target element
// - is contained within a valid container
_isWithinValidContainer(e) {
const eventTarget = e.target;
const containers = this.validContainers;
const eventTarget = e.target
const containers = this.validContainers

if (!containers || !containers.length || !eventTarget) {
return true;
return true
}

return containers.some(
(target) => !!eventTarget.closest(target));
return containers.some((target) => !!eventTarget.closest(target))
}

_handleTerminatingEvent(e) {
Expand Down
116 changes: 112 additions & 4 deletions src/TimeGrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import memoize from 'memoize-one'

import DayColumn from './DayColumn'
import TimeGutter from './TimeGutter'
import TimeGridHeader from './TimeGridHeader'
import PopOverlay from './PopOverlay'

import getWidth from 'dom-helpers/width'
import TimeGridHeader from './TimeGridHeader'
import { notify } from './utils/helpers'
import getPosition from 'dom-helpers/position'
import { views } from './utils/constants'
import { inRange, sortEvents } from './utils/eventLevels'
import { notify } from './utils/helpers'
import Resources from './utils/Resources'
import { DayLayoutAlgorithmPropType } from './utils/propTypes'

Expand All @@ -22,6 +25,7 @@ export default class TimeGrid extends Component {

this.scrollRef = React.createRef()
this.contentRef = React.createRef()
this.containerRef = React.createRef()
this._scrollRatio = null
this.gutterRef = createRef()
}
Expand Down Expand Up @@ -67,12 +71,50 @@ export default class TimeGrid extends Component {
this.applyScroll()
}

handleSelectAlldayEvent = (...args) => {
handleKeyPressEvent = (...args) => {
this.clearSelection()
notify(this.props.onKeyPressEvent, args)
}

handleSelectEvent = (...args) => {
//cancel any pending selections so only the event click goes through.
this.clearSelection()
notify(this.props.onSelectEvent, args)
}

handleDoubleClickEvent = (...args) => {
this.clearSelection()
notify(this.props.onDoubleClickEvent, args)
}

handleShowMore = (events, date, cell, slot, target) => {
const {
popup,
onDrillDown,
onShowMore,
getDrilldownView,
doShowMoreDrillDown,
} = this.props
this.clearSelection()

if (popup) {
let position = getPosition(cell, this.containerRef.current)

this.setState({
overlay: {
date,
events,
position: { ...position, width: '200px' },
target,
},
})
} else if (doShowMoreDrillDown) {
notify(onDrillDown, [date, getDrilldownView(date) || views.DAY])
}

notify(onShowMore, [events, date, slot])
}

handleSelectAllDaySlot = (slots, slotInfo) => {
const { onSelectSlot } = this.props

Expand Down Expand Up @@ -202,6 +244,7 @@ export default class TimeGrid extends Component {
'rbc-time-view',
resources && 'rbc-time-view-resources'
)}
ref={this.containerRef}
>
<TimeGridHeader
range={range}
Expand All @@ -211,6 +254,11 @@ export default class TimeGrid extends Component {
getNow={getNow}
localizer={localizer}
selected={selected}
allDayMaxRows={
this.props.showAllEvents
? Infinity
: this.props.allDayMaxRows ?? Infinity
}
resources={this.memoizedResources(resources, accessors)}
selectable={this.props.selectable}
accessors={accessors}
Expand All @@ -220,13 +268,15 @@ export default class TimeGrid extends Component {
isOverflowing={this.state.isOverflowing}
longPressThreshold={longPressThreshold}
onSelectSlot={this.handleSelectAllDaySlot}
onSelectEvent={this.handleSelectAlldayEvent}
onSelectEvent={this.handleSelectEvent}
onShowMore={this.handleShowMore}
onDoubleClickEvent={this.props.onDoubleClickEvent}
onKeyPressEvent={this.props.onKeyPressEvent}
onDrillDown={this.props.onDrillDown}
getDrilldownView={this.props.getDrilldownView}
resizable={resizable}
/>
{this.props.popup && this.renderOverlay()}
<div
ref={this.contentRef}
className="rbc-time-content"
Expand Down Expand Up @@ -256,6 +306,47 @@ export default class TimeGrid extends Component {
)
}

renderOverlay() {
let overlay = this.state?.overlay ?? {}
let {
accessors,
localizer,
components,
getters,
selected,
popupOffset,
handleDragStart,
} = this.props

const onHide = () => this.setState({ overlay: null })

return (
<PopOverlay
overlay={overlay}
accessors={accessors}
localizer={localizer}
components={components}
getters={getters}
selected={selected}
popupOffset={popupOffset}
ref={this.containerRef}
handleKeyPressEvent={this.handleKeyPressEvent}
handleSelectEvent={this.handleSelectEvent}
handleDoubleClickEvent={this.handleDoubleClickEvent}
handleDragStart={handleDragStart}
show={!!overlay.position}
overlayDisplay={this.overlayDisplay}
onHide={onHide}
/>
)
}

overlayDisplay = () => {
this.setState({
overlay: null,
})
}

clearSelection() {
clearTimeout(this._selectTimer)
this._pendingSelection = []
Expand Down Expand Up @@ -341,6 +432,8 @@ TimeGrid.propTypes = {
getters: PropTypes.object.isRequired,
localizer: PropTypes.object.isRequired,

allDayMaxRows: PropTypes.number,

selected: PropTypes.object,
selectable: PropTypes.oneOf([true, false, 'ignoreEvents']),
longPressThreshold: PropTypes.number,
Expand All @@ -350,12 +443,27 @@ TimeGrid.propTypes = {
onSelectEnd: PropTypes.func,
onSelectStart: PropTypes.func,
onSelectEvent: PropTypes.func,
onShowMore: PropTypes.func,
onDoubleClickEvent: PropTypes.func,
onKeyPressEvent: PropTypes.func,
onDrillDown: PropTypes.func,
getDrilldownView: PropTypes.func.isRequired,

dayLayoutAlgorithm: DayLayoutAlgorithmPropType,

showAllEvents: PropTypes.bool,
doShowMoreDrillDown: PropTypes.bool,

popup: PropTypes.bool,
handleDragStart: PropTypes.func,

popupOffset: PropTypes.oneOfType([
PropTypes.number,
PropTypes.shape({
x: PropTypes.number,
y: PropTypes.number,
}),
]),
}

TimeGrid.defaultProps = {
Expand Down
Loading

0 comments on commit 36871bf

Please sign in to comment.