UNPKG

@fullcalendar/web-component

Version:
274 lines (266 loc) 13.3 kB
import { jsx, jsxs, Fragment } from 'preact/jsx-runtime'; import { j as joinClassNames } from './423b7bc6.js'; import { joinDateTimeFormatParts, formatDayString, intersectRanges, startOfDay, addDays } from '@full-ui/headless-calendar'; import { B as BaseComponent, y as findWeekdayText, z as findDayNumberText, v as buildNavLinkAttrs, C as ContentContainer, u as renderText, W as WEEKDAY_ONLY_FORMAT, F as FULL_DATE_FORMAT, x as StandardEvent, a as memoize, t as buildDateStr, g as generateClassName, o as DateComponent, d as getIsHeightAuto, h as ViewContainer, S as Scroller, n as NowTimer, q as getDateMeta } from './fa7e597f.js'; import { F as classNames, c as createFormatter, an as getEventKey, al as getEventRangeMeta, s as sliceEventStore, ak as sortEventSegs } from './69b11357.js'; class ListDayHeaderInner extends BaseComponent { render() { const { props, context } = this; const { options } = context; const textParts = context.dateEnv.formatToParts(props.dayDate, props.dayFormat); const text = joinDateTimeFormatParts(textParts); const hasNavLink = options.navLinks; const renderProps = { ...props.dateMeta, view: context.viewApi, text, textParts, get weekdayText() { return findWeekdayText(textParts); }, get dayNumberText() { return findDayNumberText(textParts); }, hasNavLink, level: props.level, }; const navLinkAttrs = hasNavLink ? buildNavLinkAttrs(this.context, props.dayDate, undefined, text, this.props.isTabbable) : {}; return (jsx(ContentContainer, { tag: "div", attrs: navLinkAttrs, renderProps: renderProps, generatorName: "listDayHeaderContent", customGenerator: options.listDayHeaderContent, defaultGenerator: renderText, classNameGenerator: options.listDayHeaderInnerClass })); } } class ListDayHeader extends BaseComponent { render() { let { options, viewApi, viewSpec } = this.context; let { dayDate, dateMeta } = this.props; let stickyHeaderDates = !this.props.forPrint; const listDayFormat = options.listDayFormat ?? createDefaultListDayFormat(viewSpec); const listDayAltFormat = options.listDayAltFormat ?? createDefaultListDaySideFormat(viewSpec); let renderProps = { ...dateMeta, view: viewApi, }; return (jsx(ContentContainer, { tag: "div", attrs: { 'data-date': formatDayString(dayDate), ...(dateMeta.isToday ? { 'aria-current': 'date' } : {}), }, className: stickyHeaderDates ? classNames.stickyT : '', renderProps: renderProps, generatorName: undefined, classNameGenerator: options.listDayHeaderClass, didMount: options.listDayHeaderDidMount, willUnmount: options.listDayHeaderWillUnmount, children: () => (jsxs(Fragment, { children: [Boolean(listDayFormat) && (jsx(ListDayHeaderInner, { dayDate: dayDate, dayFormat: listDayFormat, isTabbable: true, dateMeta: dateMeta, level: 0 })), Boolean(listDayAltFormat) && (jsx(ListDayHeaderInner, { dayDate: dayDate, dayFormat: listDayAltFormat, isTabbable: false, dateMeta: dateMeta, level: 1 }))] })) })); } } function createDefaultListDayFormat({ durationUnit, singleUnit }) { if (singleUnit === 'day') { return WEEKDAY_ONLY_FORMAT; } else if (durationUnit === 'day' || singleUnit === 'week') { return WEEKDAY_ONLY_FORMAT; } else { return FULL_DATE_FORMAT; } } function createDefaultListDaySideFormat({ durationUnit, singleUnit }) { if (singleUnit === 'day') ; else if (durationUnit === 'day' || singleUnit === 'week') { return FULL_DATE_FORMAT; } else { return WEEKDAY_ONLY_FORMAT; } } const DEFAULT_TIME_FORMAT = createFormatter({ hour: 'numeric', minute: '2-digit', meridiem: 'short', }); class ListEvent extends BaseComponent { render() { let { props, context } = this; let { eventRange } = props; const { displayEventTime } = context.options; let forcedTimeText = (displayEventTime !== false) && (eventRange.def.allDay || (!props.isStart && !props.isEnd)) ? context.options.allDayText : undefined; return (jsx(StandardEvent, { ...props, attrs: { role: 'listitem', }, forcedTimeText: forcedTimeText, defaultTimeFormat: DEFAULT_TIME_FORMAT, disableDragging: true, disableResizing: true, disableZindexes // because conflicts with sticky list headers : true, display: 'list-item' })); } } class ListDay extends BaseComponent { constructor() { super(...arguments); // memo this.getDateMeta = memoize(getDateMeta); this.sortEventSegs = memoize(sortEventSegs); } render() { const { props, context } = this; const { nowDate, todayRange } = props; const { options } = context; const dateMeta = this.getDateMeta(props.dayDate, context.dateEnv, undefined, todayRange); const segs = this.sortEventSegs(props.segs, options.eventOrder); const fullDateStr = buildDateStr(this.context, props.dayDate); const listDayData = { ...dateMeta, isFirst: props.isFirst, isLast: props.isLast, view: context.viewApi, }; const listDayEventsData = { ...dateMeta, view: context.viewApi, }; return (jsxs("div", { role: 'listitem', "aria-label": fullDateStr, className: generateClassName(options.listDayClass, listDayData), children: [jsx(ListDayHeader, { dayDate: props.dayDate, dateMeta: dateMeta, forPrint: props.forPrint }), jsx("div", { role: 'list', "aria-label": options.eventsHint, className: joinClassNames(generateClassName(options.listDayBodyClass, listDayEventsData), classNames.flexCol), children: segs.map((seg, index) => { const key = getEventKey(seg); const isFirst = index === 0; const isLast = index === segs.length - 1; return (jsx(ListEvent, { eventRange: seg.eventRange, slicedStart: seg.slicedStart, slicedEnd: seg.slicedEnd, isStart: seg.isStart, isEnd: seg.isEnd, isFirst: isFirst, isLast: isLast, isDragging: false, isResizing: false, isMirror: false, isSelected: false, ...getEventRangeMeta(seg.eventRange, todayRange, nowDate) }, key)); }) })] })); } } /* Responsible for the scroller, and forwarding event-related actions into the "grid". */ class ListView extends DateComponent { constructor() { super(...arguments); // memo this.computeDateVars = memoize(computeDateVars); this.eventStoreToSegs = memoize(this._eventStoreToSegs); this.setRootEl = (rootEl) => { if (rootEl) { this.context.registerInteractiveComponent(this, { el: rootEl, disableHits: true, // HACK to not do date-clicking/selecting }); } else { this.context.unregisterInteractiveComponent(this); } }; } render() { let { props, context } = this; let { options } = context; let { dayDates, dayRanges } = this.computeDateVars(props.dateProfile); let eventSegs = this.eventStoreToSegs(props.eventStore, props.eventUiBases, dayRanges); let verticalScrolling = !props.forPrint && !getIsHeightAuto(options); return (jsx(ViewContainer, { viewSpec: context.viewSpec, className: joinClassNames(props.className, classNames.flexCol), elRef: this.setRootEl, children: eventSegs.length ? (jsx(Scroller // TODO: don't need heavyweight component , { vertical: verticalScrolling, className: joinClassNames(classNames.flexCol, verticalScrolling ? classNames.liquid : ''), children: this.renderSegList(eventSegs, dayDates) })) : this.renderEmptyMessage() })); } renderEmptyMessage() { let { options, viewApi } = this.context; let renderProps = { text: options.noEventsText, view: viewApi, }; return (jsx(ContentContainer, { tag: "div", attrs: { role: 'status', // does a polite announcement }, renderProps: renderProps, generatorName: "noEventsContent", customGenerator: options.noEventsContent, defaultGenerator: renderNoEventsInner, classNameGenerator: options.noEventsClass, className: classNames.grow, didMount: options.noEventsDidMount, willUnmount: options.noEventsWillUnmount, children: (InnerContent) => (jsx(InnerContent, { tag: "div", className: generateClassName(options.noEventsInnerClass, renderProps) })) })); } renderSegList(allSegs, dayDates) { let { options } = this.context; let segsByDay = groupSegsByDay(allSegs); // sparse array return (jsx("div", { role: "list", "aria-labelledby": this.props.labelId, "aria-label": this.props.labelStr, className: joinClassNames(classNames.flexCol, joinClassNames(options.listDaysClass)), children: jsx(NowTimer, { unit: "day", children: (nowDate, todayRange) => { const dayNodes = []; const populatedDayCount = segsByDay.reduce((count, daySegs) => count + (daySegs ? 1 : 0), 0); let populatedDayIndex = 0; for (let dayIndex = 0; dayIndex < segsByDay.length; dayIndex += 1) { let daySegs = segsByDay[dayIndex]; if (daySegs) { // sparse array, so might be undefined const dayDate = dayDates[dayIndex]; const key = formatDayString(dayDate); const isFirst = populatedDayIndex === 0; const isLast = populatedDayIndex === populatedDayCount - 1; dayNodes.push(jsx(ListDay, { dayDate: dayDate, nowDate: nowDate, todayRange: todayRange, segs: daySegs, isFirst: isFirst, isLast: isLast, forPrint: this.props.forPrint }, key)); populatedDayIndex += 1; } } return (jsx(Fragment, { children: dayNodes })); } }) })); } _eventStoreToSegs(eventStore, eventUiBases, dayRanges) { return this.eventRangesToSegs(sliceEventStore(eventStore, eventUiBases, // HACKY to reference internal state... this.props.dateProfile.activeRange, this.context.options.nextDayThreshold).fg, dayRanges); } eventRangesToSegs(fullDayEventRanges, dayRanges) { let segs = []; for (let fullDayEventRange of fullDayEventRanges) { segs.push(...this.eventRangeToSegs(fullDayEventRange, dayRanges)); } return segs; } eventRangeToSegs(fullDayEventRange, dayRanges) { let fullDayRange = fullDayEventRange.range; let dayIndex; let segs = []; for (dayIndex = 0; dayIndex < dayRanges.length; dayIndex += 1) { const slicedFullDayRange = intersectRanges(fullDayRange, dayRanges[dayIndex]); if (slicedFullDayRange) { segs.push({ eventRange: fullDayEventRange, slicedStart: slicedFullDayRange.start, slicedEnd: slicedFullDayRange.end, isStart: fullDayEventRange.isStart && fullDayRange.start.valueOf() === slicedFullDayRange.start.valueOf(), isEnd: fullDayEventRange.isEnd && fullDayRange.end.valueOf() === slicedFullDayRange.end.valueOf(), dayIndex, }); } } return segs; } } function renderNoEventsInner(renderProps) { return renderProps.text; } function computeDateVars(dateProfile) { let dayStart = startOfDay(dateProfile.renderRange.start); let viewEnd = dateProfile.renderRange.end; let dayDates = []; let dayRanges = []; while (dayStart < viewEnd) { dayDates.push(dayStart); dayRanges.push({ start: dayStart, end: addDays(dayStart, 1), }); dayStart = addDays(dayStart, 1); } return { dayDates, dayRanges }; } // Returns a sparse array of arrays, segs grouped by their dayIndex function groupSegsByDay(segs) { let segsByDay = []; // sparse array let i; let seg; for (i = 0; i < segs.length; i += 1) { seg = segs[i]; (segsByDay[seg.dayIndex] || (segsByDay[seg.dayIndex] = [])) .push(seg); } return segsByDay; } var listPlugin = { name: 'list', views: { list: { component: ListView, buttonTextKey: 'listText', // what to lookup in locale files disallowAmbigTitle: true, }, listDay: { type: 'list', duration: { days: 1 }, }, listWeek: { type: 'list', duration: { weeks: 1 }, }, listMonth: { type: 'list', duration: { month: 1 }, }, listYear: { type: 'list', duration: { year: 1 }, }, }, }; export { listPlugin as l };