New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

react-activity-calendar

Package Overview
Dependencies
Maintainers
1
Versions
99
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-activity-calendar - npm Package Compare versions

Comparing version
3.0.5
to
3.0.6
+651
build/chunks/index-3LcqA2uv.js
'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-BsYdIR3u.js').then(module => ({
default: module.Tooltip
})));
const ActivityCalendar = /*#__PURE__*/forwardRef(({
data: activities,
blockMargin = 4,
blockRadius = 2,
blockSize = 12,
colorScheme: colorSchemeProp,
fontSize = 14,
labels: labelsProp,
loading = false,
maxLevel = 4,
renderBlock,
renderColorLegend,
showColorLegend = true,
showMonthLabels = true,
showTotalCount = true,
showWeekdayLabels = false,
style: styleProp = {},
theme: themeProp,
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-3LcqA2uv.js.map
{"version":3,"file":"index-3LcqA2uv.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,\n fontSize = 14,\n labels: labelsProp,\n loading = false,\n maxLevel = 4,\n renderBlock,\n renderColorLegend,\n showColorLegend = true,\n showMonthLabels = true,\n showTotalCount = true,\n showWeekdayLabels = false,\n style: styleProp = {},\n theme: themeProp,\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>&nbsp;</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-3LcqA2uv.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()
}), isMounted && /*#__PURE__*/jsx(FloatingPortal, {
children: /*#__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-BsYdIR3u.js.map
{"version":3,"file":"Tooltip-BsYdIR3u.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 const { isMounted, styles: transitionStyles } = useTransitionStyles(context, transitionStylesProp)\n\n return (\n <>\n {cloneElement(children, { ref: refs.setReference, ...getReferenceProps() })}\n {isMounted && (\n <FloatingPortal>\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 </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;EACvF,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,EAC1EG,SAAS,iBACRQ,GAAA,CAACC,cAAc,EAAA;AAAAhD,MAAAA,QAAA,eACb0C,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;AAAC,KACQ,CACjB;AAAA,GACD,CAAC;AAEP;;;;"}
+1
-1
'use client';
export { A as ActivityCalendar } from './chunks/index-w4bahFWW.js';
export { A as ActivityCalendar } from './chunks/index-3LcqA2uv.js';
import 'react';

@@ -4,0 +4,0 @@ import 'date-fns';

{
"name": "react-activity-calendar",
"version": "3.0.5",
"version": "3.0.6",
"description": "React component to display activity data in calendar",

@@ -56,3 +56,3 @@ "author": "Jonathan Gruber <gruberjonathan@gmail.com>",

"@jest/types": "^30.0.1",
"@playwright/test": "^1.56.1",
"@playwright/test": "^1.57.0",
"@rollup/plugin-babel": "^6.1.0",

@@ -72,4 +72,4 @@ "@rollup/plugin-commonjs": "^29.0.0",

"eslint-plugin-react-hooks": "^7.0.0",
"eslint-plugin-storybook": "10.1.9",
"globals": "^16.2.0",
"eslint-plugin-storybook": "10.1.11",
"globals": "^17.0.0",
"husky": "^9.1.7",

@@ -76,0 +76,0 @@ "jest": "^30.0.3",

@@ -186,9 +186,9 @@ 'use client'

blockSize = 12,
colorScheme: colorSchemeProp = undefined,
colorScheme: colorSchemeProp,
fontSize = 14,
labels: labelsProp = undefined,
labels: labelsProp,
loading = false,
maxLevel = 4,
renderBlock = undefined,
renderColorLegend = undefined,
renderBlock,
renderColorLegend,
showColorLegend = true,

@@ -199,3 +199,3 @@ showMonthLabels = true,

style: styleProp = {},
theme: themeProp = undefined,
theme: themeProp,
tooltips = {},

@@ -202,0 +202,0 @@ weekStart = 0, // Sunday

@@ -71,3 +71,2 @@ 'use client'

const { getReferenceProps, getFloatingProps } = useInteractions([hover, dismiss, role])
const { isMounted, styles: transitionStyles } = useTransitionStyles(context, transitionStylesProp)

@@ -78,26 +77,24 @@

{cloneElement(children, { ref: refs.setReference, ...getReferenceProps() })}
{
{isMounted && (
<FloatingPortal>
{isMounted && (
<div
ref={refs.setFloating}
className={getClassName('tooltip')}
style={{ ...floatingStyles, ...transitionStyles }}
data-color-scheme={colorScheme}
{...getFloatingProps()}
>
{text}
{withArrow && (
<FloatingArrow
ref={arrowRef}
context={context}
className={getClassName('tooltip-arrow')}
/>
)}
</div>
)}
<div
ref={refs.setFloating}
className={getClassName('tooltip')}
style={{ ...floatingStyles, ...transitionStyles }}
data-color-scheme={colorScheme}
{...getFloatingProps()}
>
{text}
{withArrow && (
<FloatingArrow
ref={arrowRef}
context={context}
className={getClassName('tooltip-arrow')}
/>
)}
</div>
</FloatingPortal>
}
)}
</>
)
}
'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>&nbsp;</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;;;;"}