@ahultgren/yawv-react
Version:
Work in progress. Made for learning purposes only. Expect nothing.
151 lines (135 loc) • 9.33 kB
JavaScript
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