UNPKG

fullcalendar

Version:

FullCalendar Vanilla JS package for rendering a calendar

1,330 lines 57.4 kB
import { I as isPropsEqualShallow, H as isArraysEqual, K as isPropsEqualWithMap, g as guid, e as createFormatter, A as formatWithOrdinals, L as createAriaClickAttrs, J as computeViewBorderless, u as EventImpl, M as setElEventRange, N as buildEventRangeTimeText, O as getEventTagAndAttrs, P as computeEventRangeDraggable } from './642eba18.js';
import { createContext, Component, createElement, flushSync, isValidElement } from 'preact/compat';
import { b as isNonHandlerPropsEqual } from './28b4e459.js';
import { j as joinClassNames } from './c912f986.js';
import { createDuration, startOfDay, addDays, rangeContainsMarker, joinDateTimeFormatParts } from '@full-ui/headless-calendar';
import { c as classNames } from './3b4e987d.js';
import { jsx, jsxs, Fragment } from 'preact/jsx-runtime';
import { c as computeElIsRtl, E as Emitter } from './9e9ef97a.js';

function memoize(workerFunc, resEquality, teardownFunc) {
    let currentArgs;
    let currentRes;
    return function (...newArgs) {
        if (!currentArgs) {
            currentRes = workerFunc.apply(this, newArgs);
        }
        else if (!isArraysEqual(currentArgs, newArgs)) {
            if (teardownFunc) {
                teardownFunc(currentRes);
            }
            let res = workerFunc.apply(this, newArgs);
            if (!resEquality || !resEquality(res, currentRes)) {
                currentRes = res;
            }
        }
        currentArgs = newArgs;
        return currentRes;
    };
}
function memoizeObjArg(workerFunc, resEquality, teardownFunc) {
    let currentArg;
    let currentRes;
    return (newArg) => {
        if (!currentArg) {
            currentRes = workerFunc.call(this, newArg);
        }
        else if (!isPropsEqualShallow(currentArg, newArg)) {
            if (teardownFunc) {
                teardownFunc(currentRes);
            }
            let res = workerFunc.call(this, newArg);
            if (!resEquality || !resEquality(res, currentRes)) {
                currentRes = res;
            }
        }
        currentArg = newArg;
        return currentRes;
    };
}

const ViewContextType = createContext({}); // for Components
function buildViewContext(viewSpec, viewApi, viewOptions, dateProfileGenerator, dateEnv, nowManager, pluginHooks, dispatch, getCurrentData, emitter, calendarApi, baseId, registerInteractiveComponent, unregisterInteractiveComponent) {
    return {
        dateEnv,
        nowManager,
        options: viewOptions,
        pluginHooks,
        emitter,
        dispatch,
        getCurrentData,
        calendarApi,
        viewSpec,
        viewApi,
        dateProfileGenerator,
        baseId,
        registerInteractiveComponent,
        unregisterInteractiveComponent,
    };
}

/* eslint max-classes-per-file: off */
class PureComponent extends Component {
    // debug: boolean
    shouldComponentUpdate(nextProps, nextState) {
        return !isPropsEqualWithMap(this.props, nextProps, this.propEquality /*, this.debug && 'props' */) ||
            !isPropsEqualWithMap(this.state, nextState, this.stateEquality /*, this.debug && 'state' */);
    }
}
PureComponent.addPropsEquality = addPropsEquality;
PureComponent.addStateEquality = addStateEquality;
PureComponent.contextType = ViewContextType;
PureComponent.prototype.propEquality = {};
PureComponent.prototype.stateEquality = {};
class BaseComponent extends PureComponent {
}
BaseComponent.contextType = ViewContextType;
function addPropsEquality(propEquality) {
    let hash = Object.create(this.prototype.propEquality);
    Object.assign(hash, propEquality);
    this.prototype.propEquality = hash;
}
function addStateEquality(stateEquality) {
    let hash = Object.create(this.prototype.stateEquality);
    Object.assign(hash, stateEquality);
    this.prototype.stateEquality = hash;
}
// use other one
function setRef(ref, current) {
    if (typeof ref === 'function') {
        ref(current);
    }
    else if (ref) {
        // see https://github.com/facebook/react/issues/13029
        ref.current = current;
    }
}

class ContentInjector extends BaseComponent {
    constructor() {
        super(...arguments);
        this.id = guid();
        this.queuedDomNodes = [];
        this.currentDomNodes = [];
        this.handleEl = (el) => {
            this.el = el;
            if (this.props.elRef) {
                setRef(this.props.elRef, el);
            }
        };
    }
    render() {
        const { props, context } = this;
        const { options } = context;
        const { customGenerator, defaultGenerator, renderProps } = props;
        const attrs = buildElAttrs(props, '', this.handleEl);
        let useDefault = false;
        let innerContent;
        let queuedDomNodes = [];
        let currentGeneratorMeta;
        if (customGenerator != null) {
            const customGeneratorRes = typeof customGenerator === 'function' ?
                customGenerator(renderProps) :
                customGenerator;
            if (customGeneratorRes === true) {
                useDefault = true;
                // NOTE: see how mergeContentInjectors also uses `true` to signal useDefault
            }
            else {
                const isObject = customGeneratorRes && typeof customGeneratorRes === 'object'; // non-null
                if (isObject && ('html' in customGeneratorRes)) {
                    attrs.dangerouslySetInnerHTML = { __html: customGeneratorRes.html };
                }
                else if (isObject && ('domNodes' in customGeneratorRes)) {
                    queuedDomNodes = Array.prototype.slice.call(customGeneratorRes.domNodes);
                }
                else if (isObject
                    ? isValidElement(customGeneratorRes) // vdom node
                    : typeof customGeneratorRes !== 'function' // primitive value (like string or number)
                ) {
                    // use in vdom
                    innerContent = customGeneratorRes;
                }
                else {
                    // an exotic object for handleCustomRendering
                    currentGeneratorMeta = customGeneratorRes;
                }
            }
        }
        else {
            useDefault = !hasCustomRenderingHandler(props.generatorName, options);
        }
        if (useDefault && defaultGenerator) {
            innerContent = defaultGenerator(renderProps);
        }
        this.queuedDomNodes = queuedDomNodes;
        this.currentGeneratorMeta = currentGeneratorMeta;
        return createElement(props.tag, attrs, innerContent);
    }
    componentDidMount() {
        this.applyQueueudDomNodes();
        this.triggerCustomRendering(true);
    }
    componentDidUpdate() {
        this.applyQueueudDomNodes();
        this.triggerCustomRendering(true);
    }
    componentWillUnmount() {
        this.triggerCustomRendering(false); // TODO: different API for removal?
    }
    triggerCustomRendering(isActive) {
        const { props, context } = this;
        const { handleCustomRendering, customRenderingMetaMap } = context.options;
        if (handleCustomRendering) {
            const generatorMeta = this.currentGeneratorMeta ??
                customRenderingMetaMap?.[props.generatorName];
            if (generatorMeta) {
                handleCustomRendering({
                    id: this.id,
                    isActive,
                    containerEl: this.el,
                    generatorMeta,
                    renderProps: props.renderProps,
                });
            }
        }
    }
    applyQueueudDomNodes() {
        const { queuedDomNodes, currentDomNodes } = this;
        const { el } = this;
        if (!isArraysEqual(queuedDomNodes, currentDomNodes)) {
            for (const domNode of currentDomNodes) {
                domNode.remove();
            }
            for (let newNode of queuedDomNodes) {
                el.appendChild(newNode);
            }
            this.currentDomNodes = queuedDomNodes;
        }
    }
}
ContentInjector.addPropsEquality({
    renderProps: isPropsEqualShallow,
    attrs: isNonHandlerPropsEqual,
    style: isPropsEqualShallow,
});
// Util
/*
Does UI-framework provide custom way of rendering that does not use Preact VDOM
AND does the calendar's options define custom rendering?
AKA. Should we NOT render the default content?
*/
function hasCustomRenderingHandler(generatorName, options) {
    return Boolean(options.handleCustomRendering &&
        generatorName &&
        options.customRenderingMetaMap?.[generatorName]);
}
function buildElAttrs(props, className, elRef) {
    const attrs = { ...props.attrs, ref: elRef };
    if (props.className || className) {
        attrs.className = joinClassNames(className, props.className, attrs.className);
    }
    if (props.style) {
        attrs.style = props.style;
    }
    return attrs;
}

const RenderId = createContext(0);

class ContentContainer extends Component {
    constructor() {
        super(...arguments);
        this.InnerContent = InnerContentInjector.bind(undefined, this);
        this.handleEl = (el) => {
            this.el = el;
            if (this.props.elRef) {
                setRef(this.props.elRef, el);
                if (el && this.didMountMisfire) {
                    this.componentDidMount();
                }
            }
        };
    }
    render() {
        const { props } = this;
        const generatedClassName = generateClassName(props.classNameGenerator, props.renderProps);
        if (props.children) {
            const attrs = buildElAttrs(props, generatedClassName, this.handleEl);
            const children = props.children(this.InnerContent, props.renderProps, attrs);
            if (props.tag) {
                return createElement(props.tag, attrs, children);
            }
            else {
                return children;
            }
        }
        else {
            return createElement((ContentInjector), {
                ...props,
                elRef: this.handleEl,
                tag: props.tag || 'div',
                className: joinClassNames(props.className, generatedClassName),
                renderId: this.context,
            });
        }
    }
    componentDidMount() {
        if (this.el) {
            this.props.didMount?.({
                ...this.props.renderProps,
                el: this.el,
            });
        }
        else {
            this.didMountMisfire = true;
        }
    }
    componentWillUnmount() {
        this.props.willUnmount?.({
            ...this.props.renderProps,
            el: this.el,
        });
    }
}
ContentContainer.contextType = RenderId;
function InnerContentInjector(containerComponent, props) {
    const parentProps = containerComponent.props;
    return createElement((ContentInjector), {
        renderProps: parentProps.renderProps,
        generatorName: parentProps.generatorName,
        customGenerator: parentProps.customGenerator,
        defaultGenerator: parentProps.defaultGenerator,
        renderId: containerComponent.context,
        ...props,
    });
}
// Utils
function generateClassName(classNameGenerator, renderProps) {
    return (typeof classNameGenerator === 'function' ?
        classNameGenerator(renderProps) :
        classNameGenerator) || ''; // handles undefined
}
function renderText(renderProps) {
    return renderProps.text;
}

function getIsHeightAuto(options) {
    return options.height === 'auto' || options.contentHeight === 'auto';
}
function getTableHeaderSticky(options) {
    let { tableHeaderSticky } = options;
    if (tableHeaderSticky == null || tableHeaderSticky === 'auto') {
        tableHeaderSticky = getIsHeightAuto(options);
    }
    return tableHeaderSticky;
}
function getFooterScrollbarSticky(options) {
    const isHeightAuto = getIsHeightAuto(options);
    let { footerScrollbarSticky } = options;
    if (footerScrollbarSticky == null || footerScrollbarSticky === 'auto') {
        footerScrollbarSticky = isHeightAuto;
    }
    return Boolean(footerScrollbarSticky) && isHeightAuto;
}
function getScrollerSyncerClass(pluginHooks) {
    const ScrollerSyncer = pluginHooks.scrollerSyncerClass;
    if (!ScrollerSyncer) {
        throw new RangeError('Must import @fullcalendar/scrollgrid');
    }
    return ScrollerSyncer;
}

class NowTimerRunner {
    constructor(handleChange) {
        this.handleChange = handleChange;
        this.isMounted = false;
        this.handleRefresh = () => {
            let timing = this.computeTiming();
            if (timing.nowDate.valueOf() !== this.nowDate.valueOf() ||
                timing.nowMs !== this.nowMs // marker alone can't detect fold-hour changes
            ) {
                this.nowDate = timing.nowDate;
                this.nowMs = timing.nowMs;
                this.todayRange = timing.todayRange;
                this.handleChange();
            }
            this.clearTimeout();
            this.setTimeout(timing.waitMs);
        };
        this.handleVisibilityChange = () => {
            if (!document.hidden) {
                this.handleRefresh();
            }
        };
    }
    update(input) {
        if (!this.isMounted) {
            this.isMounted = true;
            // init inputs
            this.unit = input.unit;
            this.unitValue = input.unitValue;
            this.nowIndicatorSnap = input.nowIndicatorSnap;
            this.nowManager = input.nowManager;
            this.dateEnv = input.dateEnv;
            // init outputs
            const timing = this.computeTiming();
            this.nowDate = timing.nowDate;
            this.nowMs = timing.nowMs;
            this.todayRange = timing.todayRange;
            // init listeners
            this.setTimeout(timing.waitMs);
            this.nowManager.addResetListener(this.handleRefresh);
            // fired tab becomes visible after being hidden
            // SSR check. CalendarDataManager calls top-level sync :(
            if (typeof document !== 'undefined') {
                document.addEventListener('visibilitychange', this.handleVisibilityChange);
            }
        }
        else if (input.unit !== this.unit ||
            input.unitValue !== this.unitValue ||
            input.nowIndicatorSnap !== this.nowIndicatorSnap ||
            input.nowManager !== this.nowManager ||
            input.dateEnv !== this.dateEnv) {
            // update inputs
            this.unit = input.unit;
            this.unitValue = input.unitValue;
            this.nowIndicatorSnap = input.nowIndicatorSnap;
            this.nowManager = input.nowManager;
            this.dateEnv = input.dateEnv;
            // recompute outputs — a dateEnv (timezone) change re-projects the same exact "now"
            // to a different civil time. (the nowManager reset listener can't do this: it fires
            // before this runner receives the new dateEnv, so it recomputes with the old one)
            const timing = this.computeTiming();
            this.nowDate = timing.nowDate;
            this.nowMs = timing.nowMs;
            this.todayRange = timing.todayRange;
            this.clearTimeout();
            this.setTimeout(timing.waitMs);
        }
        return {
            nowDate: this.nowDate,
            nowMs: this.nowMs,
            todayRange: this.todayRange,
        };
    }
    destroy() {
        if (this.isMounted) {
            this.isMounted = false;
            this.clearTimeout();
            this.nowManager.removeResetListener(this.handleRefresh);
            // SSR check. CalendarDataManager calls top-level sync :(
            if (typeof document !== 'undefined') {
                document.removeEventListener('visibilitychange', this.handleVisibilityChange);
            }
        }
    }
    computeTiming() {
        let { unit, unitValue, nowIndicatorSnap, dateEnv } = this;
        let unroundedNowMs = this.nowManager.getEpochMs();
        let unroundedNow = dateEnv.timestampToMarker(unroundedNowMs);
        if (nowIndicatorSnap === 'auto') {
            nowIndicatorSnap =
                // large unit?
                /year|month|week|day/.test(unit) ||
                    // if slotDuration 30 mins for example, would NOT appear to snap (legacy behavior)
                    (unitValue || 1) === 1;
        }
        let nowDate;
        let nowMs;
        let waitMs;
        if (nowIndicatorSnap) {
            nowDate = dateEnv.startOf(unroundedNow, unit); // aka currentUnitStart
            nowMs = resolveSnappedInstant(nowDate, unroundedNowMs, dateEnv);
            let nextUnitStart = dateEnv.add(nowDate, createDuration(1, unit));
            waitMs = resolveNextSnappedInstant(nextUnitStart, unroundedNowMs, dateEnv) - unroundedNowMs;
        }
        else {
            nowDate = unroundedNow;
            nowMs = unroundedNowMs;
            waitMs = 1000 * 60; // 1 minute
        }
        // there is a max setTimeout ms value (https://stackoverflow.com/a/3468650/96342)
        // ensure no longer than a day
        waitMs = Math.min(1000 * 60 * 60 * 24, waitMs);
        return {
            nowDate,
            nowMs,
            todayRange: buildDayRange(nowDate),
            waitMs,
        };
    }
    setTimeout(waitMs = this.computeTiming().waitMs) {
        // NOTE: timeout could take longer than expected if tab sleeps,
        // which is why we listen to 'visibilitychange'
        this.timeoutId = setTimeout(() => {
            // NOTE: timeout could also return *earlier* than expected, and we need to wait like 2 ms more
            // This is why use use same waitMs from computeTiming
            const timing = this.computeTiming();
            this.nowDate = timing.nowDate;
            this.nowMs = timing.nowMs;
            this.todayRange = timing.todayRange;
            this.handleChange();
            this.setTimeout(timing.waitMs);
        }, waitMs);
    }
    clearTimeout() {
        if (this.timeoutId) {
            clearTimeout(this.timeoutId);
        }
    }
}
/*
The instant of `snappedMarker` (a civil rounding of the time at `rawMs`), choosing the
occurrence on the same side of any DST transition as `rawMs` — during a fall-back fold, a
snapped civil time exists twice. Falls back to deterministic first-occurrence resolution
when the same-offset guess doesn't round-trip (e.g. snapping crossed the transition).
*/
function resolveSnappedInstant(snappedMarker, rawMs, dateEnv) {
    const offsetMs = dateEnv.timestampToMarker(rawMs).valueOf() - rawMs;
    const candidateMs = snappedMarker.valueOf() - offsetMs;
    if (dateEnv.timestampToMarker(candidateMs).valueOf() === snappedMarker.valueOf()) {
        return candidateMs;
    }
    return dateEnv.toDate(snappedMarker).valueOf();
}
/*
The instant of the next change to the snapped display: the next civil unit boundary, or any
DST transition before it — at a fall-back transition the clock jumps backward onto an earlier
unit start (no civil boundary is crossed), and waking there recomputes with fresh offsets, so
boundaries beyond a transition never need resolving here. Scenarios (NY fall-back, hour unit):
first fold pass (05:30Z): guess for 02:00 fails round-trip → falls back to 07:00Z; transition
06:00Z wins. Second pass (06:30Z): guess 07:00Z round-trips; no transition ahead. Spring
forward: the nonexistent next unit normalizes past the gap; the transition candidate fires at
the jump itself.
*/
function resolveNextSnappedInstant(nextUnitStart, rawMs, dateEnv) {
    const nextSnappedMs = resolveSnappedInstant(nextUnitStart, rawMs, dateEnv);
    const transitionMs = findNextOffsetTransitionMs(rawMs, dateEnv, Math.min(nextSnappedMs - rawMs, 48 * 60 * 60 * 1000));
    return transitionMs != null ? Math.min(nextSnappedMs, transitionMs) : nextSnappedMs;
}
// Finds the first instant whose UTC offset differs from rawMs within a short search horizon.
function findNextOffsetTransitionMs(rawMs, dateEnv, horizonMs) {
    if (horizonMs <= 0) {
        return undefined;
    }
    const startOffsetMs = offsetAt(rawMs, dateEnv);
    let lowerMs = rawMs;
    let upperMs = rawMs + horizonMs;
    if (offsetAt(upperMs, dateEnv) === startOffsetMs) {
        return undefined;
    }
    while (upperMs - lowerMs > 1) {
        const middleMs = Math.floor((lowerMs + upperMs) / 2);
        if (offsetAt(middleMs, dateEnv) === startOffsetMs) {
            lowerMs = middleMs;
        }
        else {
            upperMs = middleMs;
        }
    }
    return upperMs > rawMs ? upperMs : undefined;
}
function offsetAt(instantMs, dateEnv) {
    return dateEnv.timestampToMarker(instantMs).valueOf() - instantMs;
}
function buildDayRange(date) {
    let start = startOfDay(date);
    let end = addDays(start, 1);
    return { start, end };
}

function isDimsEqual(v0, v1) {
    return v0 != null && (v0 === v1 || Math.abs(v0 - v1) < 0.01);
}

const nativeBorderBoxEnabled = true;
const configMap = new Map();
const afterSizeCallbacks = new Set();
let isHandling = false;
let isStalling = false;
let isAcquiringImmediately = false;
function afterSize(callback) {
    afterSizeCallbacks.add(callback);
    // batch & then flush when not within ResizeObserver handler loop
    // happens for watchers that die and report `null` as dimension
    if (!isHandling && !isStalling) {
        isStalling = true;
        requestAnimationFrame(() => {
            isStalling = false;
            flushAfterSize();
        });
    }
}
function flushAfterSize() {
    for (const flushedCallback of afterSizeCallbacks.values()) {
        afterSizeCallbacks.delete(flushedCallback);
        flushedCallback();
    }
}
/*
Commits synchronously while switching every watcher registered during the
commit to immediate acquisition: registration reads getBoundingClientRect()
on the spot and fires the callback before returning, instead of waiting for
the shared ResizeObserver's later delivery. This is the "measure now" path
required when print-only DOM mounts during the native beforeprint task —
observer delivery would arrive after the browser has already snapshotted.
(gBCR reflects transforms while the observer's border-box does not; for
print DOM that distinction is acceptable. Once components go functional, a
`useElementSize`-style hook performs this same acquire-then-observe.)

The afterSize work those callbacks (and any watcher deaths) queue
accumulates and drains ONCE after the commit, not once per registration —
so a commit mounting N measured wrappers costs one layout recomputation,
not N. The drain runs in its own flushSync so handler state updates still
settle within the calling task; additions made while draining are picked up
by the same loop. Preact flushes mount lifecycles after the root diff, so
the reads don't interleave with the commit's DOM writes.

Adopt this bracket a la carte, only for commits whose entire mounted-watcher
population tolerates a synchronous first report (currently: entering print
mode). Ordinary watchSize callers everywhere else keep their async-first
ResizeObserver semantics.
*/
function flushSyncWithSizeBatching(callback) {
    const wasHandling = isHandling;
    isHandling = true;
    isAcquiringImmediately = true;
    try {
        flushSync(callback);
        if (!wasHandling) {
            flushSync(() => {
                flushAfterSize();
                isHandling = false; // before drain's own commit, so late afterSize calls schedule a flush
            });
        }
    }
    finally {
        isHandling = wasHandling;
        isAcquiringImmediately = false;
    }
}
// Native
// -------------------------------------------------------------------------------------------------
// Single global ResizeObserver does batching and uses less memory than individuals
// Will always fire with delay after DOM mutation, but before repaint,
// thus doesn't need !isHandling check like checkConfigMap
const globalResizeObserver = typeof ResizeObserver !== 'undefined' && new ResizeObserver((entries) => {
    isHandling = true;
    // // debug
    // console.log('RESIZE-OBSERVER', entries.map((entry) => entry.target))
    for (let entry of entries) {
        const el = entry.target;
        const config = configMap.get(el);
        let width;
        let height;
        if (entry.borderBoxSize && nativeBorderBoxEnabled) {
            const borderBoxSize = entry.borderBoxSize[0] || entry.borderBoxSize; // HACK for Firefox
            width = borderBoxSize.inlineSize;
            height = borderBoxSize.blockSize;
        }
        else {
            ({ width, height } = el.getBoundingClientRect());
        }
        let shouldFire = false;
        if (!isDimsEqual(config.width, width)) {
            config.width = width;
            shouldFire = config.watchWidth;
        }
        if (!isDimsEqual(config.height, height)) {
            config.height = height;
            shouldFire || (shouldFire = config.watchHeight);
        }
        if (shouldFire) {
            config.callback(width, height);
        }
    }
    flushSync(() => {
        flushAfterSize();
        isHandling = false;
    });
});
/*
PRECONDITION: element can only have one listener attached
*/
function watchSize(el, callback, watchWidth = true, watchHeight = true) {
    const config = { callback, watchWidth, watchHeight };
    configMap.set(el, config);
    // within a flushSyncWithSizeBatching commit; see its comment.
    // the stored dims dedupe the observer's later initial delivery.
    if (isAcquiringImmediately) {
        const { width, height } = el.getBoundingClientRect();
        config.width = width;
        config.height = height;
        callback(width, height);
    }
    // if statement is for jsdom and other shim environments that execute component effects, but
    // haven't implemented ResizeObserver. Reference: https://github.com/jsdom/jsdom/issues/3368
    if (globalResizeObserver) {
        globalResizeObserver.observe(el, {
            box: 'border-box'
                 // default is 'content-box'
        });
    }
    return () => {
        configMap.delete(el);
        // same reasoning as above
        if (globalResizeObserver) {
            globalResizeObserver.unobserve(el);
        }
    };
}
function watchWidth(el, callback) {
    return watchSize(el, callback, 
    /* watchWidth = */ true);
}
function watchHeight(el, callback) {
    return watchSize(el, (_width, height) => callback(height), 
    /* watchWidth = */ false, 
    /* watchHeight = */ true);
}

class NowTimer extends Component {
    constructor(props, context) {
        super(props, context);
        this.handleChange = () => {
            this.forceUpdate();
        };
        this.runner = new NowTimerRunner(this.handleChange);
    }
    render() {
        const { props, context } = this;
        const { nowDate, nowMs, todayRange } = this.runner.update({
            nowManager: context.nowManager,
            unit: props.unit,
            unitValue: props.unitValue,
            nowIndicatorSnap: context.options.nowIndicatorSnap,
            dateEnv: context.dateEnv,
        });
        return props.children(nowDate, todayRange, nowMs);
    }
    componentWillUnmount() {
        this.runner.destroy();
    }
}
NowTimer.contextType = ViewContextType;

const FULL_DATE_FORMAT = createFormatter({ year: 'numeric', month: 'long', day: 'numeric' });
const WEEK_FORMAT = createFormatter({ week: 'long' });
const WEEKDAY_ONLY_FORMAT = createFormatter({
    weekday: 'long',
});
function findWeekdayText(parts) {
    for (const part of parts) {
        if (part.type === 'weekday') {
            return part.value;
        }
    }
    return '';
}
function findDayNumberText(parts) {
    for (const part of parts) {
        if (part.type === 'day') {
            return part.value;
        }
    }
    return '';
}
function findMonthText(parts) {
    for (const part of parts) {
        if (part.type === 'month') {
            return part.value;
        }
    }
    return '';
}

/*
TODO: just have this return the string?
*/
function buildDateStr(context, dateMarker, viewType = 'day') {
    return joinDateTimeFormatParts(context.dateEnv.formatToParts(dateMarker, viewType === 'week' ? WEEK_FORMAT : FULL_DATE_FORMAT));
}
/*
Assumes navLinks enabled
Always hidden to screen readers. Do not point aria-labelledby at this. Use aria-label instead.
*/
function buildNavLinkAttrs(context, dateMarker, viewType = 'day', dateStr = buildDateStr(context, dateMarker, viewType), isTabbable = true) {
    const { dateEnv, options, calendarApi } = context;
    const zonedDate = dateEnv.toDate(dateMarker);
    const handleInteraction = (ev) => {
        let customAction = viewType === 'day' ? options.navLinkDayClick :
            viewType === 'week' ? options.navLinkWeekClick : null;
        if (typeof customAction === 'function') {
            customAction.call(calendarApi, dateEnv.toDate(dateMarker), ev);
        }
        else {
            if (typeof customAction === 'string') {
                viewType = customAction;
            }
            calendarApi.zoomTo(dateMarker, viewType);
        }
    };
    return {
        'role': 'link', // TODO
        'aria-label': formatWithOrdinals(options.navLinkHint, [dateStr, zonedDate], dateStr),
        'className': joinClassNames(options.navLinkClass, classNames.cursorPointer, classNames.internalNavLink),
        ...(isTabbable
            ? createAriaClickAttrs(handleInteraction)
            : { onClick: handleInteraction }),
    };
}

function getDateMeta(dateMarker, dateEnv, dateProfile, todayRange, nowDate) {
    const isDisabled = Boolean(dateProfile && (!dateProfile.activeRange || !rangeContainsMarker(dateProfile.activeRange, dateMarker)));
    return {
        date: dateEnv.toDate(dateMarker),
        dow: dateMarker.getUTCDay(),
        isDisabled,
        isOther: !isDisabled && Boolean(dateProfile && !rangeContainsMarker(dateProfile.currentRange, dateMarker)),
        isToday: !isDisabled && Boolean(todayRange && rangeContainsMarker(todayRange, dateMarker)),
        isPast: !isDisabled && Boolean(nowDate ? (dateMarker < nowDate) : todayRange ? (dateMarker < todayRange.start) : false),
        isFuture: !isDisabled && Boolean(nowDate ? (dateMarker > nowDate) : todayRange ? (dateMarker >= todayRange.end) : false),
    };
}

class ViewContainer extends BaseComponent {
    constructor() {
        super(...arguments);
        this.refineRenderProps = memoizeObjArg(refineRenderProps);
    }
    render() {
        const { props, context } = this;
        const { options, viewSpec } = context;
        const renderProps = this.refineRenderProps({
            ...computeViewBorderless(options),
            options: { headerToolbar: options.headerToolbar, footerToolbar: options.footerToolbar },
            isHeightAuto: getIsHeightAuto(options),
            viewApi: context.viewApi,
        });
        return (jsx(ContentContainer, { elRef: props.elRef, tag: props.tag || 'div', attrs: props.attrs, style: props.style, className: joinClassNames(props.className, generateClassName(options.viewClass, renderProps), 
            // WORKAROUND for way calendar's className would get merged into view's className
            generateClassName(viewSpec.optionDefaults.class, renderProps), generateClassName(viewSpec.optionDefaults.className, renderProps), generateClassName(viewSpec.optionOverrides.class, renderProps), generateClassName(viewSpec.optionOverrides.className, renderProps)), renderProps: renderProps, generatorName: undefined, didMount: options.didMount || options.viewDidMount, willUnmount: options.willUnmount || options.viewWillUnmount, children: () => props.children }));
    }
}
function refineRenderProps(raw) {
    return {
        view: raw.viewApi,
        borderlessX: raw.borderlessX,
        borderlessTop: raw.borderlessTop,
        borderlessBottom: raw.borderlessBottom,
        options: raw.options,
        isHeightAuto: raw.isHeightAuto,
    };
}

/*
an INTERACTABLE date component

PURPOSES:
- hook up to fg, fill, and mirror renderers
- interface for dragging and hits
*/
class DateComponent extends BaseComponent {
    constructor() {
        super(...arguments);
        this.uid = guid();
    }
    // Hit System
    // -----------------------------------------------------------------------------------------------------------------
    prepareHits() {
    }
    queryHit(isRtl, positionLeft, positionTop, elWidth, elHeight) {
        return null; // this should be abstract
    }
    // Pointer Interaction Utils
    // -----------------------------------------------------------------------------------------------------------------
    isValidSegDownEl(el) {
        return !this.props.eventDrag && // HACK
            !this.props.eventResize && // HACK
            !el.closest(`.${classNames.internalEventMirror}`);
    }
    isValidDateDownEl(el) {
        return !el.closest(`.${classNames.internalEvent}:not(.${classNames.internalBgEvent})`) &&
            !el.closest(`.${classNames.internalMoreLink}`) &&
            !el.closest(`.${classNames.internalNavLink}`) &&
            !el.closest(`.${classNames.internalPopover}`); // hack
    }
}

class DelayedRunner {
    constructor(drainedOption) {
        this.drainedOption = drainedOption;
        this.isRunning = false;
        this.isDirty = false;
        this.pauseDepths = {};
        this.timeoutId = 0;
    }
    request(delay) {
        this.isDirty = true;
        if (!this.isPaused()) {
            this.clearTimeout();
            if (delay == null) {
                this.tryDrain();
            }
            else {
                this.timeoutId = setTimeout(// NOT OPTIMAL! TODO: look at debounce
                this.tryDrain.bind(this), delay);
            }
        }
    }
    pause(scope = '') {
        let { pauseDepths } = this;
        pauseDepths[scope] = (pauseDepths[scope] || 0) + 1;
        this.clearTimeout();
    }
    resume(scope = '', force) {
        let { pauseDepths } = this;
        if (scope in pauseDepths) {
            if (force) {
                delete pauseDepths[scope];
            }
            else {
                pauseDepths[scope] -= 1;
                let depth = pauseDepths[scope];
                if (depth <= 0) {
                    delete pauseDepths[scope];
                }
            }
            this.tryDrain();
        }
    }
    isPaused() {
        return Object.keys(this.pauseDepths).length;
    }
    tryDrain() {
        if (!this.isRunning && !this.isPaused()) {
            this.isRunning = true;
            while (this.isDirty) {
                this.isDirty = false;
                this.drained(); // might set isDirty to true again
            }
            this.isRunning = false;
        }
    }
    clear() {
        this.clearTimeout();
        this.isDirty = false;
        this.pauseDepths = {};
    }
    clearTimeout() {
        if (this.timeoutId) {
            clearTimeout(this.timeoutId);
            this.timeoutId = 0;
        }
    }
    drained() {
        if (this.drainedOption) {
            this.drainedOption();
        }
    }
}

/*
NOTE: detection is complicated (w/ touch and wheel) because ScrollerSyncer needs to know about it,
but are we sure we can't just ignore programmatic scrollTo() calls with a flag? and determine the
the scroll-master simply by who was the newest scroller? Does passive:true do things asynchronously?
*/
class ScrollListener {
    constructor(el) {
        this.el = el;
        this.emitter = new Emitter();
        this.isScroll = false;
        this.isScrollRecent = false;
        this.isWheelRecent = false;
        this.isMouseDown = false; // user currently has mouse down?
        this.isTouchDown = false; // user currently has finger down?
        // accumulated during scroll
        this.isMouse = false;
        this.isTouch = false;
        this.isWheel = false;
        // Handlers
        // ----------------------------------------------------------------------------------------------
        this.handleScroll = () => {
            this.isScrollRecent = true;
            if (this.isMouseDown) {
                this.isMouse = true;
            }
            if (this.isTouchDown) {
                this.isTouch = true;
            }
            if (this.isWheelRecent) {
                this.isWheel = true;
            }
            this.startScroll();
            this.emitter.trigger('scroll', this.getIsDevice());
            this.scrollWaiter.request(500);
        };
        this.handleScrollWait = () => {
            this.isScrollRecent = false;
            // only end the scroll if not currently touching.
            // if touching, the scrolling will end later, on touchend.
            if (!this.isTouchDown) {
                this.endScroll();
            }
        };
        // will fire *before* the scroll event is fired (might not cause a scroll!)
        this.handleWheel = () => {
            this.isWheelRecent = true;
            this.wheelWaiter.request(500);
        };
        this.handleWheelWait = () => {
            this.isWheelRecent = false;
        };
        this.handleMouseDown = () => {
            this.isMouseDown = true;
        };
        this.handleMouseUp = () => {
            this.isMouseDown = false;
        };
        // will fire *before* the scroll event is fired (might not cause a scroll!)
        this.handleTouchStart = () => {
            this.isTouchDown = true;
        };
        this.handleTouchEnd = () => {
            this.isTouchDown = false;
            // if the user ended their touch, and the scroll area wasn't moving,
            // we consider this to be the end of the scroll
            // otherwise, wait for inertia to finish and handleScrollWait to fire
            if (!this.isScrollRecent) {
                this.endScroll();
            }
        };
        this.wheelWaiter = new DelayedRunner(this.handleWheelWait);
        this.scrollWaiter = new DelayedRunner(this.handleScrollWait);
        el.addEventListener('scroll', this.handleScroll, { passive: true });
        el.addEventListener('wheel', this.handleWheel, { passive: true });
        el.addEventListener('mousedown', this.handleMouseDown);
        el.addEventListener('mouseup', this.handleMouseUp);
        el.addEventListener('touchstart', this.handleTouchStart, { passive: true });
        el.addEventListener('touchend', this.handleTouchEnd);
    }
    destroy() {
        let { el } = this;
        el.removeEventListener('scroll', this.handleScroll, { passive: true });
        el.removeEventListener('wheel', this.handleWheel, { passive: true });
        el.removeEventListener('mousedown', this.handleMouseDown);
        el.removeEventListener('mouseup', this.handleMouseUp);
        el.removeEventListener('touchstart', this.handleTouchStart, { passive: true });
        el.removeEventListener('touchend', this.handleTouchEnd);
    }
    // Start / Stop
    // ----------------------------------------------------------------------------------------------
    startScroll() {
        if (!this.isScroll) {
            this.isScroll = true;
            this.emitter.trigger('scrollStart', this.getIsDevice());
        }
    }
    endScroll() {
        if (this.isScroll) { // extra protection because might be called publicly
            this.scrollWaiter.clear(); // (same)
            this.wheelWaiter.clear(); // (same)
            this.isScroll = false;
            this.isWheelRecent = false;
            this.emitter.trigger('scrollEnd', this.getIsDevice());
            this.isMouse = false;
            this.isTouch = false;
            this.isWheel = false;
        }
    }
    getIsDevice() {
        return this.isWheel || this.isMouse || this.isTouch;
    }
}

class Scroller extends DateComponent {
    constructor() {
        super(...arguments);
        this.handleEl = (el) => {
            if (this.el) {
                this.el = null;
                this._isUnmounting = true;
                this.listener.destroy();
            }
            if (el) {
                this.el = el;
                this._isUnmounting = false;
                this.listener = new ScrollListener(el);
            }
        };
        this.handleHRuler = (el) => {
            if (this.disconnectHRuler) {
                this.disconnectHRuler();
                this.disconnectHRuler = undefined;
                if (this.clientWidth !== undefined) {
                    this.clientWidth = undefined;
                    setRef(this.props.clientWidthRef, null);
                }
            }
            if (el) {
                this.disconnectHRuler = watchWidth(el, (clientWidth) => {
                    if (this._isUnmounting)
                        return;
                    if (clientWidth !== this.clientWidth) {
                        this.clientWidth = clientWidth;
                        setRef(this.props.clientWidthRef, clientWidth);
                    }
                });
            }
        };
        this.handleVRuler = (el) => {
            if (this.disconnectVRuler) {
                this.disconnectVRuler();
                this.disconnectVRuler = undefined;
                if (this.clientHeight !== undefined) {
                    this.clientHeight = undefined;
                    setRef(this.props.clientHeightRef, null);
                }
            }
            if (el) {
                this.disconnectVRuler = watchHeight(el, (clientHeight) => {
                    if (this._isUnmounting)
                        return;
                    if (clientHeight !== this.clientHeight) {
                        this.clientHeight = clientHeight;
                        setRef(this.props.clientHeightRef, clientHeight);
                    }
                    const bottomScrollbarWidth = Math.round(this.el.getBoundingClientRect().height - clientHeight);
                    if (bottomScrollbarWidth !== this.bottomScrollbarWidth) {
                        this.bottomScrollbarWidth = bottomScrollbarWidth;
                        setRef(this.props.bottomScrollbarWidthRef, bottomScrollbarWidth);
                    }
                });
            }
        };
    }
    render() {
        const { props } = this;
        // if there's only one axis that needs scrolling, the other axis will unintentionally have
        // scrollbars too if we don't force to 'hidden'
        const fallbackOverflow = (props.horizontal || props.vertical) ? 'hidden' : '';
        return (jsxs("div", { ref: this.handleEl, className: joinClassNames(props.className, classNames.noPadding, classNames.rel, // for children fillTop/fillStart
            props.hideScrollbars && classNames.noScrollbars, classNames.internalScroller), style: {
                ...props.style,
                overflowX: (props.horizontal ? 'auto' : fallbackOverflow),
                overflowY: (props.vertical ? 'auto' : fallbackOverflow),
            }, children: [props.children, Boolean(props.clientWidthRef) && (jsx("div", { ref: this.handleHRuler, className: classNames.fillTop })), Boolean(props.clientHeightRef || props.bottomScrollbarWidthRef) && (jsx("div", { ref: this.handleVRuler, className: classNames.fillStart }))] }));
    }
    endScroll() {
        this.listener.endScroll();
    }
    // Public API
    // -----------------------------------------------------------------------------------------------
    get x() {
        const { el } = this;
        return el ? getNormalizedScrollX(el) : 0;
    }
    get y() {
        const { el } = this;
        return el ? el.scrollTop : 0;
    }
    scrollTo({ x, y }) {
        const { el } = this;
        if (el) {
            if (y != null) {
                el.scrollTop = y;
            }
            if (x != null) {
                setNormalizedScrollX(el, x);
            }
        }
    }
    addScrollStartListener(handler) {
        this.listener.emitter.on('scrollStart', handler);
    }
    removeScrollStartListener(handler) {
        this.listener.emitter.off('scrollStart', handler);
    }
    addScrollEndListener(handler) {
        this.listener.emitter.on('scrollEnd', handler);
    }
    removeScrollEndListener(handler) {
        this.listener.emitter.off('scrollEnd', handler);
    }
}
// Public API
// -------------------------------------------------------------------------------------------------
// We can drop normalization when support for Chromium-based <86 is dropped (see Notion)
function getNormalizedScrollX(el) {
    const { scrollLeft } = el;
    const isRtl = computeElIsRtl(el);
    return isRtl ? getNormalizedRtlScrollX(scrollLeft, el) : scrollLeft;
}
function setNormalizedScrollX(el, x) {
    const isRtl = computeElIsRtl(el);
    el.scrollLeft = isRtl ? getNormalizedRtlScrollLeft(x, el) : x;
}
/*
Returns a value in the 'reverse' system
*/
function getNormalizedRtlScrollX(scrollLeft, el) {
    switch (getRtlScrollerSystem()) {
        case 'positive':
            return el.scrollWidth - el.clientWidth - scrollLeft;
        case 'negative':
            return -scrollLeft;
    }
    return scrollLeft;
}
/*
Receives a value in the 'reverse' system
TODO: is this really the same equations as getNormalizedRtlScrollX??? I think so
  If so, consolidate. With isRtl check too
*/
function getNormalizedRtlScrollLeft(x, el) {
    switch (getRtlScrollerSystem()) {
        case 'positive':
            return el.scrollWidth - el.clientWidth - x;
        case 'negative':
            return -x;
    }
    return x;
}
let _rtlScrollerSystem;
function getRtlScrollerSystem() {
    return _rtlScrollerSystem || (_rtlScrollerSystem = detectRtlScrollerSystem());
}
function detectRtlScrollerSystem() {
    let el = document.createElement('div');
    el.style.position = 'absolute';
    el.style.top = '-1000px';
    el.style.width = '100px'; // must be at least the side of scrollbars or you get inaccurate values (#7335)
    el.style.height = '100px'; // "
    el.style.overflow = 'scroll';
    el.style.direction = 'rtl';
    let innerEl = document.createElement('div');
    innerEl.style.width = '200px';
    innerEl.style.height = '200px';
    el.appendChild(innerEl);
    document.body.appendChild(el);
    let system;
    if (el.scrollLeft > 0) {
        system = 'positive'; // scroll is a positive number from the left edge
    }
    else {
        el.scrollLeft = 50;
        if (el.scrollLeft > 0) {
            system = 'reverse'; // scroll is a positive number from the right edge
        }
        else {
            system = 'negative'; // scroll is a negative number from the right edge
        }
    }
    el.remove();
    return system;
}

class StandardEvent extends BaseComponent {
    constructor() {
        super(...arguments);
        // memo
        this.buildPublicEvent = memoize((context, eventDef, eventInstance) => new EventImpl(context, eventDef, eventInstance));
        this.handleEl = (el) => {
            this.el = el;
            setRef(this.props.elRef, el);
            if (el) {
                setElEventRange(el, this.props.eventRange);
            }
        };
    }
    render() {
        const { props, context } = this;
        const { options } = context;
        const { eventRange } = props;
        const eventUi = eventRange.ui;
        const timeFormat = options.eventTimeFormat || props.defaultTimeFormat;
        const timeText = props.forcedTimeText ?? buildEventRangeTimeText(timeFormat, eventRange, // just for def/instance
        props.slicedStart, props.slicedEnd, props.isStart, props.isEnd, context, props.defaultDisplayEventTime, props.defaultDisplayEventEnd);
        const [tag, attrs, isInteractive] = getEventTagAndAttrs(eventRange, context);
        const eventApi = this.buildPublicEvent(context, eventRange.def, eventRange.instance);
        const isDraggable = !props.disableDragging && computeEventRangeDraggable(eventRange, context);
        const isBlock = /row|column/.test(props.display);
        const subcontentRenderProps = {
            event: eventApi,
            isNarrow: props.isNarrow || false,
            isShort: props.isShort || false,
            timeText,
        };
        const renderProps = {
            event: eventApi, // make stable. everything else atomic. FYI, eventRange unfortunately gets reconstructed a lot, but def/instance is stable
            view: context.viewApi,
            timeText: timeText,
            color: eventUi.color || options.eventColor,
            contrastColor: eventUi.contrastColor || options.eventContrastColor,
            isDraggable,
            isStartResizable: !props.disableResizing && props.isStart && eventUi.durationEditable && options.eventResizableFromStart,
            isEndResizable: !props.disableResizing && props.isEnd && eventUi.durationEditable,
            isMirror: props.isMirror,
            isStart: Boolean(props.isStart),
            isEnd: Boolean(props.isEnd),
            isFirst: Boolean(props.isFirst),
            isLast: Boolean(props.isLast),
            isPast: Boolean(props.isPast), // TODO: don't cast. getDateMeta does it
            isFuture: Boolean(props.isFuture), // TODO: don't cast. getDateMeta does it
            isToday: Boolean(props.isToday), // TODO: don't cast. getDateMeta does it
            isSelected: Boolean(props.isSelected),
            isDragging: Boolean(props.isDragging),
            isResizing: Boolean(props.isResizing),
            isInteractive,
            isNarrow: props.isNarrow || false,
            isShort: props.isShort || false,
            level: props.level || 0,
            timeClass: joinClassNames(generateClassName(options.eventTimeClass, subcontentRenderProps), isBlock && generateClassName(options.blockEventTimeClass, subcontentRenderProps), props.display === 'row' && generateClassName(options.rowEventTimeClass, subcontentRenderProps), props.display === 'column' && generateClassName(options.columnEventTimeClass, subcontentRenderProps), props.display === 'list-item' && generateClassName(options.listItemEventTimeClass, subcontentRenderProps)),
            titleClass: joinClassNames(generateClassName(options.eventTitleClass, subcontentRenderProps), isBlock && generateClassName(options.blockEventTitleClass, subcontentRenderProps), props.display === 'row' && generateClassName(options.rowEventTitleClass, subcontentRenderProps), props.display === 'column' && generateClassName(options.columnEventTitleClass, subcontentRenderProps), props.display === 'list-item' && generateClassName(options.listItemEventTitleClass, subcontentRenderProps), props.display === 'row' && options.rowEventTitleSticky && classNames.stickyS, props.display === 'column' && options.columnEventTitleSticky && classNames.stickyT),
            options: { eventOverlap: Boolean(options.eventOverlap) },
        };
        const outerClassName = joinClassNames(// already includes eventClass below
        isBlock && generateClassName(options.blockEventClass, renderProps), props.display === 'row' && generateClassName(options.rowEventClass, renderProps), props.display === 'column' && generateClassName(options.columnEventClass, renderProps), props.display === 'list-item' && generateClassName(options.listItemEventClass, renderProps), eventUi.className, props.className, props.display === 'column'
            ? classNames.flexCol
            : classNames.flexRow, (eventRange.def.url || isDraggable) && classNames.cursorPointer, classNames.internalEvent, props.isMirror && classNames.internalEventMirror, isDraggable && classNames.internalEventDraggable, renderProps.isSelected && classNames.internalEventSelected, (renderProps.isStartResizable || renderProps.isEndResizable) && classNames.internalEventResizable);
        const beforeClassName = joinClassNames(generateClassName(options.eventBeforeClass, renderProps), isBlock && generateClassName(options.blockEventBeforeClass, renderProps), props.display === 'row' && generateClassName(options.rowEventBeforeClass, renderProps), props.display === 'column' && generateClassName(options.columnEventBeforeClass, renderProps), props.display === 'list-item' && generateClassName(options.listItemEventBeforeClass, renderProps));
        const afterClassName = joinClassNames(generateClassName(options.eventAfterClass, renderProps), isBlock && generateClassName(options.blockEventAfterClass, renderProps), props.display === 'row' && generateClassName(options.rowEventAfterClass, renderProps), props.display === 'column' && generateClassName(options.columnEventAfterClass, renderProps), props.display === 'list-item' && generateClassName(options.listItemEventAfterClass, renderProps));
        const innerClassName = joinClassNames(generateClassName(options.eventInnerClass, renderProps), isBlock && generateClassName(options.blockEventInnerClass, renderProps), props.display === 'row' && generateClassName(options.rowEventInnerClass, renderProps), props.display === 'column' && generateClassName(options.columnEventInnerClass, renderProps), props.display === 'list-item' && generateClassName(options.listItemEventInnerClass, renderProps), !props.disableLiquid && classNames.liquid);
        const beforeContent = props.display === 'row' && options.rowEventBeforeContent;
        const afterContent = props.display === 'row' && options.rowEventAfterContent;
        return (jsx(ContentContainer, { tag: tag, attrs: {
                ...props.attrs,
                ...attrs,
                // HACK because this event-element gets attached to root during some dragging
                dir: (props.isDragging && options.direction === 'rtl') ? 'rtl' : undefined,
            }, className: outerClassName, style: {
                '--fc-event-color': renderProps.color,
                '--fc-event-contrast-color': renderProps.contrastColor,
            }, elRef: this.handleEl, renderProps: renderProps, generatorName: "eventContent", customGenerator: options.eventContent, defaultGenerator: renderInnerContent, classNameGenerator: options.eventClass, didMount: options.eventDidMount, willUnmount: options.eventWillUnmount, children: (InnerContent) => (jsxs(Fragment, { children: [Boolean(renderProps.isSelected && isBlock) && (jsx("div", { className: props.display === 'column'
                            ? classNames.hitX
                            : classNames.hitY })), (beforeClassName || beforeContent) && (jsxs("div", { className: joinClassNames(beforeClassName, !props.disableZindexes && classNames.z1, renderProps.isStartResizable && joinClassNames(props.display === 'column'
                            ? classNames.cursorResizeT
                            : classNames.cursorResizeS, 
                        // these classnames required for dnd
                        classNames.internalEventResizer, classNames.internalEventResizerStart)), children: [beforeContent && (jsx(ContentContainer, { tag: 'div', style: { display: 'contents' }, attrs: { 'aria-hidden': true }, renderProps: renderProps, generatorName: undefined, customGenerator: beforeContent })), Boolean(renderProps.isStartResizable && renderProps.isSelected) && (jsx("div", { className: classNames.hit }))] })), jsx(InnerContent, { tag: "div", className: joinClassNames(innerClassName, !props.disableZindexes && classNames.z0) }), (afterClassName || afterContent) && (jsxs("div", { className: joinClassNames(afterClassName, !props.disableZindexes && classNames.z1, renderProps.isEndResizable && joinClassNames(props.display === 'column'
                            ? classNames.cursorResizeB
                            : classNames.cursorResizeE, 
                        // these classnames required for dnd
                        classNames.internalEventResizer, classNames.internalEventResizerEnd)), children: [afterContent && (jsx(ContentContainer, { tag: 'div', style: { display: 'contents' }, attrs: { 'aria-hidden': true }, renderProps: renderProps, generatorName: undefined, customGenerator: afterContent })), Boolean(renderProps.isEndResizable && renderProps.isSelected) && (jsx("div", { className: classNames.hit }))] }))] })) }));
    }
    componentDidUpdate(prevProps) {
        if (this.el && this.props.eventRange !== prevProps.eventRange) {
            setElEventRange(this.el, this.props.eventRange);
        }
    }
}
StandardEvent.addPropsEquality({
    seg: isPropsEqualShallow,
});
function renderInnerContent(innerProps) {
    return (jsxs(Fragment, { children: [innerProps.timeText && (jsx("div", { className: innerProps.timeClass, children: innerProps.timeText })), jsx("div", { className: innerProps.titleClass, children: innerProps.event.title || jsx(Fragment, { children: "\u00A0" }) })] }));
}

export { BaseComponent as B, ContentContainer as C, DelayedRunner as D, FULL_DATE_FORMAT as F, NowTimerRunner as N, PureComponent as P, RenderId as R, Scroller as S, ViewContextType as V, WEEKDAY_ONLY_FORMAT as W, memoizeObjArg as a, buildViewContext as b, getIsHeightAuto as c, NowTimer as d, DateComponent as e, flushSyncWithSizeBatching as f, generateClassName as g, ViewContainer as h, getDateMeta as i, buildDateStr as j, StandardEvent as k, findWeekdayText as l, memoize as m, findDayNumberText as n, buildNavLinkAttrs as o, afterSize as p, watchWidth as q, renderText as r, setRef as s, findMonthText as t, watchSize as u, isDimsEqual as v, watchHeight as w, getTableHeaderSticky as x, getFooterScrollbarSticky as y, getScrollerSyncerClass as z };