UNPKG

@ahultgren/yawv-react

Version:

Work in progress. Made for learning purposes only. Expect nothing.

151 lines (135 loc) 9.33 kB
import { jsx, jsxs } from 'react/jsx-runtime'; import { areIntervalsOverlapping, interval, setHours, getHours, getMinutes, clamp, startOfDay, endOfDay, format, setMinutes, startOfWeek, endOfWeek, eachDayOfInterval } from 'date-fns'; import classNames from 'classnames'; import { createContext, useContext } from 'react'; import { enUS } from 'date-fns/locale'; import { getDate, formatWithOptions } from 'date-fns/fp'; function styleInject(css, ref) { if ( ref === void 0 ) ref = {}; var insertAt = ref.insertAt; if (!css || typeof document === 'undefined') { return; } var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; if (insertAt === 'top') { if (head.firstChild) { head.insertBefore(style, head.firstChild); } else { head.appendChild(style); } } else { head.appendChild(style); } if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } } var css_248z = ".WeekView-module_weekview__WZhNl {\n --header-row-height: 50px;\n --cell-row-height: 3px;\n --line-color: #ddd;\n --text-color: #888;\n --date-color: #555;\n --event-color: #4db227;\n display: grid;\n grid-template-columns: auto 1fr;\n grid-template-rows: auto 1fr;\n position: relative;\n padding: 1%;\n color: var(--text-color);\n font-family: system-ui, Helvetica, Arial, sans-serif;\n font-size: 12px;\n}\n\n.WeekView-module_header__iupyq {\n display: grid;\n grid-auto-columns: 1fr;\n grid-column-start: 2;\n}\n\n.WeekView-module_dayTitle__rWfkv {\n grid-row: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n text-align: center;\n}\n.WeekView-module_dayTitleDate__7V-0- {\n display: block;\n font-size: 2em;\n line-height: 1;\n color: var(--date-color);\n}\n.WeekView-module_dayTitleName__7OdBQ {\n border-left: 1px solid var(--line-color);\n margin-top: 5px;\n padding: 4px 0 6px;\n line-height: 1;\n}\n\n.WeekView-module_column__M-r0H {\n display: grid;\n grid-auto-columns: minmax(0, 1fr);\n grid-auto-rows: var(--cell-row-height);\n}\n\n.WeekView-module_hours__99Yyd {\n margin-bottom: calc(0px - var(--cell-row-height) + 5px);\n}\n\n.WeekView-module_hourTitle__JjHkQ {\n padding: 0 10px 0 5px;\n text-align: right;\n line-height: 0;\n position: relative;\n grid-row-end: span 12;\n}\n.WeekView-module_hourTitle__JjHkQ:after {\n content: \"\";\n color: var(--line-color);\n position: absolute;\n right: -1px;\n top: 0px;\n display: block;\n border-top: 1px solid var(--line-color);\n width: 7px;\n}\n\n.WeekView-module_days__MvENu {\n border-top: 1px solid var(--line-color);\n display: grid;\n grid-auto-flow: column;\n grid-auto-columns: minmax(0, 1fr);\n grid-column: 2/-1;\n}\n\n.WeekView-module_day__cL3PZ {\n border-left: 1px solid var(--line-color);\n}\n\n.WeekView-module_event__gl942 {\n background-color: var(--event-color);\n border-radius: 4px;\n padding: 5px;\n margin: 0 5% 0 0;\n color: #fff;\n}\n.WeekView-module_eventStartIsClipped__zcQLT {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.WeekView-module_eventEndIsClipped__dRqy8 {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n}"; var defaultStyles = {"weekview":"WeekView-module_weekview__WZhNl","header":"WeekView-module_header__iupyq","dayTitle":"WeekView-module_dayTitle__rWfkv","dayTitleDate":"WeekView-module_dayTitleDate__7V-0-","dayTitleName":"WeekView-module_dayTitleName__7OdBQ","column":"WeekView-module_column__M-r0H","hours":"WeekView-module_hours__99Yyd","hourTitle":"WeekView-module_hourTitle__JjHkQ","days":"WeekView-module_days__MvENu","day":"WeekView-module_day__cL3PZ","event":"WeekView-module_event__gl942","eventStartIsClipped":"WeekView-module_eventStartIsClipped__zcQLT","eventEndIsClipped":"WeekView-module_eventEndIsClipped__dRqy8"}; styleInject(css_248z); const WeekViewContext = createContext({ styles: defaultStyles, locale: enUS, }); function WeekViewProvider({ children, styles = defaultStyles, locale = enUS, }) { return (jsx(WeekViewContext.Provider, { value: { styles, locale }, children: children })); } function useWeekView() { return useContext(WeekViewContext); } function filterEventsForDay(events, day, from, to) { return events.filter((event) => { return areIntervalsOverlapping(interval(setHours(day, from), setHours(day, to)), interval(event.startDate, event.endDate)); }); } function DisplayEvent({ title, startAt, endAt, startIsClipped, endIsClipped, }) { const { styles } = useWeekView(); return (jsx("div", { className: classNames("event", styles.event, { [styles.eventStartIsClipped]: startIsClipped, [styles.eventEndIsClipped]: endIsClipped, }), style: { gridRowStart: startAt, gridRowEnd: endAt, }, children: title })); } function Days({ days, fromHour, toHour, events }) { const { styles } = useWeekView(); return (jsx("div", { className: styles.days, children: days.map((day) => { const eventsOfTheDay = filterEventsForDay(events, day, fromHour, toHour); return (jsx(Day, { day: day, events: eventsOfTheDay, fromHour: fromHour, toHour: toHour }, day.toISOString())); }) })); } function Day({ day, events, fromHour, toHour, }) { const { styles } = useWeekView(); return (jsx("div", { className: classNames("column", styles.column, styles.day), "data-date": day.toISOString(), children: events.map((event) => { const { startAt, endAt, startIsClipped, endIsClipped } = formatEventProps(event, day, fromHour, toHour); return (jsx(DisplayEvent, { startAt: startAt, endAt: endAt, startIsClipped: startIsClipped, endIsClipped: endIsClipped, title: event.title }, event.id)); }) })); } function formatEventProps(event, day, fromHour, toHour) { const startAt = clampToTimeRange(getTick(clampToSameDay(event.startDate, day)), fromHour, toHour); const endAt = clampToTimeRange(getTick(clampToSameDay(event.endDate, day)), fromHour, toHour); const startIsClipped = isClipped(startAt, event.startDate); const endIsClipped = isClipped(endAt, event.endDate); return { startAt: startAt - fromHour * 12 + 1, endAt: endAt - fromHour * 12 + 1, startIsClipped, endIsClipped, }; } function clampToTimeRange(hour, from, to) { return Math.min(Math.max(hour, from * 12), to * 12); } function isClipped(hour, date) { return getTick(date) !== hour; } function getTick(date) { const hour = getHours(date); const minutes = getMinutes(date); return Math.round(hour * 12 + minutes / 5); } function clampToSameDay(date, day) { return clamp(date, interval(startOfDay(day), endOfDay(day))); } function Header({ days }) { const { styles, locale } = useWeekView(); const daynames = getDaynames(days, locale); return (jsx("div", { className: styles.header, children: daynames.map((day, i) => (jsxs("div", { className: styles.dayTitle, children: [jsx("div", { className: styles.dayTitleDate, children: getDate(days[i]) }), jsx("div", { className: styles.dayTitleName, children: day })] }, i))) })); } function getDaynames(days, locale = undefined) { return days.map(formatWithOptions({ locale }, "EEE")); } function range(from, to) { return [...Array(to - from).keys()].map((i) => i + from); } function Hours({ fromHour, toHour }) { if (fromHour >= toHour) { console.log(`WeekView: .from (${fromHour}) must be less than .to (${toHour}). Resetting to default values (0 and 24).`); fromHour = 0; toHour = 24; } const { styles, locale } = useWeekView(); const hours = range(fromHour, toHour + 1); return (jsx("div", { className: styles.column + " " + styles.hours, children: hours.map((hour) => (jsx("div", { className: styles.hourTitle, children: formatHour(locale, hour) }, hour))) })); } const formatHour = (locale, hour) => format(setMinutes(setHours(new Date(), hour), 0), "p", { locale }); /* Comment block used by Storybook:*/ /** * Demonstrates all the features of WeekView. Use the controls below to play * with the number of days or hours, for example. */ function WeekView({ fromDate, toDate, fromHour = 0, toHour = 24, events = [], styles, locale, } = {}) { return (jsx(WeekViewProvider, { styles: styles, locale: locale, children: jsx(WeekViewRender, { styles: styles, fromDate: fromDate, toDate: toDate, fromHour: fromHour, toHour: toHour, events: events }) })); } function WeekViewRender({ fromDate, toDate, fromHour = 0, toHour = 24, events = [], } = {}) { const { styles } = useWeekView(); fromDate = fromDate || startOfWeek(new Date(), { weekStartsOn: 1 }); toDate = toDate || endOfWeek(new Date(), { weekStartsOn: 1 }); const days = eachDayOfInterval(interval(fromDate, toDate, { assertPositive: true })); return (jsxs("div", { className: styles.weekview, children: [jsx(Header, { days: days }), jsx(Hours, { fromHour: fromHour, toHour: toHour }), jsx(Days, { days: days, fromHour: fromHour, toHour: toHour, events: events })] })); } export { WeekView }; //# sourceMappingURL=index.es.js.map