diff --git a/src/app/calendarOverviewCard.tsx b/src/app/calendarOverviewCard.tsx
index d69e09c..ab68d7e 100644
--- a/src/app/calendarOverviewCard.tsx
+++ b/src/app/calendarOverviewCard.tsx
@@ -5,7 +5,8 @@ import useSWR from "swr";
import {fetcher} from "@/app/utils";
import * as R from 'ramda';
import * as dFns from 'date-fns';
-import CalendarHeatmap from 'react-calendar-heatmap';
+// import CalendarHeatmap from 'react-calendar-heatmap';
+import CalendarHeatmap from '../heatmap';
import 'react-calendar-heatmap/dist/styles.css';
import './calendar-styles.css'
import { Tooltip } from 'react-tooltip';
@@ -69,8 +70,6 @@ function useCalendarData() {
}
})
- debugger
-
setData(Object.entries(summed)
.map(([key, value]) => ({
date: dFns.parseISO(key),
diff --git a/src/heatmap/b.tsx b/src/heatmap/b.tsx
new file mode 100644
index 0000000..7218ec6
--- /dev/null
+++ b/src/heatmap/b.tsx
@@ -0,0 +1,38 @@
+import * as dFns from 'date-fns';
+import {CSS_PSEDUO_NAMESPACE} from "@/heatmap/index";
+
+export function MonthLabels({
+ startDate,
+ endDate,
+ getMonthLabelCoordinates
+ }: {
+ startDate: Date;
+ endDate: Date;
+ getMonthLabelCoordinates: (month: Date) => {
+ x: number;
+ y: number
+ };
+}) {
+ // We render a label for each month in the interval if its first week is in the interval
+ const firstWeeks = dFns.eachWeekOfInterval({
+ start: startDate,
+ end: endDate,
+ }).filter(date => date.getDate() <= 7);
+
+ return (
+ <>
+ {firstWeeks.map((month, i) => {
+ const {x, y} = getMonthLabelCoordinates(month);
+
+ return (
+ {dFns.format(month, 'MMM')}
+ );
+ })}
+ >
+ );
+}
diff --git a/src/heatmap/index.js b/src/heatmap/index.js
deleted file mode 100644
index 4748f57..0000000
--- a/src/heatmap/index.js
+++ /dev/null
@@ -1,387 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import memoizeOne from 'memoize-one';
-import { DAYS_IN_WEEK, MILLISECONDS_IN_ONE_DAY, DAY_LABELS, MONTH_LABELS } from './constants';
-import {
- dateNDaysAgo,
- shiftDate,
- getBeginningTimeForDate,
- convertToDate,
- getRange,
-} from './helpers';
-
-const SQUARE_SIZE = 10;
-const MONTH_LABEL_GUTTER_SIZE = 4;
-const CSS_PSEDUO_NAMESPACE = 'react-calendar-heatmap-';
-
-class CalendarHeatmap extends React.Component {
- getDateDifferenceInDays() {
- const { startDate, numDays } = this.props;
- if (numDays) {
- // eslint-disable-next-line no-console
- console.warn(
- 'numDays is a deprecated prop. It will be removed in the next release. Consider using the startDate prop instead.',
- );
- return numDays;
- }
- const timeDiff = this.getEndDate() - convertToDate(startDate);
- return Math.ceil(timeDiff / MILLISECONDS_IN_ONE_DAY);
- }
-
- getSquareSizeWithGutter() {
- return SQUARE_SIZE + this.props.gutterSize;
- }
-
- getMonthLabelSize() {
- if (!this.props.showMonthLabels) {
- return 0;
- }
- if (this.props.horizontal) {
- return SQUARE_SIZE + MONTH_LABEL_GUTTER_SIZE;
- }
- return 2 * (SQUARE_SIZE + MONTH_LABEL_GUTTER_SIZE);
- }
-
- getWeekdayLabelSize() {
- if (!this.props.showWeekdayLabels) {
- return 0;
- }
- if (this.props.horizontal) {
- return 30;
- }
- return SQUARE_SIZE * 1.5;
- }
-
- getStartDate() {
- return shiftDate(this.getEndDate(), -this.getDateDifferenceInDays() + 1); // +1 because endDate is inclusive
- }
-
- getEndDate() {
- return getBeginningTimeForDate(convertToDate(this.props.endDate));
- }
-
- getStartDateWithEmptyDays() {
- return shiftDate(this.getStartDate(), -this.getNumEmptyDaysAtStart());
- }
-
- getNumEmptyDaysAtStart() {
- return this.getStartDate().getDay();
- }
-
- getNumEmptyDaysAtEnd() {
- return DAYS_IN_WEEK - 1 - this.getEndDate().getDay();
- }
-
- getWeekCount() {
- const numDaysRoundedToWeek =
- this.getDateDifferenceInDays() + this.getNumEmptyDaysAtStart() + this.getNumEmptyDaysAtEnd();
- return Math.ceil(numDaysRoundedToWeek / DAYS_IN_WEEK);
- }
-
- getWeekWidth() {
- return DAYS_IN_WEEK * this.getSquareSizeWithGutter();
- }
-
- getWidth() {
- return (
- this.getWeekCount() * this.getSquareSizeWithGutter() -
- (this.props.gutterSize - this.getWeekdayLabelSize())
- );
- }
-
- getHeight() {
- return (
- this.getWeekWidth() +
- (this.getMonthLabelSize() - this.props.gutterSize) +
- this.getWeekdayLabelSize()
- );
- }
-
- getValueCache = memoizeOne((props) =>
- props.values.reduce((memo, value) => {
- const date = convertToDate(value.date);
- const index = Math.floor((date - this.getStartDateWithEmptyDays()) / MILLISECONDS_IN_ONE_DAY);
- // eslint-disable-next-line no-param-reassign
- memo[index] = {
- value,
- className: this.props.classForValue(value),
- title: this.props.titleForValue ? this.props.titleForValue(value) : null,
- tooltipDataAttrs: this.getTooltipDataAttrsForValue(value),
- };
- return memo;
- }, {}),
- );
-
- getValueForIndex(index) {
- if (this.valueCache[index]) {
- return this.valueCache[index].value;
- }
- return null;
- }
-
- getClassNameForIndex(index) {
- if (this.valueCache[index]) {
- return this.valueCache[index].className;
- }
- return this.props.classForValue(null);
- }
-
- getTitleForIndex(index) {
- if (this.valueCache[index]) {
- return this.valueCache[index].title;
- }
- return this.props.titleForValue ? this.props.titleForValue(null) : null;
- }
-
- getTooltipDataAttrsForIndex(index) {
- if (this.valueCache[index]) {
- return this.valueCache[index].tooltipDataAttrs;
- }
- return this.getTooltipDataAttrsForValue({ date: null, count: null });
- }
-
- getTooltipDataAttrsForValue(value) {
- const { tooltipDataAttrs } = this.props;
-
- if (typeof tooltipDataAttrs === 'function') {
- return tooltipDataAttrs(value);
- }
- return tooltipDataAttrs;
- }
-
- getTransformForWeek(weekIndex) {
- if (this.props.horizontal) {
- return `translate(${weekIndex * this.getSquareSizeWithGutter()}, 0)`;
- }
- return `translate(0, ${weekIndex * this.getSquareSizeWithGutter()})`;
- }
-
- getTransformForWeekdayLabels() {
- if (this.props.horizontal) {
- return `translate(${SQUARE_SIZE}, ${this.getMonthLabelSize()})`;
- }
- return null;
- }
-
- getTransformForMonthLabels() {
- if (this.props.horizontal) {
- return `translate(${this.getWeekdayLabelSize()}, 0)`;
- }
- return `translate(${this.getWeekWidth() +
- MONTH_LABEL_GUTTER_SIZE}, ${this.getWeekdayLabelSize()})`;
- }
-
- getTransformForAllWeeks() {
- if (this.props.horizontal) {
- return `translate(${this.getWeekdayLabelSize()}, ${this.getMonthLabelSize()})`;
- }
- return `translate(0, ${this.getWeekdayLabelSize()})`;
- }
-
- getViewBox() {
- if (this.props.horizontal) {
- return `0 0 ${this.getWidth()} ${this.getHeight()}`;
- }
- return `0 0 ${this.getHeight()} ${this.getWidth()}`;
- }
-
- getSquareCoordinates(dayIndex) {
- if (this.props.horizontal) {
- return [0, dayIndex * this.getSquareSizeWithGutter()];
- }
- return [dayIndex * this.getSquareSizeWithGutter(), 0];
- }
-
- getWeekdayLabelCoordinates(dayIndex) {
- if (this.props.horizontal) {
- return [0, (dayIndex + 1) * SQUARE_SIZE + dayIndex * this.props.gutterSize];
- }
- return [dayIndex * SQUARE_SIZE + dayIndex * this.props.gutterSize, SQUARE_SIZE];
- }
-
- getMonthLabelCoordinates(weekIndex) {
- if (this.props.horizontal) {
- return [
- weekIndex * this.getSquareSizeWithGutter(),
- this.getMonthLabelSize() - MONTH_LABEL_GUTTER_SIZE,
- ];
- }
- const verticalOffset = -2;
- return [0, (weekIndex + 1) * this.getSquareSizeWithGutter() + verticalOffset];
- }
-
- handleClick(value) {
- if (this.props.onClick) {
- this.props.onClick(value);
- }
- }
-
- handleMouseOver(e, value) {
- if (this.props.onMouseOver) {
- this.props.onMouseOver(e, value);
- }
- }
-
- handleMouseLeave(e, value) {
- if (this.props.onMouseLeave) {
- this.props.onMouseLeave(e, value);
- }
- }
-
- renderSquare(dayIndex, index) {
- const indexOutOfRange =
- index < this.getNumEmptyDaysAtStart() ||
- index >= this.getNumEmptyDaysAtStart() + this.getDateDifferenceInDays();
- if (indexOutOfRange && !this.props.showOutOfRangeDays) {
- return null;
- }
- const [x, y] = this.getSquareCoordinates(dayIndex);
- const value = this.getValueForIndex(index);
- const rect = (
- // eslint-disable-next-line jsx-a11y/mouse-events-have-key-events
- this.handleClick(value)}
- onMouseOver={(e) => this.handleMouseOver(e, value)}
- onMouseLeave={(e) => this.handleMouseLeave(e, value)}
- {...this.getTooltipDataAttrsForIndex(index)}
- >
- {this.getTitleForIndex(index)}
-
- );
- const { transformDayElement } = this.props;
- return transformDayElement ? transformDayElement(rect, value, index) : rect;
- }
-
- renderWeek(weekIndex) {
- return (
-
- {getRange(DAYS_IN_WEEK).map((dayIndex) =>
- this.renderSquare(dayIndex, weekIndex * DAYS_IN_WEEK + dayIndex),
- )}
-
- );
- }
-
- renderAllWeeks() {
- return getRange(this.getWeekCount()).map((weekIndex) => this.renderWeek(weekIndex));
- }
-
- renderMonthLabels() {
- if (!this.props.showMonthLabels) {
- return null;
- }
- const weekRange = getRange(this.getWeekCount() - 1); // don't render for last week, because label will be cut off
- return weekRange.map((weekIndex) => {
- const endOfWeek = shiftDate(this.getStartDateWithEmptyDays(), (weekIndex + 1) * DAYS_IN_WEEK);
- const [x, y] = this.getMonthLabelCoordinates(weekIndex);
- return endOfWeek.getDate() >= 1 && endOfWeek.getDate() <= DAYS_IN_WEEK ? (
-
- {this.props.monthLabels[endOfWeek.getMonth()]}
-
- ) : null;
- });
- }
-
- renderWeekdayLabels() {
- if (!this.props.showWeekdayLabels) {
- return null;
- }
- return this.props.weekdayLabels.map((weekdayLabel, dayIndex) => {
- const [x, y] = this.getWeekdayLabelCoordinates(dayIndex);
- const cssClasses = `${
- this.props.horizontal ? '' : `${CSS_PSEDUO_NAMESPACE}small-text`
- } ${CSS_PSEDUO_NAMESPACE}weekday-label`;
- // eslint-disable-next-line no-bitwise
- return dayIndex & 1 ? (
-
- {weekdayLabel}
-
- ) : null;
- });
- }
-
- render() {
- this.valueCache = this.getValueCache(this.props);
-
- return (
-
- );
- }
-}
-
-CalendarHeatmap.propTypes = {
- values: PropTypes.arrayOf(
- PropTypes.shape({
- date: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.instanceOf(Date)])
- .isRequired,
- }).isRequired,
- ).isRequired, // array of objects with date and arbitrary metadata
- numDays: PropTypes.number, // number of days back from endDate to show
- startDate: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.instanceOf(Date)]), // start of date range
- endDate: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.instanceOf(Date)]), // end of date range
- gutterSize: PropTypes.number, // size of space between squares
- horizontal: PropTypes.bool, // whether to orient horizontally or vertically
- showMonthLabels: PropTypes.bool, // whether to show month labels
- showWeekdayLabels: PropTypes.bool, // whether to show weekday labels
- showOutOfRangeDays: PropTypes.bool, // whether to render squares for extra days in week after endDate, and before start date
- tooltipDataAttrs: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), // data attributes to add to square for setting 3rd party tooltips, e.g. { 'data-toggle': 'tooltip' } for bootstrap tooltips
- titleForValue: PropTypes.func, // function which returns title text for value
- classForValue: PropTypes.func, // function which returns html class for value
- monthLabels: PropTypes.arrayOf(PropTypes.string), // An array with 12 strings representing the text from janurary to december
- weekdayLabels: PropTypes.arrayOf(PropTypes.string), // An array with 7 strings representing the text from Sun to Sat
- onClick: PropTypes.func, // callback function when a square is clicked
- onMouseOver: PropTypes.func, // callback function when mouse pointer is over a square
- onMouseLeave: PropTypes.func, // callback function when mouse pointer is left a square
- transformDayElement: PropTypes.func, // function to further transform the svg element for a single day
-};
-
-CalendarHeatmap.defaultProps = {
- numDays: null,
- startDate: dateNDaysAgo(200),
- endDate: new Date(),
- gutterSize: 1,
- horizontal: true,
- showMonthLabels: true,
- showWeekdayLabels: false,
- showOutOfRangeDays: false,
- tooltipDataAttrs: null,
- titleForValue: null,
- classForValue: (value) => (value ? 'color-filled' : 'color-empty'),
- monthLabels: MONTH_LABELS,
- weekdayLabels: DAY_LABELS,
- onClick: null,
- onMouseOver: null,
- onMouseLeave: null,
- transformDayElement: null,
-};
-
-export default CalendarHeatmap;
diff --git a/src/heatmap/index.tsx b/src/heatmap/index.tsx
new file mode 100644
index 0000000..4879eb5
--- /dev/null
+++ b/src/heatmap/index.tsx
@@ -0,0 +1,396 @@
+// @ts-nocheck
+
+import React, {Fragment} from 'react';
+import PropTypes from 'prop-types';
+import memoizeOne from 'memoize-one';
+import {DAYS_IN_WEEK, MILLISECONDS_IN_ONE_DAY, DAY_LABELS, MONTH_LABELS} from './constants';
+import {
+ dateNDaysAgo,
+ shiftDate,
+ getBeginningTimeForDate,
+ convertToDate,
+ getRange,
+} from './helpers';
+import * as dFns from 'date-fns';
+import {MonthLabels} from "@/heatmap/b";
+
+const SQUARE_SIZE = 10;
+const MONTH_LABEL_GUTTER_SIZE = 4;
+export const CSS_PSEDUO_NAMESPACE = 'react-calendar-heatmap-';
+
+class CalendarHeatmap extends React.Component {
+ getDateDifferenceInDays() {
+ const {
+ startDate,
+ endDate
+ } = this.props;
+ return dFns.differenceInCalendarDays(endDate, startDate);
+ }
+
+ getSquareSizeWithGutter() {
+ return SQUARE_SIZE + this.props.gutterSize;
+ }
+
+ getMonthLabelSize() {
+ if (!this.props.showMonthLabels) {
+ return 0;
+ }
+ if (this.props.horizontal) {
+ return SQUARE_SIZE + MONTH_LABEL_GUTTER_SIZE;
+ }
+ return 2 * (SQUARE_SIZE + MONTH_LABEL_GUTTER_SIZE);
+ }
+
+ getWeekdayLabelSize() {
+ if (!this.props.showWeekdayLabels) {
+ return 0;
+ }
+ if (this.props.horizontal) {
+ return 30;
+ }
+ return SQUARE_SIZE * 1.5;
+ }
+
+ getStartDate() {
+ return shiftDate(this.getEndDate(), -this.getDateDifferenceInDays() + 1); // +1 because endDate is inclusive
+ }
+
+ getEndDate() {
+ return getBeginningTimeForDate(convertToDate(this.props.endDate));
+ }
+
+ getStartDateWithEmptyDays() {
+ return shiftDate(this.getStartDate(), -this.getNumEmptyDaysAtStart());
+ }
+
+ getNumEmptyDaysAtStart() {
+ return this.getStartDate().getDay();
+ }
+
+ getNumEmptyDaysAtEnd() {
+ return DAYS_IN_WEEK - 1 - this.getEndDate().getDay();
+ }
+
+ getWeekCount() {
+ const numDaysRoundedToWeek =
+ this.getDateDifferenceInDays() + this.getNumEmptyDaysAtStart() + this.getNumEmptyDaysAtEnd();
+ return Math.ceil(numDaysRoundedToWeek / DAYS_IN_WEEK);
+ }
+
+ getWeekWidth() {
+ return DAYS_IN_WEEK * this.getSquareSizeWithGutter();
+ }
+
+ getWidth() {
+ return (
+ this.getWeekCount() * this.getSquareSizeWithGutter() -
+ (this.props.gutterSize - this.getWeekdayLabelSize())
+ );
+ }
+
+ getHeight() {
+ return (
+ this.getWeekWidth() +
+ (this.getMonthLabelSize() - this.props.gutterSize) +
+ this.getWeekdayLabelSize()
+ );
+ }
+
+ getValueCache = memoizeOne((props) =>
+ props.values.reduce((memo, value) => {
+ const date = convertToDate(value.date);
+ const index = Math.floor((date - this.getStartDateWithEmptyDays()) / MILLISECONDS_IN_ONE_DAY);
+ // eslint-disable-next-line no-param-reassign
+ memo[index] = {
+ value,
+ className: this.props.classForValue(value),
+ title: this.props.titleForValue ? this.props.titleForValue(value) : null,
+ tooltipDataAttrs: this.getTooltipDataAttrsForValue(value),
+ };
+ return memo;
+ }, {}),
+ );
+
+ getValueForIndex(index) {
+ if (this.valueCache[index]) {
+ return this.valueCache[index].value;
+ }
+ return null;
+ }
+
+ getClassNameForIndex(index) {
+ if (this.valueCache[index]) {
+ return this.valueCache[index].className;
+ }
+ return this.props.classForValue(null);
+ }
+
+ getTitleForIndex(index) {
+ if (this.valueCache[index]) {
+ return this.valueCache[index].title;
+ }
+ return this.props.titleForValue ? this.props.titleForValue(null) : null;
+ }
+
+ getTooltipDataAttrsForIndex(index) {
+ if (this.valueCache[index]) {
+ return this.valueCache[index].tooltipDataAttrs;
+ }
+ return this.getTooltipDataAttrsForValue({
+ date: null,
+ count: null
+ });
+ }
+
+ getTooltipDataAttrsForValue(value) {
+ const {tooltipDataAttrs} = this.props;
+
+ if (typeof tooltipDataAttrs === 'function') {
+ return tooltipDataAttrs(value);
+ }
+ return tooltipDataAttrs;
+ }
+
+ getTransformForWeek(weekIndex) {
+ if (this.props.horizontal) {
+ return `translate(${weekIndex * this.getSquareSizeWithGutter()}, 0)`;
+ }
+ return `translate(0, ${weekIndex * this.getSquareSizeWithGutter()})`;
+ }
+
+ getTransformForWeekdayLabels() {
+ if (this.props.horizontal) {
+ return `translate(${SQUARE_SIZE}, ${this.getMonthLabelSize()})`;
+ }
+ return null;
+ }
+
+ getTransformForMonthLabels() {
+ if (this.props.horizontal) {
+ return `translate(${this.getWeekdayLabelSize()}, 0)`;
+ }
+ return `translate(${this.getWeekWidth() +
+ MONTH_LABEL_GUTTER_SIZE}, ${this.getWeekdayLabelSize()})`;
+ }
+
+ getTransformForAllWeeks() {
+ if (this.props.horizontal) {
+ return `translate(${this.getWeekdayLabelSize()}, ${this.getMonthLabelSize()})`;
+ }
+ return `translate(0, ${this.getWeekdayLabelSize()})`;
+ }
+
+ getViewBox() {
+ if (this.props.horizontal) {
+ return `0 0 ${this.getWidth()} ${this.getHeight()}`;
+ }
+ return `0 0 ${this.getHeight()} ${this.getWidth()}`;
+ }
+
+ getSquareCoordinates(dayIndex) {
+ if (this.props.horizontal) {
+ return [0, dayIndex * this.getSquareSizeWithGutter()];
+ }
+ return [dayIndex * this.getSquareSizeWithGutter(), 0];
+ }
+
+ getWeekdayLabelCoordinates(dayIndex) {
+ if (this.props.horizontal) {
+ return [0, (dayIndex + 1) * SQUARE_SIZE + dayIndex * this.props.gutterSize];
+ }
+ return [dayIndex * SQUARE_SIZE + dayIndex * this.props.gutterSize, SQUARE_SIZE];
+ }
+
+ getMonthLabelCoordinates(weekIndex) {
+ if (this.props.horizontal) {
+ return [
+ weekIndex * this.getSquareSizeWithGutter(),
+ this.getMonthLabelSize() - MONTH_LABEL_GUTTER_SIZE,
+ ];
+ }
+ const verticalOffset = -2;
+ return [0, (weekIndex + 1) * this.getSquareSizeWithGutter() + verticalOffset];
+ }
+
+ handleClick(value) {
+ if (this.props.onClick) {
+ this.props.onClick(value);
+ }
+ }
+
+ handleMouseOver(e, value) {
+ if (this.props.onMouseOver) {
+ this.props.onMouseOver(e, value);
+ }
+ }
+
+ handleMouseLeave(e, value) {
+ if (this.props.onMouseLeave) {
+ this.props.onMouseLeave(e, value);
+ }
+ }
+
+ renderSquare(dayIndex, index) {
+ const indexOutOfRange =
+ index < this.getNumEmptyDaysAtStart() ||
+ index >= this.getNumEmptyDaysAtStart() + this.getDateDifferenceInDays();
+ if (indexOutOfRange && !this.props.showOutOfRangeDays) {
+ return null;
+ }
+ const [x, y] = this.getSquareCoordinates(dayIndex);
+ const value = this.getValueForIndex(index);
+ const rect = (
+ // eslint-disable-next-line jsx-a11y/mouse-events-have-key-events
+ this.handleClick(value)}
+ onMouseOver={(e) => this.handleMouseOver(e, value)}
+ onMouseLeave={(e) => this.handleMouseLeave(e, value)}
+ {...this.getTooltipDataAttrsForIndex(index)}
+ >
+ {this.getTitleForIndex(index)}
+
+ );
+ const {transformDayElement} = this.props;
+ return transformDayElement ? transformDayElement(rect, value, index) : rect;
+ }
+
+ renderWeek(weekIndex) {
+ return (
+
+ {getRange(DAYS_IN_WEEK).map((dayIndex) =>
+ this.renderSquare(dayIndex, weekIndex * DAYS_IN_WEEK + dayIndex),
+ )}
+
+ );
+ }
+
+ renderAllWeeks() {
+ return getRange(this.getWeekCount()).map((weekIndex) => this.renderWeek(weekIndex));
+ }
+
+ renderMonthLabels() {
+ if (!this.props.showMonthLabels) {
+ return null;
+ }
+
+ const adapter = (date) => {
+ const [x, y] = this.getMonthLabelCoordinates(dFns.differenceInWeeks(date, this.props.startDate));
+ return {
+ x,
+ y
+ }
+ };
+
+ return <>
+
+ {/*{...a}*/}
+ >
+ }
+
+ renderWeekdayLabels() {
+ if (!this.props.showWeekdayLabels) {
+ return null;
+ }
+ return this.props.weekdayLabels.map((weekdayLabel, dayIndex) => {
+ const [x, y] = this.getWeekdayLabelCoordinates(dayIndex);
+ const cssClasses = `${
+ this.props.horizontal ? '' : `${CSS_PSEDUO_NAMESPACE}small-text`
+ } ${CSS_PSEDUO_NAMESPACE}weekday-label`;
+ // eslint-disable-next-line no-bitwise
+ return dayIndex & 1 ? (
+
+ {weekdayLabel}
+
+ ) : null;
+ });
+ }
+
+ render() {
+ this.valueCache = this.getValueCache(this.props);
+
+ return (
+
+ );
+ }
+}
+
+CalendarHeatmap.propTypes = {
+ values: PropTypes.arrayOf(
+ PropTypes.shape({
+ date: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.instanceOf(Date)])
+ .isRequired,
+ }).isRequired,
+ ).isRequired, // array of objects with date and arbitrary metadata
+ numDays: PropTypes.number, // number of days back from endDate to show
+ startDate: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.instanceOf(Date)]), // start of date range
+ endDate: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.instanceOf(Date)]), // end of date range
+ gutterSize: PropTypes.number, // size of space between squares
+ horizontal: PropTypes.bool, // whether to orient horizontally or vertically
+ showMonthLabels: PropTypes.bool, // whether to show month labels
+ showWeekdayLabels: PropTypes.bool, // whether to show weekday labels
+ showOutOfRangeDays: PropTypes.bool, // whether to render squares for extra days in week after endDate, and before start date
+ tooltipDataAttrs: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), // data attributes to add to square for setting 3rd party tooltips, e.g. { 'data-toggle': 'tooltip' } for bootstrap tooltips
+ titleForValue: PropTypes.func, // function which returns title text for value
+ classForValue: PropTypes.func, // function which returns html class for value
+ monthLabels: PropTypes.arrayOf(PropTypes.string), // An array with 12 strings representing the text from janurary to december
+ weekdayLabels: PropTypes.arrayOf(PropTypes.string), // An array with 7 strings representing the text from Sun to Sat
+ onClick: PropTypes.func, // callback function when a square is clicked
+ onMouseOver: PropTypes.func, // callback function when mouse pointer is over a square
+ onMouseLeave: PropTypes.func, // callback function when mouse pointer is left a square
+ transformDayElement: PropTypes.func, // function to further transform the svg element for a single day
+};
+
+CalendarHeatmap.defaultProps = {
+ numDays: null,
+ startDate: dateNDaysAgo(200),
+ endDate: new Date(),
+ gutterSize: 1,
+ horizontal: true,
+ showMonthLabels: true,
+ showWeekdayLabels: false,
+ showOutOfRangeDays: false,
+ tooltipDataAttrs: null,
+ titleForValue: null,
+ classForValue: (value) => (value ? 'color-filled' : 'color-empty'),
+ monthLabels: MONTH_LABELS,
+ weekdayLabels: DAY_LABELS,
+ onClick: null,
+ onMouseOver: null,
+ onMouseLeave: null,
+ transformDayElement: null,
+};
+
+export default CalendarHeatmap;