react-activity-calendar
Advanced tools
| 'use client'; | ||
| import { useState, useEffect, forwardRef, Fragment, Suspense, lazy } from 'react'; | ||
| import { eachDayOfInterval, formatISO, isValid, parseISO, getDay, subWeeks, nextDay, differenceInCalendarDays, getMonth, getYear } from 'date-fns'; | ||
| import { jsxs, jsx } from 'react/jsx-runtime'; | ||
| const NAMESPACE = 'react-activity-calendar'; | ||
| const LABEL_MARGIN = 8; // px | ||
| const DEFAULT_MONTH_LABELS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; | ||
| const DEFAULT_LABELS = { | ||
| months: DEFAULT_MONTH_LABELS, | ||
| weekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], | ||
| totalCount: '{{count}} activities in {{year}}', | ||
| legend: { | ||
| less: 'Less', | ||
| more: 'More' | ||
| } | ||
| }; | ||
| function useColorScheme() { | ||
| const [colorScheme, setColorScheme] = useState('light'); | ||
| const onChange = event => { | ||
| setColorScheme(event.matches ? 'dark' : 'light'); | ||
| }; | ||
| useEffect(() => { | ||
| const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); | ||
| // eslint-disable-next-line react-hooks/set-state-in-effect | ||
| setColorScheme(mediaQuery.matches ? 'dark' : 'light'); | ||
| mediaQuery.addEventListener('change', onChange); | ||
| return () => { | ||
| mediaQuery.removeEventListener('change', onChange); | ||
| }; | ||
| }, []); | ||
| return colorScheme; | ||
| } | ||
| const loadingAnimationName = `${NAMESPACE}--loading-animation`; | ||
| function useLoadingAnimation(zeroColor, colorScheme) { | ||
| const [loaded, setLoaded] = useState(false); | ||
| useEffect(() => { | ||
| const colorLoading = `oklab(from ${zeroColor} l a b)`; | ||
| const colorActive = colorScheme === 'light' ? `oklab(from ${zeroColor} calc(l * 0.96) a b)` : `oklab(from ${zeroColor} calc(l * 1.08) a b)`; | ||
| const style = document.createElement('style'); | ||
| style.innerHTML = ` | ||
| @keyframes ${loadingAnimationName} { | ||
| 0% { | ||
| fill: ${colorLoading}; | ||
| } | ||
| 50% { | ||
| fill: ${colorActive}; | ||
| } | ||
| 100% { | ||
| fill: ${colorLoading}; | ||
| } | ||
| } | ||
| `; | ||
| const handleLoad = () => { | ||
| setLoaded(true); | ||
| }; | ||
| document.head.appendChild(style); | ||
| style.addEventListener('load', handleLoad); | ||
| return () => { | ||
| document.head.removeChild(style); | ||
| style.removeEventListener('load', handleLoad); | ||
| setLoaded(false); | ||
| }; | ||
| }, [zeroColor, colorScheme]); | ||
| return loaded; | ||
| } | ||
| const query = '(prefers-reduced-motion: reduce)'; | ||
| function usePrefersReducedMotion() { | ||
| const [prefersReducedMotion, setPrefersReducedMotion] = useState(true); | ||
| useEffect(() => { | ||
| const mediaQuery = window.matchMedia(query); | ||
| // eslint-disable-next-line react-hooks/set-state-in-effect | ||
| setPrefersReducedMotion(mediaQuery.matches); | ||
| const onChange = event => { | ||
| setPrefersReducedMotion(event.matches); | ||
| }; | ||
| mediaQuery.addEventListener('change', onChange); | ||
| return () => { | ||
| mediaQuery.removeEventListener('change', onChange); | ||
| }; | ||
| }, []); | ||
| return prefersReducedMotion; | ||
| } | ||
| function validateActivities(activities, maxLevel) { | ||
| if (activities.length === 0) { | ||
| throw new Error('Activity data must not be empty.'); | ||
| } | ||
| for (const { | ||
| date, | ||
| level, | ||
| count | ||
| } of activities) { | ||
| if (!isValid(parseISO(date))) { | ||
| throw new Error(`Activity date '${date}' is not a valid ISO 8601 date string.`); | ||
| } | ||
| if (count < 0) { | ||
| throw new RangeError(`Activity count must not be negative, found ${count}.`); | ||
| } | ||
| if (level < 0 || level > maxLevel) { | ||
| throw new RangeError(`Activity level ${level} for ${date} is out of range. It must be between 0 and ${maxLevel}.`); | ||
| } | ||
| } | ||
| } | ||
| function groupByWeeks(activities, weekStart = 0 // 0 = Sunday | ||
| ) { | ||
| const normalizedActivities = fillHoles(activities); | ||
| // Determine the first date of the calendar. If the first date is not the | ||
| // passed weekday, the respective weekday one week earlier is used. | ||
| const firstActivity = normalizedActivities[0]; | ||
| const firstDate = parseISO(firstActivity.date); | ||
| const firstCalendarDate = getDay(firstDate) === weekStart ? firstDate : subWeeks(nextDay(firstDate, weekStart), 1); | ||
| // To correctly group activities by week, it is necessary to left-pad the list | ||
| // because the first date might not be the set start weekday. | ||
| const paddedActivities = [...Array(differenceInCalendarDays(firstDate, firstCalendarDate)).fill(undefined), ...normalizedActivities]; | ||
| const numberOfWeeks = Math.ceil(paddedActivities.length / 7); | ||
| // Finally, group activities by week | ||
| return range(numberOfWeeks).map(weekIndex => paddedActivities.slice(weekIndex * 7, weekIndex * 7 + 7)); | ||
| } | ||
| /** | ||
| * The calendar expects a continuous sequence of days, | ||
| * so fill gaps with empty activity data. | ||
| */ | ||
| function fillHoles(activities) { | ||
| const calendar = new Map(activities.map(a => [a.date, a])); | ||
| const firstActivity = activities[0]; | ||
| const lastActivity = activities[activities.length - 1]; | ||
| return eachDayOfInterval({ | ||
| start: parseISO(firstActivity.date), | ||
| end: parseISO(lastActivity.date) | ||
| }).map(day => { | ||
| const date = formatISO(day, { | ||
| representation: 'date' | ||
| }); | ||
| if (calendar.has(date)) { | ||
| return calendar.get(date); | ||
| } | ||
| return { | ||
| date, | ||
| count: 0, | ||
| level: 0 | ||
| }; | ||
| }); | ||
| } | ||
| /** | ||
| * Following the BEM (block, element, modifier) naming convention | ||
| * https://getbem.com/naming/ | ||
| */ | ||
| function getClassName(element) { | ||
| return `${NAMESPACE}__${element}`; | ||
| } | ||
| function range(n) { | ||
| return [...Array(n).keys()]; | ||
| } | ||
| function generateEmptyData() { | ||
| const year = new Date().getFullYear(); | ||
| const days = eachDayOfInterval({ | ||
| start: new Date(year, 0, 1), | ||
| end: new Date(year, 11, 31) | ||
| }); | ||
| return days.map(date => ({ | ||
| date: formatISO(date, { | ||
| representation: 'date' | ||
| }), | ||
| count: 0, | ||
| level: 0 | ||
| })); | ||
| } | ||
| function getMonthLabels(weeks, monthNames = DEFAULT_MONTH_LABELS) { | ||
| return weeks.reduce((labels, week, weekIndex) => { | ||
| const firstActivity = week.find(activity => activity !== undefined); | ||
| if (!firstActivity) { | ||
| throw new Error(`Unexpected error: Week ${weekIndex + 1} is empty.`); | ||
| } | ||
| const month = monthNames[getMonth(parseISO(firstActivity.date))]; | ||
| if (!month) { | ||
| const monthName = new Date(firstActivity.date).toLocaleString('en-US', { | ||
| month: 'short' | ||
| }); | ||
| throw new Error(`Unexpected error: undefined month label for ${monthName}.`); | ||
| } | ||
| const prevLabel = labels[labels.length - 1]; | ||
| if (weekIndex === 0 || prevLabel?.label !== month) { | ||
| return [...labels, { | ||
| weekIndex, | ||
| label: month | ||
| }]; | ||
| } | ||
| return labels; | ||
| }, []).filter(({ | ||
| weekIndex | ||
| }, index, labels) => { | ||
| // Labels should only be shown if there is "enough" space (data). | ||
| // This is a naive implementation that does not take the block size, | ||
| // font size, etc. into account. | ||
| const minWeeks = 3; | ||
| // Skip the first month label if there is not enough space for the next one. | ||
| if (index === 0) { | ||
| return labels[1] && labels[1].weekIndex - weekIndex >= minWeeks; | ||
| } | ||
| // Skip the last month label if there is not enough data in that month | ||
| // to avoid overflowing the calendar on the right. | ||
| if (index === labels.length - 1) { | ||
| return weeks.slice(weekIndex).length >= minWeeks; | ||
| } | ||
| return true; | ||
| }); | ||
| } | ||
| function maxWeekdayLabelWidth(labels, showWeekdayLabel, fontSize) { | ||
| if (labels.length !== 7) { | ||
| throw new Error('Exactly 7 labels, one for each weekday must be passed.'); | ||
| } | ||
| return labels.reduce((maxWidth, label, index) => showWeekdayLabel.byDayIndex(index) ? Math.max(maxWidth, Math.ceil(calcTextDimensions(label, fontSize).width)) : maxWidth, 0); | ||
| } | ||
| function calcTextDimensions(text, fontSize) { | ||
| if (typeof document === 'undefined' || typeof window === 'undefined') { | ||
| return { | ||
| width: 0, | ||
| height: 0 | ||
| }; | ||
| } | ||
| if (fontSize < 1) { | ||
| throw new RangeError('fontSize must be positive'); | ||
| } | ||
| if (text.length === 0) { | ||
| return { | ||
| width: 0, | ||
| height: 0 | ||
| }; | ||
| } | ||
| const namespace = 'http://www.w3.org/2000/svg'; | ||
| const svg = document.createElementNS(namespace, 'svg'); | ||
| svg.style.position = 'absolute'; | ||
| svg.style.visibility = 'hidden'; | ||
| svg.style.fontFamily = window.getComputedStyle(document.body).fontFamily; | ||
| svg.style.fontSize = `${fontSize}px`; | ||
| const textNode = document.createElementNS(namespace, 'text'); | ||
| textNode.textContent = text; | ||
| svg.appendChild(textNode); | ||
| document.body.appendChild(svg); | ||
| const boundingBox = textNode.getBBox(); | ||
| document.body.removeChild(svg); | ||
| return { | ||
| width: boundingBox.width, | ||
| height: boundingBox.height | ||
| }; | ||
| } | ||
| function initWeekdayLabels(input, weekStart) { | ||
| if (!input) return { | ||
| byDayIndex: () => false, | ||
| shouldShow: false | ||
| }; | ||
| // Default: Show every second day of the week. | ||
| if (input === true) { | ||
| return { | ||
| byDayIndex: index => { | ||
| return (7 + index - weekStart) % 7 % 2 !== 0; | ||
| }, | ||
| shouldShow: true | ||
| }; | ||
| } | ||
| const indexed = []; | ||
| for (const name of input) { | ||
| const index = dayNameToIndex[name.toLowerCase()]; | ||
| indexed[index] = true; | ||
| } | ||
| return { | ||
| byDayIndex: index => indexed[index] ?? false, | ||
| shouldShow: input.length > 0 | ||
| }; | ||
| } | ||
| const dayNameToIndex = { | ||
| sun: 0, | ||
| mon: 1, | ||
| tue: 2, | ||
| wed: 3, | ||
| thu: 4, | ||
| fri: 5, | ||
| sat: 6 | ||
| }; | ||
| function createTheme(input, steps = 5) { | ||
| const defaultTheme = createDefaultTheme(steps); | ||
| if (input) { | ||
| validateThemeInput(input, steps); | ||
| input.light = input.light ?? defaultTheme.light; | ||
| input.dark = input.dark ?? defaultTheme.dark; | ||
| return { | ||
| light: isPair(input.light) ? calcColorScale(input.light, steps) : input.light, | ||
| dark: isPair(input.dark) ? calcColorScale(input.dark, steps) : input.dark | ||
| }; | ||
| } | ||
| return defaultTheme; | ||
| } | ||
| function createDefaultTheme(steps) { | ||
| return { | ||
| light: calcColorScale(['hsl(0, 0%, 92%)', 'hsl(0, 0%, 26%)'], steps), | ||
| dark: calcColorScale(['hsl(0, 0%, 22%)', 'hsl(0, 0%, 92%)'], steps) | ||
| }; | ||
| } | ||
| function validateThemeInput(input, steps) { | ||
| const maxLevelHint = 'The number of colors is controlled by the "maxLevel" property.'; | ||
| if (typeof input !== 'object' || input.light === undefined && input.dark === undefined) { | ||
| throw new Error(`The theme object must contain at least one of the fields "light" and "dark" with exactly 2 or ${steps} colors respectively. ${maxLevelHint}`); | ||
| } | ||
| if (input.light) { | ||
| const { | ||
| length | ||
| } = input.light; | ||
| if (length !== 2 && length !== steps) { | ||
| throw new Error(`theme.light must contain exactly 2 or ${steps} colors, ${length} passed. ${maxLevelHint}`); | ||
| } | ||
| for (const c of input.light) { | ||
| if (typeof window !== 'undefined' && !CSS.supports('color', c)) { | ||
| throw new Error(`Invalid color "${c}" passed. All CSS color formats are accepted.`); | ||
| } | ||
| } | ||
| } | ||
| if (input.dark) { | ||
| const { | ||
| length | ||
| } = input.dark; | ||
| if (length !== 2 && length !== steps) { | ||
| throw new Error(`theme.dark must contain exactly 2 or ${steps} colors, ${length} passed. ${maxLevelHint}`); | ||
| } | ||
| for (const c of input.dark) { | ||
| if (typeof window !== 'undefined' && !CSS.supports('color', c)) { | ||
| throw new Error(`Invalid color "${c}" passed. All CSS color formats are accepted.`); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| function calcColorScale([start, end], steps) { | ||
| return range(steps).map(i => { | ||
| // In the loading animation the zero color is used. | ||
| // However, Safari 16 crashes if a CSS color-mix expression like below is | ||
| // combined with relative color syntax to calculate a hue variation for the | ||
| // animation. Since the start and end colors do not need to be mixed, they | ||
| // can be returned directly to work around this issue. | ||
| switch (i) { | ||
| case 0: | ||
| return start; | ||
| case steps - 1: | ||
| return end; | ||
| default: | ||
| { | ||
| const pos = i / (steps - 1) * 100; | ||
| return `color-mix(in oklab, ${end} ${parseFloat(pos.toFixed(2))}%, ${start})`; | ||
| } | ||
| } | ||
| }); | ||
| } | ||
| function isPair(val) { | ||
| return val.length === 2; | ||
| } | ||
| const styles = { | ||
| container: fontSize => ({ | ||
| width: 'max-content', | ||
| // Calendar should not grow | ||
| maxWidth: '100%', | ||
| // Do not remove - parent might be a flexbox | ||
| display: 'flex', | ||
| flexDirection: 'column', | ||
| gap: '8px', | ||
| fontSize: `${fontSize}px` | ||
| }), | ||
| scrollContainer: fontSize => ({ | ||
| maxWidth: '100%', | ||
| overflowX: 'auto', | ||
| overflowY: 'hidden', | ||
| paddingTop: Math.ceil(0.1 * fontSize) // SVG <text> overflows in Firefox at y=0 | ||
| }), | ||
| calendar: { | ||
| display: 'block', | ||
| // SVGs are inline-block by default | ||
| overflow: 'visible' // Weekday labels are rendered left of the container | ||
| }, | ||
| rect: colorScheme => ({ | ||
| stroke: colorScheme === 'light' ? 'rgba(0, 0, 0, 0.08)' : 'rgba(255, 255, 255, 0.04)' | ||
| }), | ||
| footer: { | ||
| container: { | ||
| display: 'flex', | ||
| flexWrap: 'wrap', | ||
| gap: '4px 16px', | ||
| whiteSpace: 'nowrap' | ||
| }, | ||
| legend: { | ||
| marginLeft: 'auto', | ||
| display: 'flex', | ||
| alignItems: 'center', | ||
| gap: '3px' | ||
| } | ||
| } | ||
| }; | ||
| const Tooltip = /*#__PURE__*/lazy(() => import('./Tooltip-CX2cJQ7a.js').then(module => ({ | ||
| default: module.Tooltip | ||
| }))); | ||
| const ActivityCalendar = /*#__PURE__*/forwardRef(({ | ||
| data: activities, | ||
| blockMargin = 4, | ||
| blockRadius = 2, | ||
| blockSize = 12, | ||
| colorScheme: colorSchemeProp = undefined, | ||
| fontSize = 14, | ||
| labels: labelsProp = undefined, | ||
| loading = false, | ||
| maxLevel = 4, | ||
| renderBlock = undefined, | ||
| renderColorLegend = undefined, | ||
| showColorLegend = true, | ||
| showMonthLabels = true, | ||
| showTotalCount = true, | ||
| showWeekdayLabels = false, | ||
| style: styleProp = {}, | ||
| theme: themeProp = undefined, | ||
| tooltips = {}, | ||
| weekStart = 0 // Sunday | ||
| }, ref) => { | ||
| const [isClient, setIsClient] = useState(false); | ||
| useEffect(() => { | ||
| setIsClient(true); | ||
| }, []); | ||
| maxLevel = Math.max(1, maxLevel); | ||
| const theme = createTheme(themeProp, maxLevel + 1); | ||
| const systemColorScheme = useColorScheme(); | ||
| const colorScheme = colorSchemeProp ?? systemColorScheme; | ||
| const colorScale = theme[colorScheme]; | ||
| const animationLoaded = useLoadingAnimation(colorScale[0], colorScheme); | ||
| const useAnimation = !usePrefersReducedMotion(); | ||
| if (loading) { | ||
| // Only show the loading state once the CSS animation has been injected | ||
| // to avoid a flash of white with dark backgrounds. | ||
| if (useAnimation && !animationLoaded) { | ||
| return null; | ||
| } | ||
| activities = generateEmptyData(); | ||
| } | ||
| validateActivities(activities, maxLevel); | ||
| const firstActivity = activities[0]; | ||
| const year = getYear(parseISO(firstActivity.date)); | ||
| const weeks = groupByWeeks(activities, weekStart); | ||
| const labels = Object.assign({}, DEFAULT_LABELS, labelsProp); | ||
| const labelHeight = showMonthLabels ? fontSize + LABEL_MARGIN : 0; | ||
| const weekdayLabels = initWeekdayLabels(showWeekdayLabels, weekStart); | ||
| // Must be calculated on the client, or SSR hydration errors will occur | ||
| // because server and client HTML would not match. | ||
| const weekdayLabelOffset = isClient && weekdayLabels.shouldShow ? maxWeekdayLabelWidth(labels.weekdays, weekdayLabels, fontSize) + LABEL_MARGIN : undefined; | ||
| function getDimensions() { | ||
| return { | ||
| width: weeks.length * (blockSize + blockMargin) - blockMargin, | ||
| height: labelHeight + (blockSize + blockMargin) * 7 - blockMargin | ||
| }; | ||
| } | ||
| function renderCalendar() { | ||
| return weeks.map((week, weekIndex) => week.map((activity, dayIndex) => { | ||
| if (!activity) { | ||
| return null; | ||
| } | ||
| const loadingAnimation = loading && useAnimation ? { | ||
| animation: `${loadingAnimationName} 1.75s ease-in-out infinite`, | ||
| animationDelay: `${weekIndex * 20 + dayIndex * 20}ms` | ||
| } : undefined; | ||
| const block = /*#__PURE__*/jsx("rect", { | ||
| x: 0, | ||
| y: labelHeight + (blockSize + blockMargin) * dayIndex, | ||
| width: blockSize, | ||
| height: blockSize, | ||
| rx: blockRadius, | ||
| ry: blockRadius, | ||
| fill: colorScale[activity.level], | ||
| "data-date": activity.date, | ||
| "data-level": activity.level, | ||
| style: { | ||
| ...styles.rect(colorScheme), | ||
| ...loadingAnimation | ||
| } | ||
| }); | ||
| const renderedBlock = renderBlock ? renderBlock(block, activity) : block; | ||
| return /*#__PURE__*/jsx(Fragment, { | ||
| children: tooltips.activity ? /*#__PURE__*/jsx(Suspense, { | ||
| fallback: renderedBlock, | ||
| children: /*#__PURE__*/jsx(Tooltip, { | ||
| text: tooltips.activity.text(activity), | ||
| colorScheme: colorScheme, | ||
| placement: tooltips.activity.placement ?? 'top', | ||
| hoverRestMs: tooltips.activity.hoverRestMs, | ||
| offset: tooltips.activity.offset, | ||
| transitionStyles: tooltips.activity.transitionStyles, | ||
| withArrow: tooltips.activity.withArrow, | ||
| children: renderedBlock | ||
| }) | ||
| }) : renderedBlock | ||
| }, activity.date); | ||
| })).map((week, x) => /*#__PURE__*/jsx("g", { | ||
| transform: `translate(${(blockSize + blockMargin) * x}, 0)`, | ||
| children: week | ||
| }, x)); | ||
| } | ||
| function renderFooter() { | ||
| if (!showTotalCount && !showColorLegend) { | ||
| return null; | ||
| } | ||
| const totalCount = activities.reduce((sum, activity) => sum + activity.count, 0); | ||
| return /*#__PURE__*/jsxs("footer", { | ||
| className: getClassName('footer'), | ||
| style: { | ||
| ...styles.footer.container, | ||
| marginLeft: weekdayLabelOffset | ||
| }, | ||
| children: [loading && /*#__PURE__*/jsx("div", { | ||
| children: "\xA0" | ||
| }), !loading && showTotalCount && /*#__PURE__*/jsx("div", { | ||
| className: getClassName('count'), | ||
| children: labels.totalCount ? labels.totalCount.replace('{{count}}', String(totalCount)).replace('{{year}}', String(year)) : `${totalCount} activities in ${year}` | ||
| }), !loading && showColorLegend && /*#__PURE__*/jsxs("div", { | ||
| className: getClassName('legend-colors'), | ||
| style: styles.footer.legend, | ||
| children: [/*#__PURE__*/jsx("span", { | ||
| style: { | ||
| marginRight: '0.4em' | ||
| }, | ||
| children: labels.legend.less | ||
| }), range(maxLevel + 1).map(level => { | ||
| const colorLegend = /*#__PURE__*/jsx("svg", { | ||
| width: blockSize, | ||
| height: blockSize, | ||
| children: /*#__PURE__*/jsx("rect", { | ||
| width: blockSize, | ||
| height: blockSize, | ||
| fill: colorScale[level], | ||
| rx: blockRadius, | ||
| ry: blockRadius, | ||
| style: styles.rect(colorScheme) | ||
| }) | ||
| }, level); | ||
| const renderedColorLegend = renderColorLegend ? renderColorLegend(colorLegend, level) : colorLegend; | ||
| return /*#__PURE__*/jsx(Fragment, { | ||
| children: tooltips.colorLegend ? /*#__PURE__*/jsx(Suspense, { | ||
| fallback: renderedColorLegend, | ||
| children: /*#__PURE__*/jsx(Tooltip, { | ||
| text: tooltips.colorLegend.text(level), | ||
| colorScheme: colorScheme, | ||
| placement: tooltips.colorLegend.placement ?? 'bottom', | ||
| hoverRestMs: tooltips.colorLegend.hoverRestMs, | ||
| offset: tooltips.colorLegend.offset, | ||
| transitionStyles: tooltips.colorLegend.transitionStyles, | ||
| withArrow: tooltips.colorLegend.withArrow, | ||
| children: renderedColorLegend | ||
| }) | ||
| }) : renderedColorLegend | ||
| }, level); | ||
| }), /*#__PURE__*/jsx("span", { | ||
| style: { | ||
| marginLeft: '0.4em' | ||
| }, | ||
| children: labels.legend.more | ||
| })] | ||
| })] | ||
| }); | ||
| } | ||
| function renderWeekdayLabels() { | ||
| if (!weekdayLabels.shouldShow) { | ||
| return null; | ||
| } | ||
| return /*#__PURE__*/jsx("g", { | ||
| className: getClassName('legend-weekday'), | ||
| children: range(7).map(index => { | ||
| const dayIndex = (index + weekStart) % 7; | ||
| if (!weekdayLabels.byDayIndex(dayIndex)) { | ||
| return null; | ||
| } | ||
| return /*#__PURE__*/jsx("text", { | ||
| x: -LABEL_MARGIN, | ||
| y: labelHeight + (blockSize + blockMargin) * index + blockSize / 2, | ||
| dominantBaseline: "central", | ||
| textAnchor: "end", | ||
| fill: "currentColor", | ||
| children: labels.weekdays[dayIndex] | ||
| }, index); | ||
| }) | ||
| }); | ||
| } | ||
| function renderMonthLabels() { | ||
| if (!showMonthLabels) { | ||
| return null; | ||
| } | ||
| return /*#__PURE__*/jsx("g", { | ||
| className: getClassName('legend-month'), | ||
| children: getMonthLabels(weeks, labels.months).map(({ | ||
| label, | ||
| weekIndex | ||
| }) => /*#__PURE__*/jsx("text", { | ||
| x: (blockSize + blockMargin) * weekIndex, | ||
| y: 0, | ||
| dominantBaseline: "hanging", | ||
| fill: "currentColor", | ||
| children: label | ||
| }, weekIndex)) | ||
| }); | ||
| } | ||
| const { | ||
| width, | ||
| height | ||
| } = getDimensions(); | ||
| return /*#__PURE__*/jsxs("article", { | ||
| ref: ref, | ||
| className: NAMESPACE, | ||
| style: { | ||
| ...styleProp, | ||
| ...styles.container(fontSize) | ||
| }, | ||
| children: [/*#__PURE__*/jsx("div", { | ||
| className: getClassName('scroll-container'), | ||
| style: styles.scrollContainer(fontSize), | ||
| children: /*#__PURE__*/jsxs("svg", { | ||
| width: width, | ||
| height: height, | ||
| viewBox: `0 0 ${width} ${height}`, | ||
| className: getClassName('calendar'), | ||
| style: { | ||
| ...styles.calendar, | ||
| marginLeft: weekdayLabelOffset | ||
| }, | ||
| children: [!loading && renderWeekdayLabels(), !loading && renderMonthLabels(), renderCalendar()] | ||
| }) | ||
| }), renderFooter()] | ||
| }); | ||
| }); | ||
| ActivityCalendar.displayName = 'ActivityCalendar'; | ||
| export { ActivityCalendar as A, getClassName as g }; | ||
| //# sourceMappingURL=index-w4bahFWW.js.map |
| {"version":3,"file":"index-w4bahFWW.js","sources":["../../src/constants.ts","../../src/hooks/useColorScheme.ts","../../src/hooks/useLoadingAnimation.ts","../../src/hooks/usePrefersReducedMotion.ts","../../src/lib/calendar.ts","../../src/lib/label.ts","../../src/lib/theme.ts","../../src/styles/styles.ts","../../src/components/ActivityCalendar.tsx"],"sourcesContent":["export const NAMESPACE = 'react-activity-calendar'\nexport const LABEL_MARGIN = 8 // px\n\nexport const DEFAULT_MONTH_LABELS = [\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'May',\n 'Jun',\n 'Jul',\n 'Aug',\n 'Sep',\n 'Oct',\n 'Nov',\n 'Dec',\n]\n\nexport const DEFAULT_LABELS = {\n months: DEFAULT_MONTH_LABELS,\n weekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\n totalCount: '{{count}} activities in {{year}}',\n legend: {\n less: 'Less',\n more: 'More',\n },\n}\n","import { useEffect, useState } from 'react'\nimport type { ColorScheme } from '../types'\n\nexport function useColorScheme() {\n const [colorScheme, setColorScheme] = useState<ColorScheme>('light')\n\n const onChange = (event: MediaQueryListEvent) => {\n setColorScheme(event.matches ? 'dark' : 'light')\n }\n\n useEffect(() => {\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setColorScheme(mediaQuery.matches ? 'dark' : 'light')\n\n mediaQuery.addEventListener('change', onChange)\n\n return () => {\n mediaQuery.removeEventListener('change', onChange)\n }\n }, [])\n\n return colorScheme\n}\n","import { useEffect, useState } from 'react'\nimport { NAMESPACE } from '../constants'\nimport type { ColorScheme } from '../types'\n\nexport const loadingAnimationName = `${NAMESPACE}--loading-animation`\n\nexport function useLoadingAnimation(zeroColor: string, colorScheme: ColorScheme) {\n const [loaded, setLoaded] = useState(false)\n\n useEffect(() => {\n const colorLoading = `oklab(from ${zeroColor} l a b)`\n const colorActive =\n colorScheme === 'light'\n ? `oklab(from ${zeroColor} calc(l * 0.96) a b)`\n : `oklab(from ${zeroColor} calc(l * 1.08) a b)`\n\n const style = document.createElement('style')\n style.innerHTML = `\n @keyframes ${loadingAnimationName} {\n 0% {\n fill: ${colorLoading};\n }\n 50% {\n fill: ${colorActive};\n }\n 100% {\n fill: ${colorLoading};\n }\n }\n `\n const handleLoad = () => {\n setLoaded(true)\n }\n\n document.head.appendChild(style)\n style.addEventListener('load', handleLoad)\n\n return () => {\n document.head.removeChild(style)\n style.removeEventListener('load', handleLoad)\n setLoaded(false)\n }\n }, [zeroColor, colorScheme])\n\n return loaded\n}\n","import { useEffect, useState } from 'react'\n\nconst query = '(prefers-reduced-motion: reduce)'\n\nexport function usePrefersReducedMotion() {\n const [prefersReducedMotion, setPrefersReducedMotion] = useState(true)\n\n useEffect(() => {\n const mediaQuery = window.matchMedia(query)\n\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setPrefersReducedMotion(mediaQuery.matches)\n\n const onChange = (event: MediaQueryListEvent) => {\n setPrefersReducedMotion(event.matches)\n }\n\n mediaQuery.addEventListener('change', onChange)\n\n return () => {\n mediaQuery.removeEventListener('change', onChange)\n }\n }, [])\n\n return prefersReducedMotion\n}\n","import {\n differenceInCalendarDays,\n eachDayOfInterval,\n endOfYear,\n formatISO,\n getDay,\n isValid,\n nextDay,\n parseISO,\n startOfYear,\n subWeeks,\n} from 'date-fns'\nimport { NAMESPACE } from '../constants'\nimport type { Activity, DayIndex, Week } from '../types'\n\nexport function validateActivities(activities: Array<Activity>, maxLevel: number) {\n if (activities.length === 0) {\n throw new Error('Activity data must not be empty.')\n }\n\n for (const { date, level, count } of activities) {\n if (!isValid(parseISO(date))) {\n throw new Error(`Activity date '${date}' is not a valid ISO 8601 date string.`)\n }\n\n if (count < 0) {\n throw new RangeError(`Activity count must not be negative, found ${count}.`)\n }\n\n if (level < 0 || level > maxLevel) {\n throw new RangeError(\n `Activity level ${level} for ${date} is out of range. It must be between 0 and ${maxLevel}.`,\n )\n }\n }\n}\n\nexport function groupByWeeks(\n activities: Array<Activity>,\n weekStart: DayIndex = 0, // 0 = Sunday\n): Array<Week> {\n const normalizedActivities = fillHoles(activities)\n\n // Determine the first date of the calendar. If the first date is not the\n // passed weekday, the respective weekday one week earlier is used.\n const firstActivity = normalizedActivities[0] as Activity\n const firstDate = parseISO(firstActivity.date)\n const firstCalendarDate =\n getDay(firstDate) === weekStart ? firstDate : subWeeks(nextDay(firstDate, weekStart), 1)\n\n // To correctly group activities by week, it is necessary to left-pad the list\n // because the first date might not be the set start weekday.\n const paddedActivities = [\n ...(Array(differenceInCalendarDays(firstDate, firstCalendarDate)).fill(\n undefined,\n ) as Array<Activity>),\n ...normalizedActivities,\n ]\n\n const numberOfWeeks = Math.ceil(paddedActivities.length / 7)\n\n // Finally, group activities by week\n return range(numberOfWeeks).map(weekIndex =>\n paddedActivities.slice(weekIndex * 7, weekIndex * 7 + 7),\n )\n}\n\n/**\n * The calendar expects a continuous sequence of days,\n * so fill gaps with empty activity data.\n */\nfunction fillHoles(activities: Array<Activity>): Array<Activity> {\n const calendar = new Map<string, Activity>(activities.map(a => [a.date, a]))\n const firstActivity = activities[0] as Activity\n const lastActivity = activities[activities.length - 1] as Activity\n\n return eachDayOfInterval({\n start: parseISO(firstActivity.date),\n end: parseISO(lastActivity.date),\n }).map(day => {\n const date = formatISO(day, { representation: 'date' })\n\n if (calendar.has(date)) {\n return calendar.get(date) as Activity\n }\n\n return {\n date,\n count: 0,\n level: 0,\n }\n })\n}\n\n/**\n * Following the BEM (block, element, modifier) naming convention\n * https://getbem.com/naming/\n */\nexport function getClassName(element: string) {\n return `${NAMESPACE}__${element}`\n}\n\nexport function range(n: number) {\n return [...Array(n).keys()]\n}\n\nexport function generateEmptyData(): Array<Activity> {\n const year = new Date().getFullYear()\n const days = eachDayOfInterval({\n start: new Date(year, 0, 1),\n end: new Date(year, 11, 31),\n })\n\n return days.map(date => ({\n date: formatISO(date, { representation: 'date' }),\n count: 0,\n level: 0,\n }))\n}\n\nexport function generateTestData(args: {\n interval?: { start: Date; end: Date }\n maxLevel?: number\n}): Array<Activity> {\n const maxCount = 20\n const maxLevel = args.maxLevel ? Math.max(1, args.maxLevel) : 4\n const now = new Date()\n\n const days = eachDayOfInterval(\n args.interval ?? {\n start: startOfYear(now),\n end: endOfYear(now),\n },\n )\n\n const noise = whiteNoise(days.length, maxLevel, v => 0.9 * Math.pow(v, 2))\n\n return days.map((date, i) => {\n const level = noise[i] as number\n\n return {\n date: formatISO(date, { representation: 'date' }),\n count: Math.round(level * (maxCount / maxLevel)),\n level,\n }\n })\n}\n\n// Deterministically generates n white noise values from 0 to max (inclusive).\nfunction whiteNoise(\n n: number,\n max: number,\n transformFn: (v: number) => number = v => v,\n): Array<number> {\n const seed = 54321\n const random = mulberry32(seed)\n\n return Array.from({ length: n }, () => {\n const v = transformFn(random())\n return Math.floor(v * (max + 1))\n })\n}\n\n// Mulberry32 pseudorandom number generator\nfunction mulberry32(seed: number) {\n let state = seed >>> 0 // ensure unsigned 32-bit integer\n\n return () => {\n state += 0x6d2b79f5\n let r = Math.imul(state ^ (state >>> 15), 1 | state)\n r ^= r + Math.imul(r ^ (r >>> 7), 61 | r)\n\n return ((r ^ (r >>> 14)) >>> 0) / 4294967296\n }\n}\n","import { getMonth, parseISO } from 'date-fns'\nimport type { Props } from '../components/ActivityCalendar'\nimport { DEFAULT_MONTH_LABELS } from '../constants'\nimport type { DayIndex, DayName, Week, WeekdayLabels } from '../types'\n\ntype MonthLabel = {\n weekIndex: number\n label: string\n}\n\nexport function getMonthLabels(\n weeks: Array<Week>,\n monthNames: Array<string> = DEFAULT_MONTH_LABELS,\n): Array<MonthLabel> {\n return weeks\n .reduce<Array<MonthLabel>>((labels, week, weekIndex) => {\n const firstActivity = week.find(activity => activity !== undefined)\n\n if (!firstActivity) {\n throw new Error(`Unexpected error: Week ${weekIndex + 1} is empty.`)\n }\n\n const month = monthNames[getMonth(parseISO(firstActivity.date))]\n\n if (!month) {\n const monthName = new Date(firstActivity.date).toLocaleString('en-US', { month: 'short' })\n throw new Error(`Unexpected error: undefined month label for ${monthName}.`)\n }\n\n const prevLabel = labels[labels.length - 1]\n\n if (weekIndex === 0 || prevLabel?.label !== month) {\n return [...labels, { weekIndex, label: month }]\n }\n\n return labels\n }, [])\n .filter(({ weekIndex }, index, labels) => {\n // Labels should only be shown if there is \"enough\" space (data).\n // This is a naive implementation that does not take the block size,\n // font size, etc. into account.\n const minWeeks = 3\n\n // Skip the first month label if there is not enough space for the next one.\n if (index === 0) {\n return labels[1] && labels[1].weekIndex - weekIndex >= minWeeks\n }\n\n // Skip the last month label if there is not enough data in that month\n // to avoid overflowing the calendar on the right.\n if (index === labels.length - 1) {\n return weeks.slice(weekIndex).length >= minWeeks\n }\n\n return true\n })\n}\n\nexport function maxWeekdayLabelWidth(\n labels: Array<string>,\n showWeekdayLabel: WeekdayLabels,\n fontSize: number,\n): number {\n if (labels.length !== 7) {\n throw new Error('Exactly 7 labels, one for each weekday must be passed.')\n }\n\n return labels.reduce(\n (maxWidth, label, index) =>\n showWeekdayLabel.byDayIndex(index as DayIndex)\n ? Math.max(maxWidth, Math.ceil(calcTextDimensions(label, fontSize).width))\n : maxWidth,\n 0,\n )\n}\n\nexport function calcTextDimensions(text: string, fontSize: number) {\n if (typeof document === 'undefined' || typeof window === 'undefined') {\n return { width: 0, height: 0 }\n }\n\n if (fontSize < 1) {\n throw new RangeError('fontSize must be positive')\n }\n\n if (text.length === 0) {\n return { width: 0, height: 0 }\n }\n\n const namespace = 'http://www.w3.org/2000/svg'\n const svg = document.createElementNS(namespace, 'svg')\n\n svg.style.position = 'absolute'\n svg.style.visibility = 'hidden'\n svg.style.fontFamily = window.getComputedStyle(document.body).fontFamily\n svg.style.fontSize = `${fontSize}px`\n\n const textNode = document.createElementNS(namespace, 'text')\n textNode.textContent = text\n\n svg.appendChild(textNode)\n document.body.appendChild(svg)\n const boundingBox = textNode.getBBox()\n\n document.body.removeChild(svg)\n\n return { width: boundingBox.width, height: boundingBox.height }\n}\n\nexport function initWeekdayLabels(\n input: Props['showWeekdayLabels'],\n weekStart: DayIndex,\n): WeekdayLabels {\n if (!input)\n return {\n byDayIndex: () => false,\n shouldShow: false,\n }\n\n // Default: Show every second day of the week.\n if (input === true) {\n return {\n byDayIndex: index => {\n return ((7 + index - weekStart) % 7) % 2 !== 0\n },\n shouldShow: true,\n }\n }\n\n const indexed: Array<boolean> = []\n for (const name of input) {\n const index = dayNameToIndex[name.toLowerCase() as DayName]\n indexed[index] = true\n }\n\n return {\n byDayIndex: index => indexed[index] ?? false,\n shouldShow: input.length > 0,\n }\n}\n\nconst dayNameToIndex: Record<DayName, DayIndex> = {\n sun: 0,\n mon: 1,\n tue: 2,\n wed: 3,\n thu: 4,\n fri: 5,\n sat: 6,\n}\n","import type { Color, ColorScale, Theme, ThemeInput } from '../types'\nimport { range } from './calendar'\n\nexport function createTheme(input?: ThemeInput, steps = 5): Theme {\n const defaultTheme = createDefaultTheme(steps)\n\n if (input) {\n validateThemeInput(input, steps)\n\n input.light = input.light ?? defaultTheme.light\n input.dark = input.dark ?? defaultTheme.dark\n\n return {\n light: isPair(input.light) ? calcColorScale(input.light, steps) : input.light,\n dark: isPair(input.dark) ? calcColorScale(input.dark, steps) : input.dark,\n }\n }\n\n return defaultTheme\n}\n\nfunction createDefaultTheme(steps: number): Theme {\n return {\n light: calcColorScale(['hsl(0, 0%, 92%)', 'hsl(0, 0%, 26%)'], steps),\n dark: calcColorScale(['hsl(0, 0%, 22%)', 'hsl(0, 0%, 92%)'], steps),\n }\n}\n\nfunction validateThemeInput(input: ThemeInput, steps: number) {\n const maxLevelHint = 'The number of colors is controlled by the \"maxLevel\" property.'\n\n if (typeof input !== 'object' || (input.light === undefined && input.dark === undefined)) {\n throw new Error(\n `The theme object must contain at least one of the fields \"light\" and \"dark\" with exactly 2 or ${steps} colors respectively. ${maxLevelHint}`,\n )\n }\n\n if (input.light) {\n const { length } = input.light\n if (length !== 2 && length !== steps) {\n throw new Error(\n `theme.light must contain exactly 2 or ${steps} colors, ${length} passed. ${maxLevelHint}`,\n )\n }\n\n for (const c of input.light) {\n if (typeof window !== 'undefined' && !CSS.supports('color', c)) {\n throw new Error(`Invalid color \"${c}\" passed. All CSS color formats are accepted.`)\n }\n }\n }\n\n if (input.dark) {\n const { length } = input.dark\n if (length !== 2 && length !== steps) {\n throw new Error(\n `theme.dark must contain exactly 2 or ${steps} colors, ${length} passed. ${maxLevelHint}`,\n )\n }\n\n for (const c of input.dark) {\n if (typeof window !== 'undefined' && !CSS.supports('color', c)) {\n throw new Error(`Invalid color \"${c}\" passed. All CSS color formats are accepted.`)\n }\n }\n }\n}\n\nfunction calcColorScale([start, end]: [Color, Color], steps: number): ColorScale {\n return range(steps).map(i => {\n // In the loading animation the zero color is used.\n // However, Safari 16 crashes if a CSS color-mix expression like below is\n // combined with relative color syntax to calculate a hue variation for the\n // animation. Since the start and end colors do not need to be mixed, they\n // can be returned directly to work around this issue.\n switch (i) {\n case 0:\n return start\n case steps - 1:\n return end\n default: {\n const pos = (i / (steps - 1)) * 100\n return `color-mix(in oklab, ${end} ${parseFloat(pos.toFixed(2))}%, ${start})`\n }\n }\n })\n}\n\nfunction isPair<T>(val: Array<T>): val is [T, T] {\n return val.length === 2\n}\n","import type { CSSProperties } from 'react'\nimport type { ColorScheme } from '../types'\n\nexport const styles = {\n container: (fontSize: number) =>\n ({\n width: 'max-content', // Calendar should not grow\n maxWidth: '100%', // Do not remove - parent might be a flexbox\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n fontSize: `${fontSize}px`,\n }) satisfies CSSProperties,\n scrollContainer: (fontSize: number) =>\n ({\n maxWidth: '100%',\n overflowX: 'auto',\n overflowY: 'hidden',\n paddingTop: Math.ceil(0.1 * fontSize), // SVG <text> overflows in Firefox at y=0\n }) satisfies CSSProperties,\n calendar: {\n display: 'block', // SVGs are inline-block by default\n overflow: 'visible', // Weekday labels are rendered left of the container\n } satisfies CSSProperties,\n rect: (colorScheme: ColorScheme) =>\n ({\n stroke: colorScheme === 'light' ? 'rgba(0, 0, 0, 0.08)' : 'rgba(255, 255, 255, 0.04)',\n }) satisfies CSSProperties,\n footer: {\n container: {\n display: 'flex',\n flexWrap: 'wrap',\n gap: '4px 16px',\n whiteSpace: 'nowrap',\n } satisfies CSSProperties,\n legend: {\n marginLeft: 'auto',\n display: 'flex',\n alignItems: 'center',\n gap: '3px',\n } satisfies CSSProperties,\n },\n}\n","'use client'\n\nimport {\n forwardRef,\n Fragment,\n lazy,\n Suspense,\n useEffect,\n useState,\n type CSSProperties,\n type ForwardedRef,\n type ReactElement,\n} from 'react'\nimport { getYear, parseISO } from 'date-fns'\nimport { DEFAULT_LABELS, LABEL_MARGIN, NAMESPACE } from '../constants'\nimport { useColorScheme } from '../hooks/useColorScheme'\nimport { loadingAnimationName, useLoadingAnimation } from '../hooks/useLoadingAnimation'\nimport { usePrefersReducedMotion } from '../hooks/usePrefersReducedMotion'\nimport {\n generateEmptyData,\n getClassName,\n groupByWeeks,\n range,\n validateActivities,\n} from '../lib/calendar'\nimport { getMonthLabels, initWeekdayLabels, maxWeekdayLabelWidth } from '../lib/label'\nimport { createTheme } from '../lib/theme'\nimport { styles } from '../styles/styles'\nimport type {\n Activity,\n BlockElement,\n ColorScheme,\n DayIndex,\n DayName,\n Labels,\n ThemeInput,\n} from '../types'\nimport { type TooltipConfig } from './Tooltip'\n\nconst Tooltip = lazy(() => import('./Tooltip').then(module => ({ default: module.Tooltip })))\n\nexport type Props = {\n /**\n * List of calendar entries. Each `Activity` object requires an ISO 8601\n * `date` string in the format `yyyy-MM-dd`, a `count` property with the\n * amount of tracked data, and a `level` property in the range `0-maxLevel`\n * to specify activity intensity. The `maxLevel` prop defaults to 4.\n *\n * Dates without corresponding entries are assumed to have no activity. This\n * allows you to set arbitrary start and end dates for the calendar by passing\n * empty entries as the first and last items.\n *\n * Example object:\n *\n * ```\n * {\n * date: \"2021-02-20\",\n * count: 16,\n * level: 3\n * }\n * ```\n */\n data: Array<Activity>\n /**\n * Margin between blocks in pixels.\n */\n blockMargin?: number\n /**\n * Border radius of blocks in pixels.\n */\n blockRadius?: number\n /**\n * Block size in pixels.\n */\n blockSize?: number\n /**\n * Use the `'light'` or `'dark'` color scheme instead of the system one.\n */\n colorScheme?: ColorScheme\n /**\n * Font size for text in pixels.\n */\n fontSize?: number\n /**\n * Localization strings for all calendar labels.\n *\n * `totalCount` supports the placeholders `{{count}}` and `{{year}}`.\n */\n labels?: Labels\n /**\n * Maximum activity level (zero-indexed). 4 by default, 0 means \"no activity\".\n */\n maxLevel?: number\n /**\n * Toggle to display the calendar loading state. The `data` property is\n * ignored if set.\n */\n loading?: boolean\n /**\n * Ref to access the calendar DOM node.\n */\n ref?: ForwardedRef<HTMLElement>\n /**\n * Render prop for calendar blocks (activities). For example, useful to\n * attach event handlers or to wrap the element with a link. Use\n * `React.cloneElement` to pass additional props to the element if necessary.\n */\n renderBlock?: (block: BlockElement, activity: Activity) => ReactElement\n /**\n * Render prop for color legend blocks. Use `React.cloneElement` to pass\n * additional props to the element if necessary.\n */\n renderColorLegend?: (block: BlockElement, level: number) => ReactElement\n /**\n * Toggle to hide the color legend below the calendar.\n */\n showColorLegend?: boolean\n /**\n * Toggle to hide the month labels above the calendar.\n */\n showMonthLabels?: boolean\n /**\n * Toggle to hide the total count below the calendar.\n */\n showTotalCount?: boolean\n /**\n * Toggle to show weekday labels left to the calendar.\n * Alternatively, provide an array of ISO 8601 weekday names to display.\n * Example: `['mon', 'wed', 'fri']`.\n */\n showWeekdayLabels?: boolean | Array<DayName>\n /**\n * Style object to pass to the component container.\n */\n style?: CSSProperties\n /**\n * Set the calendar colors for the light and dark color schemes. Provide\n * all colors per scheme explicitly (5 by default) or specify exactly two colors\n * (the lowest and highest intensity) to calculate a single-hue scale. The\n * number of colors is controlled by the `maxLevel` property. Colors can be\n * specified in any valid CSS format.\n *\n * At least one scheme's colors must be set. If undefined, the default\n * theme is used. By default, the calendar selects the current system color\n * scheme, but you can enforce a specific scheme with the `colorScheme` prop.\n *\n * Example:\n *\n * ```tsx\n * <ActivityCalendar\n * data={data}\n * theme={{\n * light: ['hsl(0, 0%, 92%)', 'firebrick'],\n * dark: ['#333', 'rgb(214, 16, 174)'],\n * }}\n * />\n * ```\n *\n */\n theme?: ThemeInput\n /**\n * Tooltips to display when hovering over activity blocks or the color legend\n * below the calendar. See the story for details about tooltip configuration.\n */\n tooltips?: {\n activity?: TooltipConfig & {\n text: (activity: Activity) => string\n }\n colorLegend?: TooltipConfig & {\n text: (level: number) => string\n }\n }\n /**\n * Index of day to be used as start of week. 0 represents Sunday.\n */\n weekStart?: DayIndex\n}\n\nexport const ActivityCalendar = forwardRef<HTMLElement, Props>(\n (\n {\n data: activities,\n blockMargin = 4,\n blockRadius = 2,\n blockSize = 12,\n colorScheme: colorSchemeProp = undefined,\n fontSize = 14,\n labels: labelsProp = undefined,\n loading = false,\n maxLevel = 4,\n renderBlock = undefined,\n renderColorLegend = undefined,\n showColorLegend = true,\n showMonthLabels = true,\n showTotalCount = true,\n showWeekdayLabels = false,\n style: styleProp = {},\n theme: themeProp = undefined,\n tooltips = {},\n weekStart = 0, // Sunday\n },\n ref,\n ) => {\n const [isClient, setIsClient] = useState(false)\n useEffect(() => {\n setIsClient(true)\n }, [])\n\n maxLevel = Math.max(1, maxLevel)\n\n const theme = createTheme(themeProp, maxLevel + 1)\n const systemColorScheme = useColorScheme()\n const colorScheme = colorSchemeProp ?? systemColorScheme\n const colorScale = theme[colorScheme]\n\n const animationLoaded = useLoadingAnimation(colorScale[0] as string, colorScheme)\n const useAnimation = !usePrefersReducedMotion()\n\n if (loading) {\n // Only show the loading state once the CSS animation has been injected\n // to avoid a flash of white with dark backgrounds.\n if (useAnimation && !animationLoaded) {\n return null\n }\n\n activities = generateEmptyData()\n }\n\n validateActivities(activities, maxLevel)\n\n const firstActivity = activities[0] as Activity\n const year = getYear(parseISO(firstActivity.date))\n const weeks = groupByWeeks(activities, weekStart)\n\n const labels = Object.assign({}, DEFAULT_LABELS, labelsProp)\n const labelHeight = showMonthLabels ? fontSize + LABEL_MARGIN : 0\n\n const weekdayLabels = initWeekdayLabels(showWeekdayLabels, weekStart)\n\n // Must be calculated on the client, or SSR hydration errors will occur\n // because server and client HTML would not match.\n const weekdayLabelOffset =\n isClient && weekdayLabels.shouldShow\n ? maxWeekdayLabelWidth(labels.weekdays, weekdayLabels, fontSize) + LABEL_MARGIN\n : undefined\n\n function getDimensions() {\n return {\n width: weeks.length * (blockSize + blockMargin) - blockMargin,\n height: labelHeight + (blockSize + blockMargin) * 7 - blockMargin,\n }\n }\n\n function renderCalendar() {\n return weeks\n .map((week, weekIndex) =>\n week.map((activity, dayIndex) => {\n if (!activity) {\n return null\n }\n\n const loadingAnimation =\n loading && useAnimation\n ? {\n animation: `${loadingAnimationName} 1.75s ease-in-out infinite`,\n animationDelay: `${weekIndex * 20 + dayIndex * 20}ms`,\n }\n : undefined\n\n const block = (\n <rect\n x={0}\n y={labelHeight + (blockSize + blockMargin) * dayIndex}\n width={blockSize}\n height={blockSize}\n rx={blockRadius}\n ry={blockRadius}\n fill={colorScale[activity.level]}\n data-date={activity.date}\n data-level={activity.level}\n style={{\n ...styles.rect(colorScheme),\n ...loadingAnimation,\n }}\n />\n )\n\n const renderedBlock = renderBlock ? renderBlock(block, activity) : block\n\n return (\n <Fragment key={activity.date}>\n {tooltips.activity ? (\n <Suspense fallback={renderedBlock}>\n <Tooltip\n text={tooltips.activity.text(activity)}\n colorScheme={colorScheme}\n placement={tooltips.activity.placement ?? 'top'}\n hoverRestMs={tooltips.activity.hoverRestMs}\n offset={tooltips.activity.offset}\n transitionStyles={tooltips.activity.transitionStyles}\n withArrow={tooltips.activity.withArrow}\n >\n {renderedBlock}\n </Tooltip>\n </Suspense>\n ) : (\n renderedBlock\n )}\n </Fragment>\n )\n }),\n )\n .map((week, x) => (\n <g key={x} transform={`translate(${(blockSize + blockMargin) * x}, 0)`}>\n {week}\n </g>\n ))\n }\n\n function renderFooter() {\n if (!showTotalCount && !showColorLegend) {\n return null\n }\n\n const totalCount = activities.reduce((sum, activity) => sum + activity.count, 0)\n\n return (\n <footer\n className={getClassName('footer')}\n style={{ ...styles.footer.container, marginLeft: weekdayLabelOffset }}\n >\n {/* Placeholder */}\n {loading && <div> </div>}\n\n {!loading && showTotalCount && (\n <div className={getClassName('count')}>\n {labels.totalCount\n ? labels.totalCount\n .replace('{{count}}', String(totalCount))\n .replace('{{year}}', String(year))\n : `${totalCount} activities in ${year}`}\n </div>\n )}\n\n {!loading && showColorLegend && (\n <div className={getClassName('legend-colors')} style={styles.footer.legend}>\n <span style={{ marginRight: '0.4em' }}>{labels.legend.less}</span>\n {range(maxLevel + 1).map(level => {\n const colorLegend = (\n <svg width={blockSize} height={blockSize} key={level}>\n <rect\n width={blockSize}\n height={blockSize}\n fill={colorScale[level]}\n rx={blockRadius}\n ry={blockRadius}\n style={styles.rect(colorScheme)}\n />\n </svg>\n )\n\n const renderedColorLegend = renderColorLegend\n ? renderColorLegend(colorLegend, level)\n : colorLegend\n\n return (\n <Fragment key={level}>\n {tooltips.colorLegend ? (\n <Suspense fallback={renderedColorLegend}>\n <Tooltip\n text={tooltips.colorLegend.text(level)}\n colorScheme={colorScheme}\n placement={tooltips.colorLegend.placement ?? 'bottom'}\n hoverRestMs={tooltips.colorLegend.hoverRestMs}\n offset={tooltips.colorLegend.offset}\n transitionStyles={tooltips.colorLegend.transitionStyles}\n withArrow={tooltips.colorLegend.withArrow}\n >\n {renderedColorLegend}\n </Tooltip>\n </Suspense>\n ) : (\n renderedColorLegend\n )}\n </Fragment>\n )\n })}\n <span style={{ marginLeft: '0.4em' }}>{labels.legend.more}</span>\n </div>\n )}\n </footer>\n )\n }\n\n function renderWeekdayLabels() {\n if (!weekdayLabels.shouldShow) {\n return null\n }\n\n return (\n <g className={getClassName('legend-weekday')}>\n {range(7).map(index => {\n const dayIndex = ((index + weekStart) % 7) as DayIndex\n\n if (!weekdayLabels.byDayIndex(dayIndex)) {\n return null\n }\n\n return (\n <text\n x={-LABEL_MARGIN}\n y={labelHeight + (blockSize + blockMargin) * index + blockSize / 2}\n dominantBaseline=\"central\"\n textAnchor=\"end\"\n fill=\"currentColor\"\n key={index}\n >\n {labels.weekdays[dayIndex]}\n </text>\n )\n })}\n </g>\n )\n }\n\n function renderMonthLabels() {\n if (!showMonthLabels) {\n return null\n }\n\n return (\n <g className={getClassName('legend-month')}>\n {getMonthLabels(weeks, labels.months).map(({ label, weekIndex }) => (\n <text\n x={(blockSize + blockMargin) * weekIndex}\n y={0}\n dominantBaseline=\"hanging\"\n fill=\"currentColor\"\n key={weekIndex}\n >\n {label}\n </text>\n ))}\n </g>\n )\n }\n\n const { width, height } = getDimensions()\n\n return (\n <article\n ref={ref}\n className={NAMESPACE}\n style={{ ...styleProp, ...styles.container(fontSize) }}\n >\n <div className={getClassName('scroll-container')} style={styles.scrollContainer(fontSize)}>\n <svg\n width={width}\n height={height}\n viewBox={`0 0 ${width} ${height}`}\n className={getClassName('calendar')}\n style={{ ...styles.calendar, marginLeft: weekdayLabelOffset }}\n >\n {!loading && renderWeekdayLabels()}\n {!loading && renderMonthLabels()}\n {renderCalendar()}\n </svg>\n </div>\n {renderFooter()}\n </article>\n )\n },\n)\n\nActivityCalendar.displayName = 'ActivityCalendar'\n"],"names":["NAMESPACE","LABEL_MARGIN","DEFAULT_MONTH_LABELS","DEFAULT_LABELS","months","weekdays","totalCount","legend","less","more","useColorScheme","colorScheme","setColorScheme","useState","onChange","event","matches","useEffect","mediaQuery","window","matchMedia","addEventListener","removeEventListener","loadingAnimationName","useLoadingAnimation","zeroColor","loaded","setLoaded","colorLoading","colorActive","style","document","createElement","innerHTML","handleLoad","head","appendChild","removeChild","query","usePrefersReducedMotion","prefersReducedMotion","setPrefersReducedMotion","validateActivities","activities","maxLevel","length","Error","date","level","count","isValid","parseISO","RangeError","groupByWeeks","weekStart","normalizedActivities","fillHoles","firstActivity","firstDate","firstCalendarDate","getDay","subWeeks","nextDay","paddedActivities","Array","differenceInCalendarDays","fill","undefined","numberOfWeeks","Math","ceil","range","map","weekIndex","slice","calendar","Map","a","lastActivity","eachDayOfInterval","start","end","day","formatISO","representation","has","get","getClassName","element","n","keys","generateEmptyData","year","Date","getFullYear","days","getMonthLabels","weeks","monthNames","reduce","labels","week","find","activity","month","getMonth","monthName","toLocaleString","prevLabel","label","filter","index","minWeeks","maxWeekdayLabelWidth","showWeekdayLabel","fontSize","maxWidth","byDayIndex","max","calcTextDimensions","width","text","height","namespace","svg","createElementNS","position","visibility","fontFamily","getComputedStyle","body","textNode","textContent","boundingBox","getBBox","initWeekdayLabels","input","shouldShow","indexed","name","dayNameToIndex","toLowerCase","sun","mon","tue","wed","thu","fri","sat","createTheme","steps","defaultTheme","createDefaultTheme","validateThemeInput","light","dark","isPair","calcColorScale","maxLevelHint","c","CSS","supports","i","pos","parseFloat","toFixed","val","styles","container","display","flexDirection","gap","scrollContainer","overflowX","overflowY","paddingTop","overflow","rect","stroke","footer","flexWrap","whiteSpace","marginLeft","alignItems","Tooltip","lazy","then","module","default","ActivityCalendar","forwardRef","data","blockMargin","blockRadius","blockSize","colorSchemeProp","labelsProp","loading","renderBlock","renderColorLegend","showColorLegend","showMonthLabels","showTotalCount","showWeekdayLabels","styleProp","theme","themeProp","tooltips","ref","isClient","setIsClient","systemColorScheme","colorScale","animationLoaded","useAnimation","getYear","Object","assign","labelHeight","weekdayLabels","weekdayLabelOffset","getDimensions","renderCalendar","dayIndex","loadingAnimation","animation","animationDelay","block","_jsx","x","y","rx","ry","renderedBlock","Fragment","children","Suspense","fallback","placement","hoverRestMs","offset","transitionStyles","withArrow","transform","renderFooter","sum","_jsxs","className","replace","String","marginRight","colorLegend","renderedColorLegend","renderWeekdayLabels","dominantBaseline","textAnchor","renderMonthLabels","viewBox","displayName"],"mappings":"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"} |
| 'use client'; | ||
| import { useState, useRef, cloneElement } from 'react'; | ||
| import { useFloating, autoUpdate, flip, offset, shift, arrow, useHover, useDismiss, useRole, useInteractions, useTransitionStyles, FloatingPortal, FloatingArrow } from '@floating-ui/react'; | ||
| import { g as getClassName } from './index-w4bahFWW.js'; | ||
| import { jsxs, Fragment, jsx } from 'react/jsx-runtime'; | ||
| import 'date-fns'; | ||
| function Tooltip({ | ||
| children, | ||
| text, | ||
| colorScheme, | ||
| placement, | ||
| offset: offsetProp = 4, | ||
| transitionStyles: transitionStylesProp, | ||
| hoverRestMs = 150, | ||
| withArrow = false | ||
| }) { | ||
| const [isOpen, setIsOpen] = useState(false); | ||
| const arrowRef = useRef(null); | ||
| const { | ||
| context, | ||
| refs, | ||
| floatingStyles | ||
| } = useFloating({ | ||
| open: isOpen, | ||
| onOpenChange: setIsOpen, | ||
| placement, | ||
| middleware: [flip(), offset(offsetProp), shift({ | ||
| padding: 8 | ||
| }), withArrow ? arrow({ | ||
| element: arrowRef | ||
| }) : null // eslint-disable-line react-hooks/refs | ||
| ], | ||
| whileElementsMounted: autoUpdate | ||
| }); | ||
| const hover = useHover(context, { | ||
| restMs: hoverRestMs | ||
| }); | ||
| const dismiss = useDismiss(context); | ||
| const role = useRole(context, { | ||
| role: 'tooltip' | ||
| }); | ||
| const { | ||
| getReferenceProps, | ||
| getFloatingProps | ||
| } = useInteractions([hover, dismiss, role]); | ||
| const { | ||
| isMounted, | ||
| styles: transitionStyles | ||
| } = useTransitionStyles(context, transitionStylesProp); | ||
| return /*#__PURE__*/jsxs(Fragment, { | ||
| children: [/*#__PURE__*/cloneElement(children, { | ||
| ref: refs.setReference, | ||
| ...getReferenceProps() | ||
| }), /*#__PURE__*/jsx(FloatingPortal, { | ||
| children: isMounted && /*#__PURE__*/jsxs("div", { | ||
| ref: refs.setFloating, | ||
| className: getClassName('tooltip'), | ||
| style: { | ||
| ...floatingStyles, | ||
| ...transitionStyles | ||
| }, | ||
| "data-color-scheme": colorScheme, | ||
| ...getFloatingProps(), | ||
| children: [text, withArrow && /*#__PURE__*/jsx(FloatingArrow, { | ||
| ref: arrowRef, | ||
| context: context, | ||
| className: getClassName('tooltip-arrow') | ||
| })] | ||
| }) | ||
| })] | ||
| }); | ||
| } | ||
| export { Tooltip }; | ||
| //# sourceMappingURL=Tooltip-CX2cJQ7a.js.map |
| {"version":3,"file":"Tooltip-CX2cJQ7a.js","sources":["../../src/components/Tooltip.tsx"],"sourcesContent":["'use client'\n\nimport { cloneElement, useRef, useState, type ReactElement, type Ref } from 'react'\nimport {\n arrow,\n autoUpdate,\n flip,\n FloatingArrow,\n FloatingPortal,\n offset,\n shift,\n useDismiss,\n useFloating,\n useHover,\n useInteractions,\n useRole,\n useTransitionStyles,\n type OffsetOptions,\n type Placement,\n type UseHoverProps,\n type UseTransitionStylesProps,\n} from '@floating-ui/react'\nimport { getClassName } from '../lib/calendar'\nimport type { ColorScheme } from '../types'\n\nexport type TooltipConfig = {\n placement?: Placement\n offset?: OffsetOptions\n transitionStyles?: UseTransitionStylesProps\n hoverRestMs?: UseHoverProps['restMs']\n withArrow?: boolean\n}\n\nexport type TooltipProps = TooltipConfig & {\n children: ReactElement<{ ref: Ref<unknown> }>\n text: string\n colorScheme: ColorScheme\n}\n\nexport function Tooltip({\n children,\n text,\n colorScheme,\n placement,\n offset: offsetProp = 4,\n transitionStyles: transitionStylesProp,\n hoverRestMs = 150,\n withArrow = false,\n}: TooltipProps) {\n const [isOpen, setIsOpen] = useState(false)\n const arrowRef = useRef(null)\n\n const { context, refs, floatingStyles } = useFloating({\n open: isOpen,\n onOpenChange: setIsOpen,\n placement,\n middleware: [\n flip(),\n offset(offsetProp),\n shift({ padding: 8 }),\n withArrow ? arrow({ element: arrowRef }) : null, // eslint-disable-line react-hooks/refs\n ],\n whileElementsMounted: autoUpdate,\n })\n\n const hover = useHover(context, { restMs: hoverRestMs })\n const dismiss = useDismiss(context)\n const role = useRole(context, { role: 'tooltip' })\n\n const { getReferenceProps, getFloatingProps } = useInteractions([hover, dismiss, role])\n\n const { isMounted, styles: transitionStyles } = useTransitionStyles(context, transitionStylesProp)\n\n return (\n <>\n {cloneElement(children, { ref: refs.setReference, ...getReferenceProps() })}\n {\n <FloatingPortal>\n {isMounted && (\n <div\n ref={refs.setFloating}\n className={getClassName('tooltip')}\n style={{ ...floatingStyles, ...transitionStyles }}\n data-color-scheme={colorScheme}\n {...getFloatingProps()}\n >\n {text}\n {withArrow && (\n <FloatingArrow\n ref={arrowRef}\n context={context}\n className={getClassName('tooltip-arrow')}\n />\n )}\n </div>\n )}\n </FloatingPortal>\n }\n </>\n )\n}\n"],"names":["Tooltip","children","text","colorScheme","placement","offset","offsetProp","transitionStyles","transitionStylesProp","hoverRestMs","withArrow","isOpen","setIsOpen","useState","arrowRef","useRef","context","refs","floatingStyles","useFloating","open","onOpenChange","middleware","flip","shift","padding","arrow","element","whileElementsMounted","autoUpdate","hover","useHover","restMs","dismiss","useDismiss","role","useRole","getReferenceProps","getFloatingProps","useInteractions","isMounted","styles","useTransitionStyles","_jsxs","_Fragment","cloneElement","ref","setReference","_jsx","FloatingPortal","setFloating","className","getClassName","style","FloatingArrow"],"mappings":";;;;;;;AAuCO,SAASA,OAAOA,CAAC;EACtBC,QAAQ;EACRC,IAAI;EACJC,WAAW;EACXC,SAAS;EACTC,MAAM,EAAEC,UAAU,GAAG,CAAC;AACtBC,EAAAA,gBAAgB,EAAEC,oBAAoB;AACtCC,EAAAA,WAAW,GAAG,GAAG;AACjBC,EAAAA,SAAS,GAAG;AACA,CAAC,EAAE;EACf,MAAM,CAACC,MAAM,EAAEC,SAAS,CAAC,GAAGC,QAAQ,CAAC,KAAK,CAAC;AAC3C,EAAA,MAAMC,QAAQ,GAAGC,MAAM,CAAC,IAAI,CAAC;EAE7B,MAAM;IAAEC,OAAO;IAAEC,IAAI;AAAEC,IAAAA;GAAgB,GAAGC,WAAW,CAAC;AACpDC,IAAAA,IAAI,EAAET,MAAM;AACZU,IAAAA,YAAY,EAAET,SAAS;IACvBR,SAAS;AACTkB,IAAAA,UAAU,EAAE,CACVC,IAAI,EAAE,EACNlB,MAAM,CAACC,UAAU,CAAC,EAClBkB,KAAK,CAAC;AAAEC,MAAAA,OAAO,EAAE;AAAE,KAAC,CAAC,EACrBf,SAAS,GAAGgB,KAAK,CAAC;AAAEC,MAAAA,OAAO,EAAEb;KAAU,CAAC,GAAG,IAAI;KAChD;AACDc,IAAAA,oBAAoB,EAAEC;AACxB,GAAC,CAAC;AAEF,EAAA,MAAMC,KAAK,GAAGC,QAAQ,CAACf,OAAO,EAAE;AAAEgB,IAAAA,MAAM,EAAEvB;AAAY,GAAC,CAAC;AACxD,EAAA,MAAMwB,OAAO,GAAGC,UAAU,CAAClB,OAAO,CAAC;AACnC,EAAA,MAAMmB,IAAI,GAAGC,OAAO,CAACpB,OAAO,EAAE;AAAEmB,IAAAA,IAAI,EAAE;AAAU,GAAC,CAAC;EAElD,MAAM;IAAEE,iBAAiB;AAAEC,IAAAA;GAAkB,GAAGC,eAAe,CAAC,CAACT,KAAK,EAAEG,OAAO,EAAEE,IAAI,CAAC,CAAC;EAEvF,MAAM;IAAEK,SAAS;AAAEC,IAAAA,MAAM,EAAElC;AAAiB,GAAC,GAAGmC,mBAAmB,CAAC1B,OAAO,EAAER,oBAAoB,CAAC;EAElG,oBACEmC,IAAA,CAAAC,QAAA,EAAA;AAAA3C,IAAAA,QAAA,EAAA,cACG4C,YAAY,CAAC5C,QAAQ,EAAE;MAAE6C,GAAG,EAAE7B,IAAI,CAAC8B,YAAY;AAAE,MAAA,GAAGV,iBAAiB;AAAG,KAAC,CAAC,eAEzEW,GAAA,CAACC,cAAc,EAAA;MAAAhD,QAAA,EACZuC,SAAS,iBACRG,IAAA,CAAA,KAAA,EAAA;QACEG,GAAG,EAAE7B,IAAI,CAACiC,WAAY;AACtBC,QAAAA,SAAS,EAAEC,YAAY,CAAC,SAAS,CAAE;AACnCC,QAAAA,KAAK,EAAE;AAAE,UAAA,GAAGnC,cAAc;UAAE,GAAGX;SAAmB;AAClD,QAAA,mBAAA,EAAmBJ,WAAY;QAAA,GAC3BmC,gBAAgB,EAAE;AAAArC,QAAAA,QAAA,GAErBC,IAAI,EACJQ,SAAS,iBACRsC,GAAA,CAACM,aAAa,EAAA;AACZR,UAAAA,GAAG,EAAEhC,QAAS;AACdE,UAAAA,OAAO,EAAEA,OAAQ;UACjBmC,SAAS,EAAEC,YAAY,CAAC,eAAe;AAAE,SAC1C,CACF;OACE;AACN,KACa,CAAC;AAAA,GAEnB,CAAC;AAEP;;;;"} |
+1
-1
| 'use client'; | ||
| export { A as ActivityCalendar } from './chunks/index-BLMVjjY9.js'; | ||
| export { A as ActivityCalendar } from './chunks/index-w4bahFWW.js'; | ||
| import 'react'; | ||
@@ -4,0 +4,0 @@ import 'date-fns'; |
+1
-1
| { | ||
| "name": "react-activity-calendar", | ||
| "version": "3.0.4", | ||
| "version": "3.0.5", | ||
| "description": "React component to display activity data in calendar", | ||
@@ -5,0 +5,0 @@ "author": "Jonathan Gruber <gruberjonathan@gmail.com>", |
@@ -5,4 +5,3 @@ import { useEffect, useState } from 'react' | ||
| export function useColorScheme() { | ||
| const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)') | ||
| const [colorScheme, setColorScheme] = useState<ColorScheme>(mediaQuery.matches ? 'dark' : 'light') | ||
| const [colorScheme, setColorScheme] = useState<ColorScheme>('light') | ||
@@ -14,2 +13,7 @@ const onChange = (event: MediaQueryListEvent) => { | ||
| useEffect(() => { | ||
| const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)') | ||
| // eslint-disable-next-line react-hooks/set-state-in-effect | ||
| setColorScheme(mediaQuery.matches ? 'dark' : 'light') | ||
| mediaQuery.addEventListener('change', onChange) | ||
@@ -20,5 +24,5 @@ | ||
| } | ||
| }, [mediaQuery]) | ||
| }, []) | ||
| return colorScheme | ||
| } |
@@ -6,6 +6,10 @@ import { useEffect, useState } from 'react' | ||
| export function usePrefersReducedMotion() { | ||
| const mediaQuery = window.matchMedia(query) | ||
| const [prefersReducedMotion, setPrefersReducedMotion] = useState(mediaQuery.matches) | ||
| const [prefersReducedMotion, setPrefersReducedMotion] = useState(true) | ||
| useEffect(() => { | ||
| const mediaQuery = window.matchMedia(query) | ||
| // eslint-disable-next-line react-hooks/set-state-in-effect | ||
| setPrefersReducedMotion(mediaQuery.matches) | ||
| const onChange = (event: MediaQueryListEvent) => { | ||
@@ -20,5 +24,5 @@ setPrefersReducedMotion(event.matches) | ||
| } | ||
| }, [mediaQuery]) | ||
| }, []) | ||
| return prefersReducedMotion | ||
| } |
| 'use client'; | ||
| import { useState, useEffect, forwardRef, Fragment, Suspense, lazy } from 'react'; | ||
| import { eachDayOfInterval, formatISO, isValid, parseISO, getDay, subWeeks, nextDay, differenceInCalendarDays, getMonth, getYear } from 'date-fns'; | ||
| import { jsxs, jsx } from 'react/jsx-runtime'; | ||
| const NAMESPACE = 'react-activity-calendar'; | ||
| const LABEL_MARGIN = 8; // px | ||
| const DEFAULT_MONTH_LABELS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; | ||
| const DEFAULT_LABELS = { | ||
| months: DEFAULT_MONTH_LABELS, | ||
| weekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], | ||
| totalCount: '{{count}} activities in {{year}}', | ||
| legend: { | ||
| less: 'Less', | ||
| more: 'More' | ||
| } | ||
| }; | ||
| function useColorScheme() { | ||
| const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); | ||
| const [colorScheme, setColorScheme] = useState(mediaQuery.matches ? 'dark' : 'light'); | ||
| const onChange = event => { | ||
| setColorScheme(event.matches ? 'dark' : 'light'); | ||
| }; | ||
| useEffect(() => { | ||
| mediaQuery.addEventListener('change', onChange); | ||
| return () => { | ||
| mediaQuery.removeEventListener('change', onChange); | ||
| }; | ||
| }, [mediaQuery]); | ||
| return colorScheme; | ||
| } | ||
| const loadingAnimationName = `${NAMESPACE}--loading-animation`; | ||
| function useLoadingAnimation(zeroColor, colorScheme) { | ||
| const [loaded, setLoaded] = useState(false); | ||
| useEffect(() => { | ||
| const colorLoading = `oklab(from ${zeroColor} l a b)`; | ||
| const colorActive = colorScheme === 'light' ? `oklab(from ${zeroColor} calc(l * 0.96) a b)` : `oklab(from ${zeroColor} calc(l * 1.08) a b)`; | ||
| const style = document.createElement('style'); | ||
| style.innerHTML = ` | ||
| @keyframes ${loadingAnimationName} { | ||
| 0% { | ||
| fill: ${colorLoading}; | ||
| } | ||
| 50% { | ||
| fill: ${colorActive}; | ||
| } | ||
| 100% { | ||
| fill: ${colorLoading}; | ||
| } | ||
| } | ||
| `; | ||
| const handleLoad = () => { | ||
| setLoaded(true); | ||
| }; | ||
| document.head.appendChild(style); | ||
| style.addEventListener('load', handleLoad); | ||
| return () => { | ||
| document.head.removeChild(style); | ||
| style.removeEventListener('load', handleLoad); | ||
| setLoaded(false); | ||
| }; | ||
| }, [zeroColor, colorScheme]); | ||
| return loaded; | ||
| } | ||
| const query = '(prefers-reduced-motion: reduce)'; | ||
| function usePrefersReducedMotion() { | ||
| const mediaQuery = window.matchMedia(query); | ||
| const [prefersReducedMotion, setPrefersReducedMotion] = useState(mediaQuery.matches); | ||
| useEffect(() => { | ||
| const onChange = event => { | ||
| setPrefersReducedMotion(event.matches); | ||
| }; | ||
| mediaQuery.addEventListener('change', onChange); | ||
| return () => { | ||
| mediaQuery.removeEventListener('change', onChange); | ||
| }; | ||
| }, [mediaQuery]); | ||
| return prefersReducedMotion; | ||
| } | ||
| function validateActivities(activities, maxLevel) { | ||
| if (activities.length === 0) { | ||
| throw new Error('Activity data must not be empty.'); | ||
| } | ||
| for (const { | ||
| date, | ||
| level, | ||
| count | ||
| } of activities) { | ||
| if (!isValid(parseISO(date))) { | ||
| throw new Error(`Activity date '${date}' is not a valid ISO 8601 date string.`); | ||
| } | ||
| if (count < 0) { | ||
| throw new RangeError(`Activity count must not be negative, found ${count}.`); | ||
| } | ||
| if (level < 0 || level > maxLevel) { | ||
| throw new RangeError(`Activity level ${level} for ${date} is out of range. It must be between 0 and ${maxLevel}.`); | ||
| } | ||
| } | ||
| } | ||
| function groupByWeeks(activities, weekStart = 0 // 0 = Sunday | ||
| ) { | ||
| const normalizedActivities = fillHoles(activities); | ||
| // Determine the first date of the calendar. If the first date is not the | ||
| // passed weekday, the respective weekday one week earlier is used. | ||
| const firstActivity = normalizedActivities[0]; | ||
| const firstDate = parseISO(firstActivity.date); | ||
| const firstCalendarDate = getDay(firstDate) === weekStart ? firstDate : subWeeks(nextDay(firstDate, weekStart), 1); | ||
| // To correctly group activities by week, it is necessary to left-pad the list | ||
| // because the first date might not be the set start weekday. | ||
| const paddedActivities = [...Array(differenceInCalendarDays(firstDate, firstCalendarDate)).fill(undefined), ...normalizedActivities]; | ||
| const numberOfWeeks = Math.ceil(paddedActivities.length / 7); | ||
| // Finally, group activities by week | ||
| return range(numberOfWeeks).map(weekIndex => paddedActivities.slice(weekIndex * 7, weekIndex * 7 + 7)); | ||
| } | ||
| /** | ||
| * The calendar expects a continuous sequence of days, | ||
| * so fill gaps with empty activity data. | ||
| */ | ||
| function fillHoles(activities) { | ||
| const calendar = new Map(activities.map(a => [a.date, a])); | ||
| const firstActivity = activities[0]; | ||
| const lastActivity = activities[activities.length - 1]; | ||
| return eachDayOfInterval({ | ||
| start: parseISO(firstActivity.date), | ||
| end: parseISO(lastActivity.date) | ||
| }).map(day => { | ||
| const date = formatISO(day, { | ||
| representation: 'date' | ||
| }); | ||
| if (calendar.has(date)) { | ||
| return calendar.get(date); | ||
| } | ||
| return { | ||
| date, | ||
| count: 0, | ||
| level: 0 | ||
| }; | ||
| }); | ||
| } | ||
| /** | ||
| * Following the BEM (block, element, modifier) naming convention | ||
| * https://getbem.com/naming/ | ||
| */ | ||
| function getClassName(element) { | ||
| return `${NAMESPACE}__${element}`; | ||
| } | ||
| function range(n) { | ||
| return [...Array(n).keys()]; | ||
| } | ||
| function generateEmptyData() { | ||
| const year = new Date().getFullYear(); | ||
| const days = eachDayOfInterval({ | ||
| start: new Date(year, 0, 1), | ||
| end: new Date(year, 11, 31) | ||
| }); | ||
| return days.map(date => ({ | ||
| date: formatISO(date, { | ||
| representation: 'date' | ||
| }), | ||
| count: 0, | ||
| level: 0 | ||
| })); | ||
| } | ||
| function getMonthLabels(weeks, monthNames = DEFAULT_MONTH_LABELS) { | ||
| return weeks.reduce((labels, week, weekIndex) => { | ||
| const firstActivity = week.find(activity => activity !== undefined); | ||
| if (!firstActivity) { | ||
| throw new Error(`Unexpected error: Week ${weekIndex + 1} is empty.`); | ||
| } | ||
| const month = monthNames[getMonth(parseISO(firstActivity.date))]; | ||
| if (!month) { | ||
| const monthName = new Date(firstActivity.date).toLocaleString('en-US', { | ||
| month: 'short' | ||
| }); | ||
| throw new Error(`Unexpected error: undefined month label for ${monthName}.`); | ||
| } | ||
| const prevLabel = labels[labels.length - 1]; | ||
| if (weekIndex === 0 || prevLabel?.label !== month) { | ||
| return [...labels, { | ||
| weekIndex, | ||
| label: month | ||
| }]; | ||
| } | ||
| return labels; | ||
| }, []).filter(({ | ||
| weekIndex | ||
| }, index, labels) => { | ||
| // Labels should only be shown if there is "enough" space (data). | ||
| // This is a naive implementation that does not take the block size, | ||
| // font size, etc. into account. | ||
| const minWeeks = 3; | ||
| // Skip the first month label if there is not enough space for the next one. | ||
| if (index === 0) { | ||
| return labels[1] && labels[1].weekIndex - weekIndex >= minWeeks; | ||
| } | ||
| // Skip the last month label if there is not enough data in that month | ||
| // to avoid overflowing the calendar on the right. | ||
| if (index === labels.length - 1) { | ||
| return weeks.slice(weekIndex).length >= minWeeks; | ||
| } | ||
| return true; | ||
| }); | ||
| } | ||
| function maxWeekdayLabelWidth(labels, showWeekdayLabel, fontSize) { | ||
| if (labels.length !== 7) { | ||
| throw new Error('Exactly 7 labels, one for each weekday must be passed.'); | ||
| } | ||
| return labels.reduce((maxWidth, label, index) => showWeekdayLabel.byDayIndex(index) ? Math.max(maxWidth, Math.ceil(calcTextDimensions(label, fontSize).width)) : maxWidth, 0); | ||
| } | ||
| function calcTextDimensions(text, fontSize) { | ||
| if (typeof document === 'undefined' || typeof window === 'undefined') { | ||
| return { | ||
| width: 0, | ||
| height: 0 | ||
| }; | ||
| } | ||
| if (fontSize < 1) { | ||
| throw new RangeError('fontSize must be positive'); | ||
| } | ||
| if (text.length === 0) { | ||
| return { | ||
| width: 0, | ||
| height: 0 | ||
| }; | ||
| } | ||
| const namespace = 'http://www.w3.org/2000/svg'; | ||
| const svg = document.createElementNS(namespace, 'svg'); | ||
| svg.style.position = 'absolute'; | ||
| svg.style.visibility = 'hidden'; | ||
| svg.style.fontFamily = window.getComputedStyle(document.body).fontFamily; | ||
| svg.style.fontSize = `${fontSize}px`; | ||
| const textNode = document.createElementNS(namespace, 'text'); | ||
| textNode.textContent = text; | ||
| svg.appendChild(textNode); | ||
| document.body.appendChild(svg); | ||
| const boundingBox = textNode.getBBox(); | ||
| document.body.removeChild(svg); | ||
| return { | ||
| width: boundingBox.width, | ||
| height: boundingBox.height | ||
| }; | ||
| } | ||
| function initWeekdayLabels(input, weekStart) { | ||
| if (!input) return { | ||
| byDayIndex: () => false, | ||
| shouldShow: false | ||
| }; | ||
| // Default: Show every second day of the week. | ||
| if (input === true) { | ||
| return { | ||
| byDayIndex: index => { | ||
| return (7 + index - weekStart) % 7 % 2 !== 0; | ||
| }, | ||
| shouldShow: true | ||
| }; | ||
| } | ||
| const indexed = []; | ||
| for (const name of input) { | ||
| const index = dayNameToIndex[name.toLowerCase()]; | ||
| indexed[index] = true; | ||
| } | ||
| return { | ||
| byDayIndex: index => indexed[index] ?? false, | ||
| shouldShow: input.length > 0 | ||
| }; | ||
| } | ||
| const dayNameToIndex = { | ||
| sun: 0, | ||
| mon: 1, | ||
| tue: 2, | ||
| wed: 3, | ||
| thu: 4, | ||
| fri: 5, | ||
| sat: 6 | ||
| }; | ||
| function createTheme(input, steps = 5) { | ||
| const defaultTheme = createDefaultTheme(steps); | ||
| if (input) { | ||
| validateThemeInput(input, steps); | ||
| input.light = input.light ?? defaultTheme.light; | ||
| input.dark = input.dark ?? defaultTheme.dark; | ||
| return { | ||
| light: isPair(input.light) ? calcColorScale(input.light, steps) : input.light, | ||
| dark: isPair(input.dark) ? calcColorScale(input.dark, steps) : input.dark | ||
| }; | ||
| } | ||
| return defaultTheme; | ||
| } | ||
| function createDefaultTheme(steps) { | ||
| return { | ||
| light: calcColorScale(['hsl(0, 0%, 92%)', 'hsl(0, 0%, 26%)'], steps), | ||
| dark: calcColorScale(['hsl(0, 0%, 22%)', 'hsl(0, 0%, 92%)'], steps) | ||
| }; | ||
| } | ||
| function validateThemeInput(input, steps) { | ||
| const maxLevelHint = 'The number of colors is controlled by the "maxLevel" property.'; | ||
| if (typeof input !== 'object' || input.light === undefined && input.dark === undefined) { | ||
| throw new Error(`The theme object must contain at least one of the fields "light" and "dark" with exactly 2 or ${steps} colors respectively. ${maxLevelHint}`); | ||
| } | ||
| if (input.light) { | ||
| const { | ||
| length | ||
| } = input.light; | ||
| if (length !== 2 && length !== steps) { | ||
| throw new Error(`theme.light must contain exactly 2 or ${steps} colors, ${length} passed. ${maxLevelHint}`); | ||
| } | ||
| for (const c of input.light) { | ||
| if (typeof window !== 'undefined' && !CSS.supports('color', c)) { | ||
| throw new Error(`Invalid color "${c}" passed. All CSS color formats are accepted.`); | ||
| } | ||
| } | ||
| } | ||
| if (input.dark) { | ||
| const { | ||
| length | ||
| } = input.dark; | ||
| if (length !== 2 && length !== steps) { | ||
| throw new Error(`theme.dark must contain exactly 2 or ${steps} colors, ${length} passed. ${maxLevelHint}`); | ||
| } | ||
| for (const c of input.dark) { | ||
| if (typeof window !== 'undefined' && !CSS.supports('color', c)) { | ||
| throw new Error(`Invalid color "${c}" passed. All CSS color formats are accepted.`); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| function calcColorScale([start, end], steps) { | ||
| return range(steps).map(i => { | ||
| // In the loading animation the zero color is used. | ||
| // However, Safari 16 crashes if a CSS color-mix expression like below is | ||
| // combined with relative color syntax to calculate a hue variation for the | ||
| // animation. Since the start and end colors do not need to be mixed, they | ||
| // can be returned directly to work around this issue. | ||
| switch (i) { | ||
| case 0: | ||
| return start; | ||
| case steps - 1: | ||
| return end; | ||
| default: | ||
| { | ||
| const pos = i / (steps - 1) * 100; | ||
| return `color-mix(in oklab, ${end} ${parseFloat(pos.toFixed(2))}%, ${start})`; | ||
| } | ||
| } | ||
| }); | ||
| } | ||
| function isPair(val) { | ||
| return val.length === 2; | ||
| } | ||
| const styles = { | ||
| container: fontSize => ({ | ||
| width: 'max-content', | ||
| // Calendar should not grow | ||
| maxWidth: '100%', | ||
| // Do not remove - parent might be a flexbox | ||
| display: 'flex', | ||
| flexDirection: 'column', | ||
| gap: '8px', | ||
| fontSize: `${fontSize}px` | ||
| }), | ||
| scrollContainer: fontSize => ({ | ||
| maxWidth: '100%', | ||
| overflowX: 'auto', | ||
| overflowY: 'hidden', | ||
| paddingTop: Math.ceil(0.1 * fontSize) // SVG <text> overflows in Firefox at y=0 | ||
| }), | ||
| calendar: { | ||
| display: 'block', | ||
| // SVGs are inline-block by default | ||
| overflow: 'visible' // Weekday labels are rendered left of the container | ||
| }, | ||
| rect: colorScheme => ({ | ||
| stroke: colorScheme === 'light' ? 'rgba(0, 0, 0, 0.08)' : 'rgba(255, 255, 255, 0.04)' | ||
| }), | ||
| footer: { | ||
| container: { | ||
| display: 'flex', | ||
| flexWrap: 'wrap', | ||
| gap: '4px 16px', | ||
| whiteSpace: 'nowrap' | ||
| }, | ||
| legend: { | ||
| marginLeft: 'auto', | ||
| display: 'flex', | ||
| alignItems: 'center', | ||
| gap: '3px' | ||
| } | ||
| } | ||
| }; | ||
| const Tooltip = /*#__PURE__*/lazy(() => import('./Tooltip-s91_dg_C.js').then(module => ({ | ||
| default: module.Tooltip | ||
| }))); | ||
| const ActivityCalendar = /*#__PURE__*/forwardRef(({ | ||
| data: activities, | ||
| blockMargin = 4, | ||
| blockRadius = 2, | ||
| blockSize = 12, | ||
| colorScheme: colorSchemeProp = undefined, | ||
| fontSize = 14, | ||
| labels: labelsProp = undefined, | ||
| loading = false, | ||
| maxLevel = 4, | ||
| renderBlock = undefined, | ||
| renderColorLegend = undefined, | ||
| showColorLegend = true, | ||
| showMonthLabels = true, | ||
| showTotalCount = true, | ||
| showWeekdayLabels = false, | ||
| style: styleProp = {}, | ||
| theme: themeProp = undefined, | ||
| tooltips = {}, | ||
| weekStart = 0 // Sunday | ||
| }, ref) => { | ||
| const [isClient, setIsClient] = useState(false); | ||
| useEffect(() => { | ||
| setIsClient(true); | ||
| }, []); | ||
| maxLevel = Math.max(1, maxLevel); | ||
| const theme = createTheme(themeProp, maxLevel + 1); | ||
| const systemColorScheme = useColorScheme(); | ||
| const colorScheme = colorSchemeProp ?? systemColorScheme; | ||
| const colorScale = theme[colorScheme]; | ||
| const animationLoaded = useLoadingAnimation(colorScale[0], colorScheme); | ||
| const useAnimation = !usePrefersReducedMotion(); | ||
| if (loading) { | ||
| // Only show the loading state once the CSS animation has been injected | ||
| // to avoid a flash of white with dark backgrounds. | ||
| if (useAnimation && !animationLoaded) { | ||
| return null; | ||
| } | ||
| activities = generateEmptyData(); | ||
| } | ||
| validateActivities(activities, maxLevel); | ||
| const firstActivity = activities[0]; | ||
| const year = getYear(parseISO(firstActivity.date)); | ||
| const weeks = groupByWeeks(activities, weekStart); | ||
| const labels = Object.assign({}, DEFAULT_LABELS, labelsProp); | ||
| const labelHeight = showMonthLabels ? fontSize + LABEL_MARGIN : 0; | ||
| const weekdayLabels = initWeekdayLabels(showWeekdayLabels, weekStart); | ||
| // Must be calculated on the client, or SSR hydration errors will occur | ||
| // because server and client HTML would not match. | ||
| const weekdayLabelOffset = isClient && weekdayLabels.shouldShow ? maxWeekdayLabelWidth(labels.weekdays, weekdayLabels, fontSize) + LABEL_MARGIN : undefined; | ||
| function getDimensions() { | ||
| return { | ||
| width: weeks.length * (blockSize + blockMargin) - blockMargin, | ||
| height: labelHeight + (blockSize + blockMargin) * 7 - blockMargin | ||
| }; | ||
| } | ||
| function renderCalendar() { | ||
| return weeks.map((week, weekIndex) => week.map((activity, dayIndex) => { | ||
| if (!activity) { | ||
| return null; | ||
| } | ||
| const loadingAnimation = loading && useAnimation ? { | ||
| animation: `${loadingAnimationName} 1.75s ease-in-out infinite`, | ||
| animationDelay: `${weekIndex * 20 + dayIndex * 20}ms` | ||
| } : undefined; | ||
| const block = /*#__PURE__*/jsx("rect", { | ||
| x: 0, | ||
| y: labelHeight + (blockSize + blockMargin) * dayIndex, | ||
| width: blockSize, | ||
| height: blockSize, | ||
| rx: blockRadius, | ||
| ry: blockRadius, | ||
| fill: colorScale[activity.level], | ||
| "data-date": activity.date, | ||
| "data-level": activity.level, | ||
| style: { | ||
| ...styles.rect(colorScheme), | ||
| ...loadingAnimation | ||
| } | ||
| }); | ||
| const renderedBlock = renderBlock ? renderBlock(block, activity) : block; | ||
| return /*#__PURE__*/jsx(Fragment, { | ||
| children: tooltips.activity ? /*#__PURE__*/jsx(Suspense, { | ||
| fallback: renderedBlock, | ||
| children: /*#__PURE__*/jsx(Tooltip, { | ||
| text: tooltips.activity.text(activity), | ||
| colorScheme: colorScheme, | ||
| placement: tooltips.activity.placement ?? 'top', | ||
| hoverRestMs: tooltips.activity.hoverRestMs, | ||
| offset: tooltips.activity.offset, | ||
| transitionStyles: tooltips.activity.transitionStyles, | ||
| withArrow: tooltips.activity.withArrow, | ||
| children: renderedBlock | ||
| }) | ||
| }) : renderedBlock | ||
| }, activity.date); | ||
| })).map((week, x) => /*#__PURE__*/jsx("g", { | ||
| transform: `translate(${(blockSize + blockMargin) * x}, 0)`, | ||
| children: week | ||
| }, x)); | ||
| } | ||
| function renderFooter() { | ||
| if (!showTotalCount && !showColorLegend) { | ||
| return null; | ||
| } | ||
| const totalCount = activities.reduce((sum, activity) => sum + activity.count, 0); | ||
| return /*#__PURE__*/jsxs("footer", { | ||
| className: getClassName('footer'), | ||
| style: { | ||
| ...styles.footer.container, | ||
| marginLeft: weekdayLabelOffset | ||
| }, | ||
| children: [loading && /*#__PURE__*/jsx("div", { | ||
| children: "\xA0" | ||
| }), !loading && showTotalCount && /*#__PURE__*/jsx("div", { | ||
| className: getClassName('count'), | ||
| children: labels.totalCount ? labels.totalCount.replace('{{count}}', String(totalCount)).replace('{{year}}', String(year)) : `${totalCount} activities in ${year}` | ||
| }), !loading && showColorLegend && /*#__PURE__*/jsxs("div", { | ||
| className: getClassName('legend-colors'), | ||
| style: styles.footer.legend, | ||
| children: [/*#__PURE__*/jsx("span", { | ||
| style: { | ||
| marginRight: '0.4em' | ||
| }, | ||
| children: labels.legend.less | ||
| }), range(maxLevel + 1).map(level => { | ||
| const colorLegend = /*#__PURE__*/jsx("svg", { | ||
| width: blockSize, | ||
| height: blockSize, | ||
| children: /*#__PURE__*/jsx("rect", { | ||
| width: blockSize, | ||
| height: blockSize, | ||
| fill: colorScale[level], | ||
| rx: blockRadius, | ||
| ry: blockRadius, | ||
| style: styles.rect(colorScheme) | ||
| }) | ||
| }, level); | ||
| const renderedColorLegend = renderColorLegend ? renderColorLegend(colorLegend, level) : colorLegend; | ||
| return /*#__PURE__*/jsx(Fragment, { | ||
| children: tooltips.colorLegend ? /*#__PURE__*/jsx(Suspense, { | ||
| fallback: renderedColorLegend, | ||
| children: /*#__PURE__*/jsx(Tooltip, { | ||
| text: tooltips.colorLegend.text(level), | ||
| colorScheme: colorScheme, | ||
| placement: tooltips.colorLegend.placement ?? 'bottom', | ||
| hoverRestMs: tooltips.colorLegend.hoverRestMs, | ||
| offset: tooltips.colorLegend.offset, | ||
| transitionStyles: tooltips.colorLegend.transitionStyles, | ||
| withArrow: tooltips.colorLegend.withArrow, | ||
| children: renderedColorLegend | ||
| }) | ||
| }) : renderedColorLegend | ||
| }, level); | ||
| }), /*#__PURE__*/jsx("span", { | ||
| style: { | ||
| marginLeft: '0.4em' | ||
| }, | ||
| children: labels.legend.more | ||
| })] | ||
| })] | ||
| }); | ||
| } | ||
| function renderWeekdayLabels() { | ||
| if (!weekdayLabels.shouldShow) { | ||
| return null; | ||
| } | ||
| return /*#__PURE__*/jsx("g", { | ||
| className: getClassName('legend-weekday'), | ||
| children: range(7).map(index => { | ||
| const dayIndex = (index + weekStart) % 7; | ||
| if (!weekdayLabels.byDayIndex(dayIndex)) { | ||
| return null; | ||
| } | ||
| return /*#__PURE__*/jsx("text", { | ||
| x: -LABEL_MARGIN, | ||
| y: labelHeight + (blockSize + blockMargin) * index + blockSize / 2, | ||
| dominantBaseline: "central", | ||
| textAnchor: "end", | ||
| fill: "currentColor", | ||
| children: labels.weekdays[dayIndex] | ||
| }, index); | ||
| }) | ||
| }); | ||
| } | ||
| function renderMonthLabels() { | ||
| if (!showMonthLabels) { | ||
| return null; | ||
| } | ||
| return /*#__PURE__*/jsx("g", { | ||
| className: getClassName('legend-month'), | ||
| children: getMonthLabels(weeks, labels.months).map(({ | ||
| label, | ||
| weekIndex | ||
| }) => /*#__PURE__*/jsx("text", { | ||
| x: (blockSize + blockMargin) * weekIndex, | ||
| y: 0, | ||
| dominantBaseline: "hanging", | ||
| fill: "currentColor", | ||
| children: label | ||
| }, weekIndex)) | ||
| }); | ||
| } | ||
| const { | ||
| width, | ||
| height | ||
| } = getDimensions(); | ||
| return /*#__PURE__*/jsxs("article", { | ||
| ref: ref, | ||
| className: NAMESPACE, | ||
| style: { | ||
| ...styleProp, | ||
| ...styles.container(fontSize) | ||
| }, | ||
| children: [/*#__PURE__*/jsx("div", { | ||
| className: getClassName('scroll-container'), | ||
| style: styles.scrollContainer(fontSize), | ||
| children: /*#__PURE__*/jsxs("svg", { | ||
| width: width, | ||
| height: height, | ||
| viewBox: `0 0 ${width} ${height}`, | ||
| className: getClassName('calendar'), | ||
| style: { | ||
| ...styles.calendar, | ||
| marginLeft: weekdayLabelOffset | ||
| }, | ||
| children: [!loading && renderWeekdayLabels(), !loading && renderMonthLabels(), renderCalendar()] | ||
| }) | ||
| }), renderFooter()] | ||
| }); | ||
| }); | ||
| ActivityCalendar.displayName = 'ActivityCalendar'; | ||
| export { ActivityCalendar as A, getClassName as g }; | ||
| //# sourceMappingURL=index-BLMVjjY9.js.map |
| {"version":3,"file":"index-BLMVjjY9.js","sources":["../../src/constants.ts","../../src/hooks/useColorScheme.ts","../../src/hooks/useLoadingAnimation.ts","../../src/hooks/usePrefersReducedMotion.ts","../../src/lib/calendar.ts","../../src/lib/label.ts","../../src/lib/theme.ts","../../src/styles/styles.ts","../../src/components/ActivityCalendar.tsx"],"sourcesContent":["export const NAMESPACE = 'react-activity-calendar'\nexport const LABEL_MARGIN = 8 // px\n\nexport const DEFAULT_MONTH_LABELS = [\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'May',\n 'Jun',\n 'Jul',\n 'Aug',\n 'Sep',\n 'Oct',\n 'Nov',\n 'Dec',\n]\n\nexport const DEFAULT_LABELS = {\n months: DEFAULT_MONTH_LABELS,\n weekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\n totalCount: '{{count}} activities in {{year}}',\n legend: {\n less: 'Less',\n more: 'More',\n },\n}\n","import { useEffect, useState } from 'react'\nimport type { ColorScheme } from '../types'\n\nexport function useColorScheme() {\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n const [colorScheme, setColorScheme] = useState<ColorScheme>(mediaQuery.matches ? 'dark' : 'light')\n\n const onChange = (event: MediaQueryListEvent) => {\n setColorScheme(event.matches ? 'dark' : 'light')\n }\n\n useEffect(() => {\n mediaQuery.addEventListener('change', onChange)\n\n return () => {\n mediaQuery.removeEventListener('change', onChange)\n }\n }, [mediaQuery])\n\n return colorScheme\n}\n","import { useEffect, useState } from 'react'\nimport { NAMESPACE } from '../constants'\nimport type { ColorScheme } from '../types'\n\nexport const loadingAnimationName = `${NAMESPACE}--loading-animation`\n\nexport function useLoadingAnimation(zeroColor: string, colorScheme: ColorScheme) {\n const [loaded, setLoaded] = useState(false)\n\n useEffect(() => {\n const colorLoading = `oklab(from ${zeroColor} l a b)`\n const colorActive =\n colorScheme === 'light'\n ? `oklab(from ${zeroColor} calc(l * 0.96) a b)`\n : `oklab(from ${zeroColor} calc(l * 1.08) a b)`\n\n const style = document.createElement('style')\n style.innerHTML = `\n @keyframes ${loadingAnimationName} {\n 0% {\n fill: ${colorLoading};\n }\n 50% {\n fill: ${colorActive};\n }\n 100% {\n fill: ${colorLoading};\n }\n }\n `\n const handleLoad = () => {\n setLoaded(true)\n }\n\n document.head.appendChild(style)\n style.addEventListener('load', handleLoad)\n\n return () => {\n document.head.removeChild(style)\n style.removeEventListener('load', handleLoad)\n setLoaded(false)\n }\n }, [zeroColor, colorScheme])\n\n return loaded\n}\n","import { useEffect, useState } from 'react'\n\nconst query = '(prefers-reduced-motion: reduce)'\n\nexport function usePrefersReducedMotion() {\n const mediaQuery = window.matchMedia(query)\n const [prefersReducedMotion, setPrefersReducedMotion] = useState(mediaQuery.matches)\n\n useEffect(() => {\n const onChange = (event: MediaQueryListEvent) => {\n setPrefersReducedMotion(event.matches)\n }\n\n mediaQuery.addEventListener('change', onChange)\n\n return () => {\n mediaQuery.removeEventListener('change', onChange)\n }\n }, [mediaQuery])\n\n return prefersReducedMotion\n}\n","import {\n differenceInCalendarDays,\n eachDayOfInterval,\n endOfYear,\n formatISO,\n getDay,\n isValid,\n nextDay,\n parseISO,\n startOfYear,\n subWeeks,\n} from 'date-fns'\nimport { NAMESPACE } from '../constants'\nimport type { Activity, DayIndex, Week } from '../types'\n\nexport function validateActivities(activities: Array<Activity>, maxLevel: number) {\n if (activities.length === 0) {\n throw new Error('Activity data must not be empty.')\n }\n\n for (const { date, level, count } of activities) {\n if (!isValid(parseISO(date))) {\n throw new Error(`Activity date '${date}' is not a valid ISO 8601 date string.`)\n }\n\n if (count < 0) {\n throw new RangeError(`Activity count must not be negative, found ${count}.`)\n }\n\n if (level < 0 || level > maxLevel) {\n throw new RangeError(\n `Activity level ${level} for ${date} is out of range. It must be between 0 and ${maxLevel}.`,\n )\n }\n }\n}\n\nexport function groupByWeeks(\n activities: Array<Activity>,\n weekStart: DayIndex = 0, // 0 = Sunday\n): Array<Week> {\n const normalizedActivities = fillHoles(activities)\n\n // Determine the first date of the calendar. If the first date is not the\n // passed weekday, the respective weekday one week earlier is used.\n const firstActivity = normalizedActivities[0] as Activity\n const firstDate = parseISO(firstActivity.date)\n const firstCalendarDate =\n getDay(firstDate) === weekStart ? firstDate : subWeeks(nextDay(firstDate, weekStart), 1)\n\n // To correctly group activities by week, it is necessary to left-pad the list\n // because the first date might not be the set start weekday.\n const paddedActivities = [\n ...(Array(differenceInCalendarDays(firstDate, firstCalendarDate)).fill(\n undefined,\n ) as Array<Activity>),\n ...normalizedActivities,\n ]\n\n const numberOfWeeks = Math.ceil(paddedActivities.length / 7)\n\n // Finally, group activities by week\n return range(numberOfWeeks).map(weekIndex =>\n paddedActivities.slice(weekIndex * 7, weekIndex * 7 + 7),\n )\n}\n\n/**\n * The calendar expects a continuous sequence of days,\n * so fill gaps with empty activity data.\n */\nfunction fillHoles(activities: Array<Activity>): Array<Activity> {\n const calendar = new Map<string, Activity>(activities.map(a => [a.date, a]))\n const firstActivity = activities[0] as Activity\n const lastActivity = activities[activities.length - 1] as Activity\n\n return eachDayOfInterval({\n start: parseISO(firstActivity.date),\n end: parseISO(lastActivity.date),\n }).map(day => {\n const date = formatISO(day, { representation: 'date' })\n\n if (calendar.has(date)) {\n return calendar.get(date) as Activity\n }\n\n return {\n date,\n count: 0,\n level: 0,\n }\n })\n}\n\n/**\n * Following the BEM (block, element, modifier) naming convention\n * https://getbem.com/naming/\n */\nexport function getClassName(element: string) {\n return `${NAMESPACE}__${element}`\n}\n\nexport function range(n: number) {\n return [...Array(n).keys()]\n}\n\nexport function generateEmptyData(): Array<Activity> {\n const year = new Date().getFullYear()\n const days = eachDayOfInterval({\n start: new Date(year, 0, 1),\n end: new Date(year, 11, 31),\n })\n\n return days.map(date => ({\n date: formatISO(date, { representation: 'date' }),\n count: 0,\n level: 0,\n }))\n}\n\nexport function generateTestData(args: {\n interval?: { start: Date; end: Date }\n maxLevel?: number\n}): Array<Activity> {\n const maxCount = 20\n const maxLevel = args.maxLevel ? Math.max(1, args.maxLevel) : 4\n const now = new Date()\n\n const days = eachDayOfInterval(\n args.interval ?? {\n start: startOfYear(now),\n end: endOfYear(now),\n },\n )\n\n const noise = whiteNoise(days.length, maxLevel, v => 0.9 * Math.pow(v, 2))\n\n return days.map((date, i) => {\n const level = noise[i] as number\n\n return {\n date: formatISO(date, { representation: 'date' }),\n count: Math.round(level * (maxCount / maxLevel)),\n level,\n }\n })\n}\n\n// Deterministically generates n white noise values from 0 to max (inclusive).\nfunction whiteNoise(\n n: number,\n max: number,\n transformFn: (v: number) => number = v => v,\n): Array<number> {\n const seed = 54321\n const random = mulberry32(seed)\n\n return Array.from({ length: n }, () => {\n const v = transformFn(random())\n return Math.floor(v * (max + 1))\n })\n}\n\n// Mulberry32 pseudorandom number generator\nfunction mulberry32(seed: number) {\n let state = seed >>> 0 // ensure unsigned 32-bit integer\n\n return () => {\n state += 0x6d2b79f5\n let r = Math.imul(state ^ (state >>> 15), 1 | state)\n r ^= r + Math.imul(r ^ (r >>> 7), 61 | r)\n\n return ((r ^ (r >>> 14)) >>> 0) / 4294967296\n }\n}\n","import { getMonth, parseISO } from 'date-fns'\nimport type { Props } from '../components/ActivityCalendar'\nimport { DEFAULT_MONTH_LABELS } from '../constants'\nimport type { DayIndex, DayName, Week, WeekdayLabels } from '../types'\n\ntype MonthLabel = {\n weekIndex: number\n label: string\n}\n\nexport function getMonthLabels(\n weeks: Array<Week>,\n monthNames: Array<string> = DEFAULT_MONTH_LABELS,\n): Array<MonthLabel> {\n return weeks\n .reduce<Array<MonthLabel>>((labels, week, weekIndex) => {\n const firstActivity = week.find(activity => activity !== undefined)\n\n if (!firstActivity) {\n throw new Error(`Unexpected error: Week ${weekIndex + 1} is empty.`)\n }\n\n const month = monthNames[getMonth(parseISO(firstActivity.date))]\n\n if (!month) {\n const monthName = new Date(firstActivity.date).toLocaleString('en-US', { month: 'short' })\n throw new Error(`Unexpected error: undefined month label for ${monthName}.`)\n }\n\n const prevLabel = labels[labels.length - 1]\n\n if (weekIndex === 0 || prevLabel?.label !== month) {\n return [...labels, { weekIndex, label: month }]\n }\n\n return labels\n }, [])\n .filter(({ weekIndex }, index, labels) => {\n // Labels should only be shown if there is \"enough\" space (data).\n // This is a naive implementation that does not take the block size,\n // font size, etc. into account.\n const minWeeks = 3\n\n // Skip the first month label if there is not enough space for the next one.\n if (index === 0) {\n return labels[1] && labels[1].weekIndex - weekIndex >= minWeeks\n }\n\n // Skip the last month label if there is not enough data in that month\n // to avoid overflowing the calendar on the right.\n if (index === labels.length - 1) {\n return weeks.slice(weekIndex).length >= minWeeks\n }\n\n return true\n })\n}\n\nexport function maxWeekdayLabelWidth(\n labels: Array<string>,\n showWeekdayLabel: WeekdayLabels,\n fontSize: number,\n): number {\n if (labels.length !== 7) {\n throw new Error('Exactly 7 labels, one for each weekday must be passed.')\n }\n\n return labels.reduce(\n (maxWidth, label, index) =>\n showWeekdayLabel.byDayIndex(index as DayIndex)\n ? Math.max(maxWidth, Math.ceil(calcTextDimensions(label, fontSize).width))\n : maxWidth,\n 0,\n )\n}\n\nexport function calcTextDimensions(text: string, fontSize: number) {\n if (typeof document === 'undefined' || typeof window === 'undefined') {\n return { width: 0, height: 0 }\n }\n\n if (fontSize < 1) {\n throw new RangeError('fontSize must be positive')\n }\n\n if (text.length === 0) {\n return { width: 0, height: 0 }\n }\n\n const namespace = 'http://www.w3.org/2000/svg'\n const svg = document.createElementNS(namespace, 'svg')\n\n svg.style.position = 'absolute'\n svg.style.visibility = 'hidden'\n svg.style.fontFamily = window.getComputedStyle(document.body).fontFamily\n svg.style.fontSize = `${fontSize}px`\n\n const textNode = document.createElementNS(namespace, 'text')\n textNode.textContent = text\n\n svg.appendChild(textNode)\n document.body.appendChild(svg)\n const boundingBox = textNode.getBBox()\n\n document.body.removeChild(svg)\n\n return { width: boundingBox.width, height: boundingBox.height }\n}\n\nexport function initWeekdayLabels(\n input: Props['showWeekdayLabels'],\n weekStart: DayIndex,\n): WeekdayLabels {\n if (!input)\n return {\n byDayIndex: () => false,\n shouldShow: false,\n }\n\n // Default: Show every second day of the week.\n if (input === true) {\n return {\n byDayIndex: index => {\n return ((7 + index - weekStart) % 7) % 2 !== 0\n },\n shouldShow: true,\n }\n }\n\n const indexed: Array<boolean> = []\n for (const name of input) {\n const index = dayNameToIndex[name.toLowerCase() as DayName]\n indexed[index] = true\n }\n\n return {\n byDayIndex: index => indexed[index] ?? false,\n shouldShow: input.length > 0,\n }\n}\n\nconst dayNameToIndex: Record<DayName, DayIndex> = {\n sun: 0,\n mon: 1,\n tue: 2,\n wed: 3,\n thu: 4,\n fri: 5,\n sat: 6,\n}\n","import type { Color, ColorScale, Theme, ThemeInput } from '../types'\nimport { range } from './calendar'\n\nexport function createTheme(input?: ThemeInput, steps = 5): Theme {\n const defaultTheme = createDefaultTheme(steps)\n\n if (input) {\n validateThemeInput(input, steps)\n\n input.light = input.light ?? defaultTheme.light\n input.dark = input.dark ?? defaultTheme.dark\n\n return {\n light: isPair(input.light) ? calcColorScale(input.light, steps) : input.light,\n dark: isPair(input.dark) ? calcColorScale(input.dark, steps) : input.dark,\n }\n }\n\n return defaultTheme\n}\n\nfunction createDefaultTheme(steps: number): Theme {\n return {\n light: calcColorScale(['hsl(0, 0%, 92%)', 'hsl(0, 0%, 26%)'], steps),\n dark: calcColorScale(['hsl(0, 0%, 22%)', 'hsl(0, 0%, 92%)'], steps),\n }\n}\n\nfunction validateThemeInput(input: ThemeInput, steps: number) {\n const maxLevelHint = 'The number of colors is controlled by the \"maxLevel\" property.'\n\n if (typeof input !== 'object' || (input.light === undefined && input.dark === undefined)) {\n throw new Error(\n `The theme object must contain at least one of the fields \"light\" and \"dark\" with exactly 2 or ${steps} colors respectively. ${maxLevelHint}`,\n )\n }\n\n if (input.light) {\n const { length } = input.light\n if (length !== 2 && length !== steps) {\n throw new Error(\n `theme.light must contain exactly 2 or ${steps} colors, ${length} passed. ${maxLevelHint}`,\n )\n }\n\n for (const c of input.light) {\n if (typeof window !== 'undefined' && !CSS.supports('color', c)) {\n throw new Error(`Invalid color \"${c}\" passed. All CSS color formats are accepted.`)\n }\n }\n }\n\n if (input.dark) {\n const { length } = input.dark\n if (length !== 2 && length !== steps) {\n throw new Error(\n `theme.dark must contain exactly 2 or ${steps} colors, ${length} passed. ${maxLevelHint}`,\n )\n }\n\n for (const c of input.dark) {\n if (typeof window !== 'undefined' && !CSS.supports('color', c)) {\n throw new Error(`Invalid color \"${c}\" passed. All CSS color formats are accepted.`)\n }\n }\n }\n}\n\nfunction calcColorScale([start, end]: [Color, Color], steps: number): ColorScale {\n return range(steps).map(i => {\n // In the loading animation the zero color is used.\n // However, Safari 16 crashes if a CSS color-mix expression like below is\n // combined with relative color syntax to calculate a hue variation for the\n // animation. Since the start and end colors do not need to be mixed, they\n // can be returned directly to work around this issue.\n switch (i) {\n case 0:\n return start\n case steps - 1:\n return end\n default: {\n const pos = (i / (steps - 1)) * 100\n return `color-mix(in oklab, ${end} ${parseFloat(pos.toFixed(2))}%, ${start})`\n }\n }\n })\n}\n\nfunction isPair<T>(val: Array<T>): val is [T, T] {\n return val.length === 2\n}\n","import type { CSSProperties } from 'react'\nimport type { ColorScheme } from '../types'\n\nexport const styles = {\n container: (fontSize: number) =>\n ({\n width: 'max-content', // Calendar should not grow\n maxWidth: '100%', // Do not remove - parent might be a flexbox\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n fontSize: `${fontSize}px`,\n }) satisfies CSSProperties,\n scrollContainer: (fontSize: number) =>\n ({\n maxWidth: '100%',\n overflowX: 'auto',\n overflowY: 'hidden',\n paddingTop: Math.ceil(0.1 * fontSize), // SVG <text> overflows in Firefox at y=0\n }) satisfies CSSProperties,\n calendar: {\n display: 'block', // SVGs are inline-block by default\n overflow: 'visible', // Weekday labels are rendered left of the container\n } satisfies CSSProperties,\n rect: (colorScheme: ColorScheme) =>\n ({\n stroke: colorScheme === 'light' ? 'rgba(0, 0, 0, 0.08)' : 'rgba(255, 255, 255, 0.04)',\n }) satisfies CSSProperties,\n footer: {\n container: {\n display: 'flex',\n flexWrap: 'wrap',\n gap: '4px 16px',\n whiteSpace: 'nowrap',\n } satisfies CSSProperties,\n legend: {\n marginLeft: 'auto',\n display: 'flex',\n alignItems: 'center',\n gap: '3px',\n } satisfies CSSProperties,\n },\n}\n","'use client'\n\nimport {\n forwardRef,\n Fragment,\n lazy,\n Suspense,\n useEffect,\n useState,\n type CSSProperties,\n type ForwardedRef,\n type ReactElement,\n} from 'react'\nimport { getYear, parseISO } from 'date-fns'\nimport { DEFAULT_LABELS, LABEL_MARGIN, NAMESPACE } from '../constants'\nimport { useColorScheme } from '../hooks/useColorScheme'\nimport { loadingAnimationName, useLoadingAnimation } from '../hooks/useLoadingAnimation'\nimport { usePrefersReducedMotion } from '../hooks/usePrefersReducedMotion'\nimport {\n generateEmptyData,\n getClassName,\n groupByWeeks,\n range,\n validateActivities,\n} from '../lib/calendar'\nimport { getMonthLabels, initWeekdayLabels, maxWeekdayLabelWidth } from '../lib/label'\nimport { createTheme } from '../lib/theme'\nimport { styles } from '../styles/styles'\nimport type {\n Activity,\n BlockElement,\n ColorScheme,\n DayIndex,\n DayName,\n Labels,\n ThemeInput,\n} from '../types'\nimport { type TooltipConfig } from './Tooltip'\n\nconst Tooltip = lazy(() => import('./Tooltip').then(module => ({ default: module.Tooltip })))\n\nexport type Props = {\n /**\n * List of calendar entries. Each `Activity` object requires an ISO 8601\n * `date` string in the format `yyyy-MM-dd`, a `count` property with the\n * amount of tracked data, and a `level` property in the range `0-maxLevel`\n * to specify activity intensity. The `maxLevel` prop defaults to 4.\n *\n * Dates without corresponding entries are assumed to have no activity. This\n * allows you to set arbitrary start and end dates for the calendar by passing\n * empty entries as the first and last items.\n *\n * Example object:\n *\n * ```\n * {\n * date: \"2021-02-20\",\n * count: 16,\n * level: 3\n * }\n * ```\n */\n data: Array<Activity>\n /**\n * Margin between blocks in pixels.\n */\n blockMargin?: number\n /**\n * Border radius of blocks in pixels.\n */\n blockRadius?: number\n /**\n * Block size in pixels.\n */\n blockSize?: number\n /**\n * Use the `'light'` or `'dark'` color scheme instead of the system one.\n */\n colorScheme?: ColorScheme\n /**\n * Font size for text in pixels.\n */\n fontSize?: number\n /**\n * Localization strings for all calendar labels.\n *\n * `totalCount` supports the placeholders `{{count}}` and `{{year}}`.\n */\n labels?: Labels\n /**\n * Maximum activity level (zero-indexed). 4 by default, 0 means \"no activity\".\n */\n maxLevel?: number\n /**\n * Toggle to display the calendar loading state. The `data` property is\n * ignored if set.\n */\n loading?: boolean\n /**\n * Ref to access the calendar DOM node.\n */\n ref?: ForwardedRef<HTMLElement>\n /**\n * Render prop for calendar blocks (activities). For example, useful to\n * attach event handlers or to wrap the element with a link. Use\n * `React.cloneElement` to pass additional props to the element if necessary.\n */\n renderBlock?: (block: BlockElement, activity: Activity) => ReactElement\n /**\n * Render prop for color legend blocks. Use `React.cloneElement` to pass\n * additional props to the element if necessary.\n */\n renderColorLegend?: (block: BlockElement, level: number) => ReactElement\n /**\n * Toggle to hide the color legend below the calendar.\n */\n showColorLegend?: boolean\n /**\n * Toggle to hide the month labels above the calendar.\n */\n showMonthLabels?: boolean\n /**\n * Toggle to hide the total count below the calendar.\n */\n showTotalCount?: boolean\n /**\n * Toggle to show weekday labels left to the calendar.\n * Alternatively, provide an array of ISO 8601 weekday names to display.\n * Example: `['mon', 'wed', 'fri']`.\n */\n showWeekdayLabels?: boolean | Array<DayName>\n /**\n * Style object to pass to the component container.\n */\n style?: CSSProperties\n /**\n * Set the calendar colors for the light and dark color schemes. Provide\n * all colors per scheme explicitly (5 by default) or specify exactly two colors\n * (the lowest and highest intensity) to calculate a single-hue scale. The\n * number of colors is controlled by the `maxLevel` property. Colors can be\n * specified in any valid CSS format.\n *\n * At least one scheme's colors must be set. If undefined, the default\n * theme is used. By default, the calendar selects the current system color\n * scheme, but you can enforce a specific scheme with the `colorScheme` prop.\n *\n * Example:\n *\n * ```tsx\n * <ActivityCalendar\n * data={data}\n * theme={{\n * light: ['hsl(0, 0%, 92%)', 'firebrick'],\n * dark: ['#333', 'rgb(214, 16, 174)'],\n * }}\n * />\n * ```\n *\n */\n theme?: ThemeInput\n /**\n * Tooltips to display when hovering over activity blocks or the color legend\n * below the calendar. See the story for details about tooltip configuration.\n */\n tooltips?: {\n activity?: TooltipConfig & {\n text: (activity: Activity) => string\n }\n colorLegend?: TooltipConfig & {\n text: (level: number) => string\n }\n }\n /**\n * Index of day to be used as start of week. 0 represents Sunday.\n */\n weekStart?: DayIndex\n}\n\nexport const ActivityCalendar = forwardRef<HTMLElement, Props>(\n (\n {\n data: activities,\n blockMargin = 4,\n blockRadius = 2,\n blockSize = 12,\n colorScheme: colorSchemeProp = undefined,\n fontSize = 14,\n labels: labelsProp = undefined,\n loading = false,\n maxLevel = 4,\n renderBlock = undefined,\n renderColorLegend = undefined,\n showColorLegend = true,\n showMonthLabels = true,\n showTotalCount = true,\n showWeekdayLabels = false,\n style: styleProp = {},\n theme: themeProp = undefined,\n tooltips = {},\n weekStart = 0, // Sunday\n },\n ref,\n ) => {\n const [isClient, setIsClient] = useState(false)\n useEffect(() => {\n setIsClient(true)\n }, [])\n\n maxLevel = Math.max(1, maxLevel)\n\n const theme = createTheme(themeProp, maxLevel + 1)\n const systemColorScheme = useColorScheme()\n const colorScheme = colorSchemeProp ?? systemColorScheme\n const colorScale = theme[colorScheme]\n\n const animationLoaded = useLoadingAnimation(colorScale[0] as string, colorScheme)\n const useAnimation = !usePrefersReducedMotion()\n\n if (loading) {\n // Only show the loading state once the CSS animation has been injected\n // to avoid a flash of white with dark backgrounds.\n if (useAnimation && !animationLoaded) {\n return null\n }\n\n activities = generateEmptyData()\n }\n\n validateActivities(activities, maxLevel)\n\n const firstActivity = activities[0] as Activity\n const year = getYear(parseISO(firstActivity.date))\n const weeks = groupByWeeks(activities, weekStart)\n\n const labels = Object.assign({}, DEFAULT_LABELS, labelsProp)\n const labelHeight = showMonthLabels ? fontSize + LABEL_MARGIN : 0\n\n const weekdayLabels = initWeekdayLabels(showWeekdayLabels, weekStart)\n\n // Must be calculated on the client, or SSR hydration errors will occur\n // because server and client HTML would not match.\n const weekdayLabelOffset =\n isClient && weekdayLabels.shouldShow\n ? maxWeekdayLabelWidth(labels.weekdays, weekdayLabels, fontSize) + LABEL_MARGIN\n : undefined\n\n function getDimensions() {\n return {\n width: weeks.length * (blockSize + blockMargin) - blockMargin,\n height: labelHeight + (blockSize + blockMargin) * 7 - blockMargin,\n }\n }\n\n function renderCalendar() {\n return weeks\n .map((week, weekIndex) =>\n week.map((activity, dayIndex) => {\n if (!activity) {\n return null\n }\n\n const loadingAnimation =\n loading && useAnimation\n ? {\n animation: `${loadingAnimationName} 1.75s ease-in-out infinite`,\n animationDelay: `${weekIndex * 20 + dayIndex * 20}ms`,\n }\n : undefined\n\n const block = (\n <rect\n x={0}\n y={labelHeight + (blockSize + blockMargin) * dayIndex}\n width={blockSize}\n height={blockSize}\n rx={blockRadius}\n ry={blockRadius}\n fill={colorScale[activity.level]}\n data-date={activity.date}\n data-level={activity.level}\n style={{\n ...styles.rect(colorScheme),\n ...loadingAnimation,\n }}\n />\n )\n\n const renderedBlock = renderBlock ? renderBlock(block, activity) : block\n\n return (\n <Fragment key={activity.date}>\n {tooltips.activity ? (\n <Suspense fallback={renderedBlock}>\n <Tooltip\n text={tooltips.activity.text(activity)}\n colorScheme={colorScheme}\n placement={tooltips.activity.placement ?? 'top'}\n hoverRestMs={tooltips.activity.hoverRestMs}\n offset={tooltips.activity.offset}\n transitionStyles={tooltips.activity.transitionStyles}\n withArrow={tooltips.activity.withArrow}\n >\n {renderedBlock}\n </Tooltip>\n </Suspense>\n ) : (\n renderedBlock\n )}\n </Fragment>\n )\n }),\n )\n .map((week, x) => (\n <g key={x} transform={`translate(${(blockSize + blockMargin) * x}, 0)`}>\n {week}\n </g>\n ))\n }\n\n function renderFooter() {\n if (!showTotalCount && !showColorLegend) {\n return null\n }\n\n const totalCount = activities.reduce((sum, activity) => sum + activity.count, 0)\n\n return (\n <footer\n className={getClassName('footer')}\n style={{ ...styles.footer.container, marginLeft: weekdayLabelOffset }}\n >\n {/* Placeholder */}\n {loading && <div> </div>}\n\n {!loading && showTotalCount && (\n <div className={getClassName('count')}>\n {labels.totalCount\n ? labels.totalCount\n .replace('{{count}}', String(totalCount))\n .replace('{{year}}', String(year))\n : `${totalCount} activities in ${year}`}\n </div>\n )}\n\n {!loading && showColorLegend && (\n <div className={getClassName('legend-colors')} style={styles.footer.legend}>\n <span style={{ marginRight: '0.4em' }}>{labels.legend.less}</span>\n {range(maxLevel + 1).map(level => {\n const colorLegend = (\n <svg width={blockSize} height={blockSize} key={level}>\n <rect\n width={blockSize}\n height={blockSize}\n fill={colorScale[level]}\n rx={blockRadius}\n ry={blockRadius}\n style={styles.rect(colorScheme)}\n />\n </svg>\n )\n\n const renderedColorLegend = renderColorLegend\n ? renderColorLegend(colorLegend, level)\n : colorLegend\n\n return (\n <Fragment key={level}>\n {tooltips.colorLegend ? (\n <Suspense fallback={renderedColorLegend}>\n <Tooltip\n text={tooltips.colorLegend.text(level)}\n colorScheme={colorScheme}\n placement={tooltips.colorLegend.placement ?? 'bottom'}\n hoverRestMs={tooltips.colorLegend.hoverRestMs}\n offset={tooltips.colorLegend.offset}\n transitionStyles={tooltips.colorLegend.transitionStyles}\n withArrow={tooltips.colorLegend.withArrow}\n >\n {renderedColorLegend}\n </Tooltip>\n </Suspense>\n ) : (\n renderedColorLegend\n )}\n </Fragment>\n )\n })}\n <span style={{ marginLeft: '0.4em' }}>{labels.legend.more}</span>\n </div>\n )}\n </footer>\n )\n }\n\n function renderWeekdayLabels() {\n if (!weekdayLabels.shouldShow) {\n return null\n }\n\n return (\n <g className={getClassName('legend-weekday')}>\n {range(7).map(index => {\n const dayIndex = ((index + weekStart) % 7) as DayIndex\n\n if (!weekdayLabels.byDayIndex(dayIndex)) {\n return null\n }\n\n return (\n <text\n x={-LABEL_MARGIN}\n y={labelHeight + (blockSize + blockMargin) * index + blockSize / 2}\n dominantBaseline=\"central\"\n textAnchor=\"end\"\n fill=\"currentColor\"\n key={index}\n >\n {labels.weekdays[dayIndex]}\n </text>\n )\n })}\n </g>\n )\n }\n\n function renderMonthLabels() {\n if (!showMonthLabels) {\n return null\n }\n\n return (\n <g className={getClassName('legend-month')}>\n {getMonthLabels(weeks, labels.months).map(({ label, weekIndex }) => (\n <text\n x={(blockSize + blockMargin) * weekIndex}\n y={0}\n dominantBaseline=\"hanging\"\n fill=\"currentColor\"\n key={weekIndex}\n >\n {label}\n </text>\n ))}\n </g>\n )\n }\n\n const { width, height } = getDimensions()\n\n return (\n <article\n ref={ref}\n className={NAMESPACE}\n style={{ ...styleProp, ...styles.container(fontSize) }}\n >\n <div className={getClassName('scroll-container')} style={styles.scrollContainer(fontSize)}>\n <svg\n width={width}\n height={height}\n viewBox={`0 0 ${width} ${height}`}\n className={getClassName('calendar')}\n style={{ ...styles.calendar, marginLeft: weekdayLabelOffset }}\n >\n {!loading && renderWeekdayLabels()}\n {!loading && renderMonthLabels()}\n {renderCalendar()}\n </svg>\n </div>\n {renderFooter()}\n </article>\n )\n },\n)\n\nActivityCalendar.displayName = 'ActivityCalendar'\n"],"names":["NAMESPACE","LABEL_MARGIN","DEFAULT_MONTH_LABELS","DEFAULT_LABELS","months","weekdays","totalCount","legend","less","more","useColorScheme","mediaQuery","window","matchMedia","colorScheme","setColorScheme","useState","matches","onChange","event","useEffect","addEventListener","removeEventListener","loadingAnimationName","useLoadingAnimation","zeroColor","loaded","setLoaded","colorLoading","colorActive","style","document","createElement","innerHTML","handleLoad","head","appendChild","removeChild","query","usePrefersReducedMotion","prefersReducedMotion","setPrefersReducedMotion","validateActivities","activities","maxLevel","length","Error","date","level","count","isValid","parseISO","RangeError","groupByWeeks","weekStart","normalizedActivities","fillHoles","firstActivity","firstDate","firstCalendarDate","getDay","subWeeks","nextDay","paddedActivities","Array","differenceInCalendarDays","fill","undefined","numberOfWeeks","Math","ceil","range","map","weekIndex","slice","calendar","Map","a","lastActivity","eachDayOfInterval","start","end","day","formatISO","representation","has","get","getClassName","element","n","keys","generateEmptyData","year","Date","getFullYear","days","getMonthLabels","weeks","monthNames","reduce","labels","week","find","activity","month","getMonth","monthName","toLocaleString","prevLabel","label","filter","index","minWeeks","maxWeekdayLabelWidth","showWeekdayLabel","fontSize","maxWidth","byDayIndex","max","calcTextDimensions","width","text","height","namespace","svg","createElementNS","position","visibility","fontFamily","getComputedStyle","body","textNode","textContent","boundingBox","getBBox","initWeekdayLabels","input","shouldShow","indexed","name","dayNameToIndex","toLowerCase","sun","mon","tue","wed","thu","fri","sat","createTheme","steps","defaultTheme","createDefaultTheme","validateThemeInput","light","dark","isPair","calcColorScale","maxLevelHint","c","CSS","supports","i","pos","parseFloat","toFixed","val","styles","container","display","flexDirection","gap","scrollContainer","overflowX","overflowY","paddingTop","overflow","rect","stroke","footer","flexWrap","whiteSpace","marginLeft","alignItems","Tooltip","lazy","then","module","default","ActivityCalendar","forwardRef","data","blockMargin","blockRadius","blockSize","colorSchemeProp","labelsProp","loading","renderBlock","renderColorLegend","showColorLegend","showMonthLabels","showTotalCount","showWeekdayLabels","styleProp","theme","themeProp","tooltips","ref","isClient","setIsClient","systemColorScheme","colorScale","animationLoaded","useAnimation","getYear","Object","assign","labelHeight","weekdayLabels","weekdayLabelOffset","getDimensions","renderCalendar","dayIndex","loadingAnimation","animation","animationDelay","block","_jsx","x","y","rx","ry","renderedBlock","Fragment","children","Suspense","fallback","placement","hoverRestMs","offset","transitionStyles","withArrow","transform","renderFooter","sum","_jsxs","className","replace","String","marginRight","colorLegend","renderedColorLegend","renderWeekdayLabels","dominantBaseline","textAnchor","renderMonthLabels","viewBox","displayName"],"mappings":"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"} |
| 'use client'; | ||
| import { useState, useRef, cloneElement } from 'react'; | ||
| import { useFloating, autoUpdate, flip, offset, shift, arrow, useHover, useDismiss, useRole, useInteractions, useTransitionStyles, FloatingPortal, FloatingArrow } from '@floating-ui/react'; | ||
| import { g as getClassName } from './index-BLMVjjY9.js'; | ||
| import { jsxs, Fragment, jsx } from 'react/jsx-runtime'; | ||
| import 'date-fns'; | ||
| function Tooltip({ | ||
| children, | ||
| text, | ||
| colorScheme, | ||
| placement, | ||
| offset: offsetProp = 4, | ||
| transitionStyles: transitionStylesProp, | ||
| hoverRestMs = 150, | ||
| withArrow = false | ||
| }) { | ||
| const [isOpen, setIsOpen] = useState(false); | ||
| const arrowRef = useRef(null); | ||
| const { | ||
| context, | ||
| refs, | ||
| floatingStyles | ||
| } = useFloating({ | ||
| open: isOpen, | ||
| onOpenChange: setIsOpen, | ||
| placement, | ||
| middleware: [flip(), offset(offsetProp), shift({ | ||
| padding: 8 | ||
| }), withArrow ? arrow({ | ||
| element: arrowRef | ||
| }) : null // eslint-disable-line react-hooks/refs | ||
| ], | ||
| whileElementsMounted: autoUpdate | ||
| }); | ||
| const hover = useHover(context, { | ||
| restMs: hoverRestMs | ||
| }); | ||
| const dismiss = useDismiss(context); | ||
| const role = useRole(context, { | ||
| role: 'tooltip' | ||
| }); | ||
| const { | ||
| getReferenceProps, | ||
| getFloatingProps | ||
| } = useInteractions([hover, dismiss, role]); | ||
| const { | ||
| isMounted, | ||
| styles: transitionStyles | ||
| } = useTransitionStyles(context, transitionStylesProp); | ||
| return /*#__PURE__*/jsxs(Fragment, { | ||
| children: [/*#__PURE__*/cloneElement(children, { | ||
| ref: refs.setReference, | ||
| ...getReferenceProps() | ||
| }), /*#__PURE__*/jsx(FloatingPortal, { | ||
| children: isMounted && /*#__PURE__*/jsxs("div", { | ||
| ref: refs.setFloating, | ||
| className: getClassName('tooltip'), | ||
| style: { | ||
| ...floatingStyles, | ||
| ...transitionStyles | ||
| }, | ||
| "data-color-scheme": colorScheme, | ||
| ...getFloatingProps(), | ||
| children: [text, withArrow && /*#__PURE__*/jsx(FloatingArrow, { | ||
| ref: arrowRef, | ||
| context: context, | ||
| className: getClassName('tooltip-arrow') | ||
| })] | ||
| }) | ||
| })] | ||
| }); | ||
| } | ||
| export { Tooltip }; | ||
| //# sourceMappingURL=Tooltip-s91_dg_C.js.map |
| {"version":3,"file":"Tooltip-s91_dg_C.js","sources":["../../src/components/Tooltip.tsx"],"sourcesContent":["'use client'\n\nimport { cloneElement, useRef, useState, type ReactElement, type Ref } from 'react'\nimport {\n arrow,\n autoUpdate,\n flip,\n FloatingArrow,\n FloatingPortal,\n offset,\n shift,\n useDismiss,\n useFloating,\n useHover,\n useInteractions,\n useRole,\n useTransitionStyles,\n type OffsetOptions,\n type Placement,\n type UseHoverProps,\n type UseTransitionStylesProps,\n} from '@floating-ui/react'\nimport { getClassName } from '../lib/calendar'\nimport type { ColorScheme } from '../types'\n\nexport type TooltipConfig = {\n placement?: Placement\n offset?: OffsetOptions\n transitionStyles?: UseTransitionStylesProps\n hoverRestMs?: UseHoverProps['restMs']\n withArrow?: boolean\n}\n\nexport type TooltipProps = TooltipConfig & {\n children: ReactElement<{ ref: Ref<unknown> }>\n text: string\n colorScheme: ColorScheme\n}\n\nexport function Tooltip({\n children,\n text,\n colorScheme,\n placement,\n offset: offsetProp = 4,\n transitionStyles: transitionStylesProp,\n hoverRestMs = 150,\n withArrow = false,\n}: TooltipProps) {\n const [isOpen, setIsOpen] = useState(false)\n const arrowRef = useRef(null)\n\n const { context, refs, floatingStyles } = useFloating({\n open: isOpen,\n onOpenChange: setIsOpen,\n placement,\n middleware: [\n flip(),\n offset(offsetProp),\n shift({ padding: 8 }),\n withArrow ? arrow({ element: arrowRef }) : null, // eslint-disable-line react-hooks/refs\n ],\n whileElementsMounted: autoUpdate,\n })\n\n const hover = useHover(context, { restMs: hoverRestMs })\n const dismiss = useDismiss(context)\n const role = useRole(context, { role: 'tooltip' })\n\n const { getReferenceProps, getFloatingProps } = useInteractions([hover, dismiss, role])\n\n const { isMounted, styles: transitionStyles } = useTransitionStyles(context, transitionStylesProp)\n\n return (\n <>\n {cloneElement(children, { ref: refs.setReference, ...getReferenceProps() })}\n {\n <FloatingPortal>\n {isMounted && (\n <div\n ref={refs.setFloating}\n className={getClassName('tooltip')}\n style={{ ...floatingStyles, ...transitionStyles }}\n data-color-scheme={colorScheme}\n {...getFloatingProps()}\n >\n {text}\n {withArrow && (\n <FloatingArrow\n ref={arrowRef}\n context={context}\n className={getClassName('tooltip-arrow')}\n />\n )}\n </div>\n )}\n </FloatingPortal>\n }\n </>\n )\n}\n"],"names":["Tooltip","children","text","colorScheme","placement","offset","offsetProp","transitionStyles","transitionStylesProp","hoverRestMs","withArrow","isOpen","setIsOpen","useState","arrowRef","useRef","context","refs","floatingStyles","useFloating","open","onOpenChange","middleware","flip","shift","padding","arrow","element","whileElementsMounted","autoUpdate","hover","useHover","restMs","dismiss","useDismiss","role","useRole","getReferenceProps","getFloatingProps","useInteractions","isMounted","styles","useTransitionStyles","_jsxs","_Fragment","cloneElement","ref","setReference","_jsx","FloatingPortal","setFloating","className","getClassName","style","FloatingArrow"],"mappings":";;;;;;;AAuCO,SAASA,OAAOA,CAAC;EACtBC,QAAQ;EACRC,IAAI;EACJC,WAAW;EACXC,SAAS;EACTC,MAAM,EAAEC,UAAU,GAAG,CAAC;AACtBC,EAAAA,gBAAgB,EAAEC,oBAAoB;AACtCC,EAAAA,WAAW,GAAG,GAAG;AACjBC,EAAAA,SAAS,GAAG;AACA,CAAC,EAAE;EACf,MAAM,CAACC,MAAM,EAAEC,SAAS,CAAC,GAAGC,QAAQ,CAAC,KAAK,CAAC;AAC3C,EAAA,MAAMC,QAAQ,GAAGC,MAAM,CAAC,IAAI,CAAC;EAE7B,MAAM;IAAEC,OAAO;IAAEC,IAAI;AAAEC,IAAAA;GAAgB,GAAGC,WAAW,CAAC;AACpDC,IAAAA,IAAI,EAAET,MAAM;AACZU,IAAAA,YAAY,EAAET,SAAS;IACvBR,SAAS;AACTkB,IAAAA,UAAU,EAAE,CACVC,IAAI,EAAE,EACNlB,MAAM,CAACC,UAAU,CAAC,EAClBkB,KAAK,CAAC;AAAEC,MAAAA,OAAO,EAAE;AAAE,KAAC,CAAC,EACrBf,SAAS,GAAGgB,KAAK,CAAC;AAAEC,MAAAA,OAAO,EAAEb;KAAU,CAAC,GAAG,IAAI;KAChD;AACDc,IAAAA,oBAAoB,EAAEC;AACxB,GAAC,CAAC;AAEF,EAAA,MAAMC,KAAK,GAAGC,QAAQ,CAACf,OAAO,EAAE;AAAEgB,IAAAA,MAAM,EAAEvB;AAAY,GAAC,CAAC;AACxD,EAAA,MAAMwB,OAAO,GAAGC,UAAU,CAAClB,OAAO,CAAC;AACnC,EAAA,MAAMmB,IAAI,GAAGC,OAAO,CAACpB,OAAO,EAAE;AAAEmB,IAAAA,IAAI,EAAE;AAAU,GAAC,CAAC;EAElD,MAAM;IAAEE,iBAAiB;AAAEC,IAAAA;GAAkB,GAAGC,eAAe,CAAC,CAACT,KAAK,EAAEG,OAAO,EAAEE,IAAI,CAAC,CAAC;EAEvF,MAAM;IAAEK,SAAS;AAAEC,IAAAA,MAAM,EAAElC;AAAiB,GAAC,GAAGmC,mBAAmB,CAAC1B,OAAO,EAAER,oBAAoB,CAAC;EAElG,oBACEmC,IAAA,CAAAC,QAAA,EAAA;AAAA3C,IAAAA,QAAA,EAAA,cACG4C,YAAY,CAAC5C,QAAQ,EAAE;MAAE6C,GAAG,EAAE7B,IAAI,CAAC8B,YAAY;AAAE,MAAA,GAAGV,iBAAiB;AAAG,KAAC,CAAC,eAEzEW,GAAA,CAACC,cAAc,EAAA;MAAAhD,QAAA,EACZuC,SAAS,iBACRG,IAAA,CAAA,KAAA,EAAA;QACEG,GAAG,EAAE7B,IAAI,CAACiC,WAAY;AACtBC,QAAAA,SAAS,EAAEC,YAAY,CAAC,SAAS,CAAE;AACnCC,QAAAA,KAAK,EAAE;AAAE,UAAA,GAAGnC,cAAc;UAAE,GAAGX;SAAmB;AAClD,QAAA,mBAAA,EAAmBJ,WAAY;QAAA,GAC3BmC,gBAAgB,EAAE;AAAArC,QAAAA,QAAA,GAErBC,IAAI,EACJQ,SAAS,iBACRsC,GAAA,CAACM,aAAa,EAAA;AACZR,UAAAA,GAAG,EAAEhC,QAAS;AACdE,UAAAA,OAAO,EAAEA,OAAQ;UACjBmC,SAAS,EAAEC,YAAY,CAAC,eAAe;AAAE,SAC1C,CACF;OACE;AACN,KACa,CAAC;AAAA,GAEnB,CAAC;AAEP;;;;"} |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
168941
0.34%3011
0.27%