From 878e0de026c99f79b1a205cec179f35150bbc96c Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 17 Dec 2020 19:08:35 -0500 Subject: [PATCH] make +more popover aware of its resource. fixes #5593 --- packages-premium | 2 +- .../common/src/component/DateComponent.ts | 15 +----- packages/daygrid/src/MorePopover.tsx | 51 +++++++++---------- packages/daygrid/src/Table.tsx | 27 ++++++++-- packages/daygrid/src/TableCell.tsx | 4 ++ packages/daygrid/src/TableRow.tsx | 10 +++- 6 files changed, 63 insertions(+), 46 deletions(-) diff --git a/packages-premium b/packages-premium index 10ee540625..4b7d48be97 160000 --- a/packages-premium +++ b/packages-premium @@ -1 +1 @@ -Subproject commit 10ee5406257b9b8a3968dd55095596e83ae4eccf +Subproject commit 4b7d48be979c875ebe6fe964fcdffab5c7904de6 diff --git a/packages/common/src/component/DateComponent.ts b/packages/common/src/component/DateComponent.ts index 882e94a5d2..f64ebd7a5a 100644 --- a/packages/common/src/component/DateComponent.ts +++ b/packages/common/src/component/DateComponent.ts @@ -94,24 +94,13 @@ export abstract class DateComponent extends isValidSegDownEl(el: HTMLElement) { return !(this.props as any).eventDrag && // HACK !(this.props as any).eventResize && // HACK - !elementClosest(el, '.fc-event-mirror') && - (this.isPopover() || !this.isInPopover(el)) - // ^above line ensures we don't detect a seg interaction within a nested component. - // it's a HACK because it only supports a popover as the nested component. + !elementClosest(el, '.fc-event-mirror') } isValidDateDownEl(el: HTMLElement) { return !elementClosest(el, '.fc-event:not(.fc-bg-event)') && !elementClosest(el, '.fc-daygrid-more-link') && // a "more.." link !elementClosest(el, 'a[data-navlink]') && // a clickable nav link - !this.isInPopover(el) - } - - isPopover() { // HACK. should be overridden by any components that know that they live within a popover - return false - } - - isInPopover(el: HTMLElement) { - return Boolean(elementClosest(el, '.fc-popover')) + !elementClosest(el, '.fc-popover') // hack } } diff --git a/packages/daygrid/src/MorePopover.tsx b/packages/daygrid/src/MorePopover.tsx index 1ee98c847d..907df6eb12 100644 --- a/packages/daygrid/src/MorePopover.tsx +++ b/packages/daygrid/src/MorePopover.tsx @@ -3,13 +3,13 @@ import { DateMarker, createElement, EventInstanceHash, - Hit, addDays, DateRange, getSegMeta, DayCellRoot, DayCellContent, DateProfile, + createRef, } from '@fullcalendar/common' import { TableSeg } from './TableSeg' import { TableBlockEvent } from './TableBlockEvent' @@ -30,7 +30,7 @@ export interface MorePopoverProps { } export class MorePopover extends DateComponent { - private popoverEl: HTMLElement + private rootElRef = createRef() render() { let { options, dateEnv } = this.context @@ -39,7 +39,7 @@ export class MorePopover extends DateComponent { let title = dateEnv.format(date, options.dayPopoverFormat) return ( - + {(rootElRef, dayClassNames, dataAttrs) => ( { ) } - handlePopoverEl = (popoverEl: HTMLElement | null) => { - this.popoverEl = popoverEl + positionToHit(positionLeft: number, positionTop: number, originEl: HTMLElement) { + let rootEl = this.rootElRef.current - if (popoverEl) { - this.context.registerInteractiveComponent(this, { - el: popoverEl, - useEventCenter: false, - }) - } else { - this.context.unregisterInteractiveComponent(this) + if (!originEl || !rootEl) { // why? + return null } - } - queryHit(positionLeft: number, positionTop: number, elWidth: number, elHeight: number): Hit | null { + let originRect = originEl.getBoundingClientRect() + let elRect = rootEl.getBoundingClientRect() + let newOriginLeft = elRect.left - originRect.left + let newOriginTop = elRect.top - originRect.top + let localLeft = positionLeft - newOriginLeft + let localTop = positionTop - newOriginTop let date = this.props.date - if (positionLeft < elWidth && positionTop < elHeight) { + if ( // ugly way to detect intersection + localLeft >= 0 && localLeft < elRect.width && + localTop >= 0 && localTop < elRect.height + ) { return { - component: this, dateSpan: { allDay: true, range: { start: date, end: addDays(date, 1) }, }, - dayEl: this.popoverEl, - rect: { - left: 0, - top: 0, - right: elWidth, - bottom: elHeight, + dayEl: rootEl, + relativeRect: { + left: newOriginLeft, + top: newOriginTop, + right: elRect.width, + bottom: elRect.height, }, - layer: 1, + layer: 1, // important when comparing with hits from other components } } return null } - - isPopover() { - return true // gross - } } diff --git a/packages/daygrid/src/Table.tsx b/packages/daygrid/src/Table.tsx index 713a8c321f..f859403034 100644 --- a/packages/daygrid/src/Table.tsx +++ b/packages/daygrid/src/Table.tsx @@ -17,6 +17,7 @@ import { EventApi, DateProfile, Fragment, + createRef, } from '@fullcalendar/common' import { TableSeg, splitSegsByRow, splitInteractionByRow } from './TableSeg' import { TableRow } from './TableRow' @@ -54,6 +55,8 @@ interface TableState { interface MorePopoverState extends MoreLinkArg { currentFgEventSegs: TableSeg[] + fromRow: number + fromCol: number } export class Table extends DateComponent { @@ -65,11 +68,12 @@ export class Table extends DateComponent { private splitEventResize = memoize(splitInteractionByRow) private buildBuildMoreLinkText = memoize(buildBuildMoreLinkText) private rootEl: HTMLElement + private morePopoverRef = createRef() private rowRefs = new RefMap() private rowPositions: PositionCache private colPositions: PositionCache - state = { + state: TableState = { morePopoverState: null, } @@ -153,7 +157,9 @@ export class Table extends DateComponent { clientWidth={props.clientWidth} clientHeight={props.clientHeight} buildMoreLinkText={buildMoreLinkText} - onMoreClick={this.handleMoreLinkClick} + onMoreClick={(arg) => { + this.handleMoreLinkClick({...arg, fromRow: row}) + }} /> ))} @@ -161,6 +167,7 @@ export class Table extends DateComponent { { // clear popover on event mod (!props.forPrint && morePopoverState && morePopoverState.currentFgEventSegs === props.fgEventSegs) && ( { setRef(this.props.elRef, rootEl) } - handleMoreLinkClick = (arg: MoreLinkArg) => { // TODO: bad names "more link click" versus "more click" + handleMoreLinkClick = (arg: MoreLinkArg & {fromRow: number, fromCol: number}) => { // TODO: bad names "more link click" versus "more click" let { context } = this let { dateEnv } = context let clickOption = context.options.moreLinkClick @@ -222,6 +229,8 @@ export class Table extends DateComponent { morePopoverState: { ...arg, currentFgEventSegs: this.props.fgEventSegs, + fromRow: arg.fromRow, + fromCol: arg.fromCol, }, }) } else if (typeof clickOption === 'string') { // a view name @@ -255,6 +264,18 @@ export class Table extends DateComponent { } positionToHit(leftPosition, topPosition) { + let morePopover = this.morePopoverRef.current + let morePopoverHit = morePopover ? morePopover.positionToHit(leftPosition, topPosition, this.rootEl) : null + let { morePopoverState } = this.state + + if (morePopoverHit) { + return { + row: morePopoverState.fromRow, + col: morePopoverState.fromCol, + ...morePopoverHit, + } + } + let { colPositions, rowPositions } = this let col = colPositions.leftToIndex(leftPosition) let row = rowPositions.topToIndex(topPosition) diff --git a/packages/daygrid/src/TableCell.tsx b/packages/daygrid/src/TableCell.tsx index 4940d64b9f..7529a9d472 100644 --- a/packages/daygrid/src/TableCell.tsx +++ b/packages/daygrid/src/TableCell.tsx @@ -204,6 +204,10 @@ export class TableCell extends DateComponent { } } +TableCell.addPropsEquality({ + onMoreClick: true, // never forces rerender +}) + function renderMoreLinkInner(props) { return props.text } diff --git a/packages/daygrid/src/TableRow.tsx b/packages/daygrid/src/TableRow.tsx index d399929a80..e63e8afc2c 100644 --- a/packages/daygrid/src/TableRow.tsx +++ b/packages/daygrid/src/TableRow.tsx @@ -40,7 +40,7 @@ export interface TableRowProps { dayMaxEventRows: boolean | number clientWidth: number | null clientHeight: number | null // simply for causing an updateSize, for when liquid height - onMoreClick?: (arg: MoreLinkArg) => void + onMoreClick?: (arg: MoreLinkArg & {fromCol: number}) => void dateProfile: DateProfile todayRange: DateRange showDayNumbers: boolean @@ -133,7 +133,9 @@ export class TableRow extends DateComponent { extraClassNames={cell.extraClassNames} moreCnt={moreCnts[col]} buildMoreLinkText={props.buildMoreLinkText} - onMoreClick={props.onMoreClick} + onMoreClick={(arg) => { + props.onMoreClick({...arg, fromCol: col}) + }} segIsHidden={segIsHidden} moreMarginTop={moreTops[col] /* rename */} segsByEachCol={segsByEachCol[col]} @@ -369,6 +371,10 @@ export class TableRow extends DateComponent { } } +TableRow.addPropsEquality({ + onMoreClick: true, // never forces rerender +}) + TableRow.addStateEquality({ segHeights: isPropsEqual, })