@pearpages/heatmap 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +37 -47
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
[](https://www.npmjs.com/package/@pearpages/heatmap)
|
|
2
|
+
[](https://github.com/pearpages/heatmap/actions)
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
[](https://www.npmjs.com/package/@pearpages/heatmap)
|
|
5
|
+
|
|
1
6
|
# Heatmap
|
|
2
7
|
|
|
3
8
|
## Getting started
|
package/dist/index.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ interface ContributionHeatmapProps {
|
|
|
27
27
|
};
|
|
28
28
|
className?: string;
|
|
29
29
|
}
|
|
30
|
-
declare function ContributionHeatmap({ data: {
|
|
30
|
+
declare function ContributionHeatmap({ data: { period, weeks }, className, }: ContributionHeatmapProps): react_jsx_runtime.JSX.Element;
|
|
31
31
|
|
|
32
32
|
declare function ContributionHeatmapExample(): react_jsx_runtime.JSX.Element;
|
|
33
33
|
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
|
|
4
|
-
// src/
|
|
4
|
+
// src/shared/models.tsx
|
|
5
5
|
var monthNames = [
|
|
6
6
|
"Jan",
|
|
7
7
|
"Feb",
|
|
@@ -74,31 +74,8 @@ function getMonthsForHeader({
|
|
|
74
74
|
}
|
|
75
75
|
return months;
|
|
76
76
|
}
|
|
77
|
-
function Legend() {
|
|
78
|
-
return /* @__PURE__ */ jsxs("div", { className: "contribution-heatmap__legend", children: [
|
|
79
|
-
/* @__PURE__ */ jsx("span", { className: "contribution-heatmap__legend-text", children: "Less" }),
|
|
80
|
-
[0, 1, 2, 3, 4].map((level) => /* @__PURE__ */ jsx(
|
|
81
|
-
"div",
|
|
82
|
-
{
|
|
83
|
-
className: `contribution-heatmap__legend-item contribution-heatmap__legend-item--level-${level}`,
|
|
84
|
-
title: `Level ${level}`
|
|
85
|
-
},
|
|
86
|
-
level
|
|
87
|
-
)),
|
|
88
|
-
/* @__PURE__ */ jsx("span", { className: "contribution-heatmap__legend-text", children: "More" })
|
|
89
|
-
] });
|
|
90
|
-
}
|
|
91
|
-
function Header({ contributions }) {
|
|
92
|
-
return /* @__PURE__ */ jsxs("div", { className: "contribution-heatmap__header", children: [
|
|
93
|
-
/* @__PURE__ */ jsx("h3", { className: "contribution-heatmap__title", children: "Activity Overview" }),
|
|
94
|
-
/* @__PURE__ */ jsxs("p", { className: "contribution-heatmap__subtitle", children: [
|
|
95
|
-
contributions,
|
|
96
|
-
' "healthy" days in the last year'
|
|
97
|
-
] })
|
|
98
|
-
] });
|
|
99
|
-
}
|
|
100
77
|
|
|
101
|
-
// src/
|
|
78
|
+
// src/shared/formatTooltip.tsx
|
|
102
79
|
function isInRange(date, { start, end }) {
|
|
103
80
|
const actualStartDate = new Date(start);
|
|
104
81
|
const actualEndDate = new Date(end);
|
|
@@ -118,6 +95,20 @@ var formatTooltip = (contribution, { start, end }) => {
|
|
|
118
95
|
}
|
|
119
96
|
return `${formattedDate}: ${contribution.count} contribution${contribution.count !== 1 ? "s" : ""}`;
|
|
120
97
|
};
|
|
98
|
+
function Legend() {
|
|
99
|
+
return /* @__PURE__ */ jsxs("div", { className: "contribution-heatmap__legend", children: [
|
|
100
|
+
/* @__PURE__ */ jsx("span", { className: "contribution-heatmap__legend-text", children: "Less" }),
|
|
101
|
+
[0, 1, 2, 3, 4].map((level) => /* @__PURE__ */ jsx(
|
|
102
|
+
"div",
|
|
103
|
+
{
|
|
104
|
+
className: `contribution-heatmap__legend-item contribution-heatmap__legend-item--level-${level}`,
|
|
105
|
+
title: `Level ${level}`
|
|
106
|
+
},
|
|
107
|
+
level
|
|
108
|
+
)),
|
|
109
|
+
/* @__PURE__ */ jsx("span", { className: "contribution-heatmap__legend-text", children: "More" })
|
|
110
|
+
] });
|
|
111
|
+
}
|
|
121
112
|
|
|
122
113
|
// src/ContributionHeatmap/addExtraWeekIfNeeded.ts
|
|
123
114
|
var createEmptyContribution = (date) => ({
|
|
@@ -145,13 +136,12 @@ function addExtraWeekIfNeeded(weeks) {
|
|
|
145
136
|
return [...weeks, extraWeek];
|
|
146
137
|
}
|
|
147
138
|
function ContributionHeatmap({
|
|
148
|
-
data: {
|
|
139
|
+
data: { period: period2, weeks },
|
|
149
140
|
className = ""
|
|
150
141
|
}) {
|
|
151
142
|
const adjustedWeeks = addExtraWeekIfNeeded(weeks);
|
|
152
143
|
const months = getMonthsForHeader({ weeks: adjustedWeeks, period: period2 });
|
|
153
144
|
return /* @__PURE__ */ jsxs("div", { className: `contribution-heatmap ${className}`, children: [
|
|
154
|
-
/* @__PURE__ */ jsx(Header, { contributions: contribution.filter((d) => d.count > 0).length }),
|
|
155
145
|
/* @__PURE__ */ jsxs("table", { className: "contribution-heatmap__table", children: [
|
|
156
146
|
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
157
147
|
/* @__PURE__ */ jsx("th", { className: "contribution-heatmap__day-header" }),
|
|
@@ -168,17 +158,17 @@ function ContributionHeatmap({
|
|
|
168
158
|
/* @__PURE__ */ jsx("tbody", { children: dayNames.map((dayName, dayIndex) => /* @__PURE__ */ jsxs("tr", { children: [
|
|
169
159
|
/* @__PURE__ */ jsx("td", { className: "contribution-heatmap__day-label", children: window.innerWidth > 768 ? dayName : dayName.charAt(0) }),
|
|
170
160
|
adjustedWeeks.map((week, weekIndex) => {
|
|
171
|
-
const
|
|
161
|
+
const contribution = week[dayIndex];
|
|
172
162
|
return /* @__PURE__ */ jsx(
|
|
173
163
|
"td",
|
|
174
164
|
{
|
|
175
|
-
className: `contribution-heatmap__day contribution-heatmap__day--level-${
|
|
176
|
-
title: formatTooltip(
|
|
177
|
-
"aria-label": formatTooltip(
|
|
165
|
+
className: `contribution-heatmap__day contribution-heatmap__day--level-${contribution.level}`,
|
|
166
|
+
title: formatTooltip(contribution, period2),
|
|
167
|
+
"aria-label": formatTooltip(contribution, period2),
|
|
178
168
|
role: "button",
|
|
179
169
|
tabIndex: 0,
|
|
180
|
-
"data-count":
|
|
181
|
-
"data-date":
|
|
170
|
+
"data-count": contribution.count,
|
|
171
|
+
"data-date": contribution.date,
|
|
182
172
|
style: {
|
|
183
173
|
"--animation-delay": `${(weekIndex * 7 + dayIndex) * 5e-3}s`
|
|
184
174
|
}
|
|
@@ -192,7 +182,18 @@ function ContributionHeatmap({
|
|
|
192
182
|
] });
|
|
193
183
|
}
|
|
194
184
|
|
|
195
|
-
// src/ContributionHeatmap/
|
|
185
|
+
// src/ContributionHeatmap/getLevel.ts
|
|
186
|
+
var getLevel = (count) => {
|
|
187
|
+
let level = 0;
|
|
188
|
+
if (count === 0) level = 0;
|
|
189
|
+
else if (count <= 2) level = 1;
|
|
190
|
+
else if (count <= 5) level = 2;
|
|
191
|
+
else if (count <= 8) level = 3;
|
|
192
|
+
else level = 4;
|
|
193
|
+
return level;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
// src/mocks/createRealisticMockedCount.ts
|
|
196
197
|
var isSummerMonth = (month) => {
|
|
197
198
|
return month >= 5 && month <= 7;
|
|
198
199
|
};
|
|
@@ -215,18 +216,7 @@ function createRealisticMockedCount(date) {
|
|
|
215
216
|
return count;
|
|
216
217
|
}
|
|
217
218
|
|
|
218
|
-
// src/
|
|
219
|
-
var getLevel = (count) => {
|
|
220
|
-
let level = 0;
|
|
221
|
-
if (count === 0) level = 0;
|
|
222
|
-
else if (count <= 2) level = 1;
|
|
223
|
-
else if (count <= 5) level = 2;
|
|
224
|
-
else if (count <= 8) level = 3;
|
|
225
|
-
else level = 4;
|
|
226
|
-
return level;
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
// src/ContributionHeatmap/generateMockData.tsx
|
|
219
|
+
// src/mocks/generateMockData.tsx
|
|
230
220
|
var getRandomCount = () => Math.floor(Math.random() * 15);
|
|
231
221
|
function getRange(period2) {
|
|
232
222
|
if (period2 !== "lastYear") {
|
|
@@ -254,7 +244,7 @@ function generateMockData({
|
|
|
254
244
|
return data;
|
|
255
245
|
}
|
|
256
246
|
|
|
257
|
-
// src/
|
|
247
|
+
// src/shared/groupByWeeks.ts
|
|
258
248
|
var createEmpyContribution = (date) => ({
|
|
259
249
|
date,
|
|
260
250
|
count: 0,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ContributionHeatmap/models.tsx","../src/ContributionHeatmap/getMonthsForHeader.ts","../src/ContributionHeatmap/Legend.tsx","../src/ContributionHeatmap/Header.tsx","../src/ContributionHeatmap/formatTooltip.tsx","../src/ContributionHeatmap/addExtraWeekIfNeeded.ts","../src/ContributionHeatmap/index.tsx","../src/ContributionHeatmap/createRealisticMockedCount.ts","../src/ContributionHeatmap/getLevel.ts","../src/ContributionHeatmap/generateMockData.tsx","../src/ContributionHeatmap/groupByWeeks.ts","../src/Example/ControlGroups.tsx","../src/Example/index.tsx"],"names":["period","jsxs","jsx","contribution","Fragment"],"mappings":"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","file":"index.js","sourcesContent":["type Theme = '' | 'ocean' | 'sunset' | 'purple';\n\ninterface ContributionData {\n date: string;\n count: number;\n level: 0 | 1 | 2 | 3 | 4;\n}\n\ntype Week = [\n ContributionData,\n ContributionData,\n ContributionData,\n ContributionData,\n ContributionData,\n ContributionData,\n ContributionData,\n];\n\ntype Period = { start: Date; end: Date };\n\nconst monthNames = [\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] as const;\nconst dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] as const;\n\nfunction getLastYearPeriod(): Period {\n const start = new Date(\n new Date().setFullYear(\n new Date().getFullYear() - 1,\n new Date().getMonth(),\n new Date().getDate() + 1,\n ),\n );\n const end = new Date();\n return { start, end };\n}\n\nconst createDateString = (date: Date): string =>\n date.toISOString().split('T')[0];\n\nexport type { ContributionData, Week, Period, Theme };\nexport { monthNames, dayNames, createDateString, getLastYearPeriod };\n","import { monthNames, type Period, type Week } from './models';\n\nfunction getMonthsForHeader({\n weeks,\n period,\n}: {\n weeks: Week[];\n period: Period;\n}): {\n name: string;\n span: number;\n}[] {\n const months: { name: string; span: number }[] = [];\n const { start, end } = period;\n let currentMonth = -1;\n let currentSpan = 0;\n\n weeks.forEach((week) => {\n if (week.length > 0) {\n // Find the first day in the week that falls within our actual data range\n let monthToUse = -1;\n const actualStartDate = new Date(start);\n const actualEndDate = new Date(end);\n\n for (const day of week) {\n const dayDate = new Date(day.date);\n if (dayDate >= actualStartDate && dayDate <= actualEndDate) {\n monthToUse = dayDate.getMonth();\n break;\n }\n }\n\n // If no day in the week is in our actual range, use the middle day (Wednesday)\n if (monthToUse === -1) {\n const middleDay = week[3]; // Wednesday (index 3)\n monthToUse = new Date(middleDay.date).getMonth();\n }\n\n if (monthToUse !== currentMonth) {\n if (currentMonth !== -1) {\n months.push({ name: monthNames[currentMonth], span: currentSpan });\n }\n currentMonth = monthToUse;\n currentSpan = 1;\n } else {\n currentSpan++;\n }\n }\n });\n\n if (currentMonth !== -1) {\n months.push({ name: monthNames[currentMonth], span: currentSpan });\n }\n\n // If the last month only has one week, add an extra week for better visual balance\n if (months.length > 0 && months[months.length - 1].span === 1) {\n months[months.length - 1].span = 2;\n }\n\n return months;\n}\n\nexport { getMonthsForHeader };\n","function Legend(): React.ReactNode {\n return (\n <div className=\"contribution-heatmap__legend\">\n <span className=\"contribution-heatmap__legend-text\">Less</span>\n {[0, 1, 2, 3, 4].map((level) => (\n <div\n key={level}\n className={`contribution-heatmap__legend-item contribution-heatmap__legend-item--level-${level}`}\n title={`Level ${level}`}\n ></div>\n ))}\n <span className=\"contribution-heatmap__legend-text\">More</span>\n </div>\n );\n}\n\nexport { Legend };\n","function Header({ contributions }: { contributions: number }): React.ReactNode {\n return (\n <div className=\"contribution-heatmap__header\">\n <h3 className=\"contribution-heatmap__title\">Activity Overview</h3>\n <p className=\"contribution-heatmap__subtitle\">\n {contributions} \"healthy\" days in the last year\n </p>\n </div>\n );\n}\n\nexport { Header };\n","import type { ContributionData, Period } from './models';\n\nfunction isInRange(date: Date, { start, end }: Period): boolean {\n const actualStartDate = new Date(start);\n const actualEndDate = new Date(end);\n const contributionDate = new Date(date);\n\n return contributionDate > actualStartDate && contributionDate < actualEndDate;\n}\n\nconst formatTooltip = (\n contribution: ContributionData,\n { start, end }: Period,\n): string => {\n const date = new Date(contribution.date);\n const formattedDate = date.toLocaleDateString('en-US', {\n weekday: 'short',\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n\n if (\n !isInRange(new Date(contribution.date), { start, end }) ||\n contribution.count === 0\n ) {\n return `${formattedDate}: No contributions`;\n }\n\n return `${formattedDate}: ${contribution.count} contribution${contribution.count !== 1 ? 's' : ''}`;\n};\n\nexport { formatTooltip };\n","import { createDateString, type ContributionData, type Week } from './models';\n\nconst createEmptyContribution = (date: string): ContributionData => ({\n date,\n count: 0,\n level: 0,\n});\n\nconst createEmptyWeek = (startDate: Date): Week => {\n const week: ContributionData[] = [];\n const currentDate = new Date(startDate);\n \n for (let day = 0; day < 7; day++) {\n const dateString = createDateString(currentDate);\n week.push(createEmptyContribution(dateString));\n currentDate.setDate(currentDate.getDate() + 1);\n }\n\n return week as Week;\n};\n\n/**\n * Adds an extra empty week if the last month only has one week\n * to match the header span and improve visual balance\n */\nexport function addExtraWeekIfNeeded(weeks: Week[]): Week[] {\n if (weeks.length === 0) return weeks;\n\n // Simple approach: always add an extra week at the end for better balance\n // This ensures the table has an extra column to match the header span\n const lastWeek = weeks[weeks.length - 1];\n const lastDate = new Date(lastWeek[6].date); // Saturday of last week\n const nextWeekStart = new Date(lastDate);\n nextWeekStart.setDate(lastDate.getDate() + 1); // Next Sunday\n \n const extraWeek = createEmptyWeek(nextWeekStart);\n return [...weeks, extraWeek];\n}","import './index.scss';\nimport type { ContributionData, Period, Week as WeekType } from './models';\nimport { getMonthsForHeader } from './getMonthsForHeader';\nimport { Legend } from './Legend';\nimport { Header } from './Header';\nimport { formatTooltip } from './formatTooltip';\nimport { dayNames } from './models';\nimport { addExtraWeekIfNeeded } from './addExtraWeekIfNeeded';\n\ninterface ContributionHeatmapProps {\n data: { contribution: ContributionData[]; period: Period; weeks: WeekType[] };\n className?: string;\n}\n\nfunction ContributionHeatmap({\n data: { contribution, period, weeks },\n className = '',\n}: ContributionHeatmapProps) {\n // Add extra week if needed to match header span\n const adjustedWeeks = addExtraWeekIfNeeded(weeks);\n const months = getMonthsForHeader({ weeks: adjustedWeeks, period });\n\n return (\n <div className={`contribution-heatmap ${className}`}>\n <Header contributions={contribution.filter((d) => d.count > 0).length} />\n\n <table className=\"contribution-heatmap__table\">\n <thead>\n <tr>\n <th className=\"contribution-heatmap__day-header\"></th>\n {months.map((month, index) => (\n <th\n key={index}\n className=\"contribution-heatmap__month-header\"\n colSpan={month.span}\n >\n {month.name}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {dayNames.map((dayName, dayIndex) => (\n <tr key={dayIndex}>\n <td className=\"contribution-heatmap__day-label\">\n {window.innerWidth > 768 ? dayName : dayName.charAt(0)}\n </td>\n {adjustedWeeks.map((week, weekIndex) => {\n const contribution = week[dayIndex];\n return (\n <td\n key={weekIndex}\n className={`contribution-heatmap__day contribution-heatmap__day--level-${contribution.level}`}\n title={formatTooltip(contribution, period)}\n aria-label={formatTooltip(contribution, period)}\n role=\"button\"\n tabIndex={0}\n data-count={contribution.count}\n data-date={contribution.date}\n style={{ \n '--animation-delay': `${(weekIndex * 7 + dayIndex) * 0.005}s` \n } as React.CSSProperties}\n ></td>\n );\n })}\n </tr>\n ))}\n </tbody>\n </table>\n\n <Legend />\n </div>\n );\n}\n\nexport { ContributionHeatmap };\n","import type { ContributionData } from './models';\n\nconst isSummerMonth = (month: number) => {\n return month >= 5 && month <= 7;\n};\n\nexport function createRealisticMockedCount(\n date: Date,\n): ContributionData['count'] {\n // Create realistic patterns\n const dayOfWeek = date.getDay();\n const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;\n const month = date.getMonth();\n\n let baseCount = isWeekend ? 2 : 8;\n\n // Lower activity in summer months (June, July, August)\n if (isSummerMonth(month)) {\n baseCount = Math.max(0, baseCount - 3);\n }\n\n // Add some randomness\n const randomFactor = Math.random();\n let count = 0;\n\n if (randomFactor > 0.3) {\n count = Math.floor(Math.random() * baseCount);\n }\n\n // Occasional high activity days\n if (randomFactor > 0.95) {\n count += Math.floor(Math.random() * 10);\n }\n\n return count;\n}\n","import type { ContributionData } from './models';\n\nconst getLevel = (count: number): ContributionData['level'] => {\n let level: 0 | 1 | 2 | 3 | 4 = 0;\n if (count === 0) level = 0;\n else if (count <= 2) level = 1;\n else if (count <= 5) level = 2;\n else if (count <= 8) level = 3;\n else level = 4;\n\n return level;\n};\n\nexport { getLevel };\n","import { createDateString, type ContributionData, type Period } from './models';\nimport { createRealisticMockedCount } from './createRealisticMockedCount';\nimport { getLevel } from './getLevel';\n\nconst getRandomCount = () => Math.floor(Math.random() * 15);\n\nfunction getRange(period: Period | 'lastYear') {\n if (period !== 'lastYear') {\n return period;\n }\n const end = new Date(); // Today\n const start = new Date();\n start.setFullYear(start.getFullYear() - 1); // One year ago\n return { start, end };\n}\n\nfunction generateMockData({\n period,\n isRealistic,\n}: {\n period: Period | 'lastYear';\n isRealistic: boolean;\n}): ContributionData[] {\n const data: ContributionData[] = [];\n const { start, end } = getRange(period);\n\n for (\n let date = new Date(start);\n date <= end;\n date.setDate(date.getDate() + 1)\n ) {\n const count = isRealistic\n ? createRealisticMockedCount(date)\n : getRandomCount();\n data.push({\n date: createDateString(date),\n count,\n level: getLevel(count),\n });\n }\n\n return data;\n}\n\nexport { generateMockData };\n","import { createDateString, type ContributionData, type Week } from './models';\n\nconst createEmpyContribution = (date: string): ContributionData => ({\n date,\n count: 0,\n level: 0,\n});\n\nconst createContributionMap = (\n contributions: ContributionData[],\n): Map<string, ContributionData> => {\n const contributionMap = new Map<string, ContributionData>();\n contributions.forEach((contribution) => {\n contributionMap.set(contribution.date, contribution);\n });\n return contributionMap;\n};\n\nconst getFirstSunday: (firstDate: Date) => Date = (firstDate) => {\n const startOfWeek = new Date(firstDate);\n startOfWeek.setDate(firstDate.getDate() - firstDate.getDay());\n return startOfWeek;\n};\n\nconst getLastSaturday: (lastDate: Date) => Date = (lastDate) => {\n const endOfWeek = new Date(lastDate);\n endOfWeek.setDate(lastDate.getDate() + (6 - lastDate.getDay()));\n return endOfWeek;\n};\n\nconst createWeek = (\n startDate: Date,\n contributionMap: Map<string, ContributionData>,\n): Week => {\n const week: ContributionData[] = [];\n const currentDate = new Date(startDate);\n for (let day = 0; day < 7; day++) {\n const dateString = createDateString(currentDate);\n const contribution = contributionMap.get(dateString);\n\n if (contribution) {\n week.push(contribution);\n } else {\n week.push(createEmpyContribution(dateString));\n }\n currentDate.setDate(currentDate.getDate() + 1);\n }\n\n return week as Week;\n};\n\nconst groupByWeeks: (contributions: ContributionData[]) => Week[] = (\n contributions,\n) => {\n const weeks: Week[] = [];\n const contributionMap = createContributionMap(contributions);\n\n const firstDay = getFirstSunday(new Date(contributions[0].date));\n const lastDate = getLastSaturday(\n new Date(contributions[contributions.length - 1].date),\n );\n\n const currentDate = new Date(firstDay);\n while (currentDate <= lastDate) {\n weeks.push(createWeek(currentDate, contributionMap));\n currentDate.setDate(currentDate.getDate() + 7);\n }\n\n return weeks;\n};\n\nexport { groupByWeeks };\n","import './controlGroups.scss';\nimport type { Theme } from '@pearpages/heatmap/ContributionHeatmap/models';\n\nexport function ControlGroups({\n actions: { theme, setTheme, hasRealisticData, setHasRealisticData },\n}: {\n actions: {\n theme: Theme;\n setTheme: (theme: Theme) => void;\n hasRealisticData: boolean;\n setHasRealisticData: (use: boolean) => void;\n };\n}) {\n return (\n <>\n <div className=\"control-group\">\n <label className=\"control-group__label\">Theme:</label>\n <div className=\"control-group__buttons\">\n <button\n className={`theme-button ${theme === '' ? 'theme-button--active' : ''}`}\n onClick={() => setTheme('')}\n >\n GitHub\n </button>\n <button\n className={`theme-button ${theme === 'ocean' ? 'theme-button--active' : ''}`}\n onClick={() => setTheme('ocean')}\n >\n Ocean\n </button>\n <button\n className={`theme-button ${theme === 'sunset' ? 'theme-button--active' : ''}`}\n onClick={() => setTheme('sunset')}\n >\n Sunset\n </button>\n <button\n className={`theme-button ${theme === 'purple' ? 'theme-button--active' : ''}`}\n onClick={() => setTheme('purple')}\n >\n Purple\n </button>\n </div>\n </div>\n <div className=\"control-group\">\n <label className=\"control-group__checkbox\">\n <input\n type=\"checkbox\"\n checked={hasRealisticData}\n onChange={(e) => setHasRealisticData(e.target.checked)}\n />\n Use realistic sample data\n </label>\n </div>\n </>\n );\n}\n","import { useState } from 'react';\nimport { ContributionHeatmap } from '@pearpages/heatmap/ContributionHeatmap';\nimport { generateMockData } from '@pearpages/heatmap/ContributionHeatmap/generateMockData';\nimport { getLastYearPeriod, type Theme } from '@pearpages/heatmap/ContributionHeatmap/models';\nimport { groupByWeeks } from '@pearpages/heatmap/ContributionHeatmap/groupByWeeks';\nimport './index.scss';\nimport { ControlGroups } from './ControlGroups';\n\nconst sampleData = generateMockData({ period: 'lastYear', isRealistic: true });\nconst period = getLastYearPeriod();\n\nfunction ContributionHeatmapExample() {\n const [theme, setTheme] = useState<Theme>('');\n const [hasRealisticData, setHasRealisticData] = useState(false);\n\n const contribution = hasRealisticData\n ? sampleData\n : generateMockData({\n period,\n isRealistic: false,\n });\n\n return (\n <>\n <div className=\"example__controls\">\n <ControlGroups\n actions={{ theme, setTheme, hasRealisticData, setHasRealisticData }}\n />\n </div>\n\n <div className=\"example__heatmap\">\n <ContributionHeatmap\n className={theme ? `contribution-heatmap--${theme}` : ''}\n data={{\n weeks: groupByWeeks(contribution),\n contribution,\n period,\n }}\n />\n </div>\n </>\n );\n}\n\nexport { ContributionHeatmapExample };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/shared/models.tsx","../src/ContributionHeatmap/getMonthsForHeader.ts","../src/shared/formatTooltip.tsx","../src/shared/Legend.tsx","../src/ContributionHeatmap/addExtraWeekIfNeeded.ts","../src/ContributionHeatmap/index.tsx","../src/ContributionHeatmap/getLevel.ts","../src/mocks/createRealisticMockedCount.ts","../src/mocks/generateMockData.tsx","../src/shared/groupByWeeks.ts","../src/Example/ControlGroups.tsx","../src/Example/index.tsx"],"names":["period","jsxs","jsx","Fragment"],"mappings":"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","file":"index.js","sourcesContent":["type Theme = '' | 'ocean' | 'sunset' | 'purple';\n\ninterface ContributionData {\n date: string;\n count: number;\n level: 0 | 1 | 2 | 3 | 4;\n}\n\ntype Week = [\n ContributionData,\n ContributionData,\n ContributionData,\n ContributionData,\n ContributionData,\n ContributionData,\n ContributionData,\n];\n\ntype Period = { start: Date; end: Date };\n\nconst monthNames = [\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] as const;\nconst dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] as const;\n\nfunction getLastYearPeriod(): Period {\n const start = new Date(\n new Date().setFullYear(\n new Date().getFullYear() - 1,\n new Date().getMonth(),\n new Date().getDate() + 1,\n ),\n );\n const end = new Date();\n return { start, end };\n}\n\nconst createDateString = (date: Date): string =>\n date.toISOString().split('T')[0];\n\nexport type { ContributionData, Week, Period, Theme };\nexport { monthNames, dayNames, createDateString, getLastYearPeriod };\n","import { monthNames, type Period, type Week } from '@/shared/models';\n\nfunction getMonthsForHeader({\n weeks,\n period,\n}: {\n weeks: Week[];\n period: Period;\n}): {\n name: string;\n span: number;\n}[] {\n const months: { name: string; span: number }[] = [];\n const { start, end } = period;\n let currentMonth = -1;\n let currentSpan = 0;\n\n weeks.forEach((week) => {\n if (week.length > 0) {\n // Find the first day in the week that falls within our actual data range\n let monthToUse = -1;\n const actualStartDate = new Date(start);\n const actualEndDate = new Date(end);\n\n for (const day of week) {\n const dayDate = new Date(day.date);\n if (dayDate >= actualStartDate && dayDate <= actualEndDate) {\n monthToUse = dayDate.getMonth();\n break;\n }\n }\n\n // If no day in the week is in our actual range, use the middle day (Wednesday)\n if (monthToUse === -1) {\n const middleDay = week[3]; // Wednesday (index 3)\n monthToUse = new Date(middleDay.date).getMonth();\n }\n\n if (monthToUse !== currentMonth) {\n if (currentMonth !== -1) {\n months.push({ name: monthNames[currentMonth], span: currentSpan });\n }\n currentMonth = monthToUse;\n currentSpan = 1;\n } else {\n currentSpan++;\n }\n }\n });\n\n if (currentMonth !== -1) {\n months.push({ name: monthNames[currentMonth], span: currentSpan });\n }\n\n // If the last month only has one week, add an extra week for better visual balance\n if (months.length > 0 && months[months.length - 1].span === 1) {\n months[months.length - 1].span = 2;\n }\n\n return months;\n}\n\nexport { getMonthsForHeader };\n","import type { ContributionData, Period } from '@/shared/models';\n\nfunction isInRange(date: Date, { start, end }: Period): boolean {\n const actualStartDate = new Date(start);\n const actualEndDate = new Date(end);\n const contributionDate = new Date(date);\n\n return contributionDate > actualStartDate && contributionDate < actualEndDate;\n}\n\nconst formatTooltip = (\n contribution: ContributionData,\n { start, end }: Period,\n): string => {\n const date = new Date(contribution.date);\n const formattedDate = date.toLocaleDateString('en-US', {\n weekday: 'short',\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n\n if (\n !isInRange(new Date(contribution.date), { start, end }) ||\n contribution.count === 0\n ) {\n return `${formattedDate}: No contributions`;\n }\n\n return `${formattedDate}: ${contribution.count} contribution${contribution.count !== 1 ? 's' : ''}`;\n};\n\nexport { formatTooltip };\n","function Legend(): React.ReactNode {\n return (\n <div className=\"contribution-heatmap__legend\">\n <span className=\"contribution-heatmap__legend-text\">Less</span>\n {[0, 1, 2, 3, 4].map((level) => (\n <div\n key={level}\n className={`contribution-heatmap__legend-item contribution-heatmap__legend-item--level-${level}`}\n title={`Level ${level}`}\n ></div>\n ))}\n <span className=\"contribution-heatmap__legend-text\">More</span>\n </div>\n );\n}\n\nexport { Legend };\n","import { createDateString, type ContributionData, type Week } from '@/shared/models';\n\nconst createEmptyContribution = (date: string): ContributionData => ({\n date,\n count: 0,\n level: 0,\n});\n\nconst createEmptyWeek = (startDate: Date): Week => {\n const week: ContributionData[] = [];\n const currentDate = new Date(startDate);\n \n for (let day = 0; day < 7; day++) {\n const dateString = createDateString(currentDate);\n week.push(createEmptyContribution(dateString));\n currentDate.setDate(currentDate.getDate() + 1);\n }\n\n return week as Week;\n};\n\n/**\n * Adds an extra empty week if the last month only has one week\n * to match the header span and improve visual balance\n */\nexport function addExtraWeekIfNeeded(weeks: Week[]): Week[] {\n if (weeks.length === 0) return weeks;\n\n // Simple approach: always add an extra week at the end for better balance\n // This ensures the table has an extra column to match the header span\n const lastWeek = weeks[weeks.length - 1];\n const lastDate = new Date(lastWeek[6].date); // Saturday of last week\n const nextWeekStart = new Date(lastDate);\n nextWeekStart.setDate(lastDate.getDate() + 1); // Next Sunday\n \n const extraWeek = createEmptyWeek(nextWeekStart);\n return [...weeks, extraWeek];\n}","import './index.scss';\nimport type { ContributionData, Period, Week as WeekType } from '../shared/models';\nimport { getMonthsForHeader } from './getMonthsForHeader';\nimport { formatTooltip } from '@/shared/formatTooltip';\nimport { dayNames } from '@/shared/models';\nimport { Legend } from '@/shared/Legend';\nimport { addExtraWeekIfNeeded } from './addExtraWeekIfNeeded';\n\ninterface ContributionHeatmapProps {\n data: { contribution: ContributionData[]; period: Period; weeks: WeekType[] };\n className?: string;\n}\n\nfunction ContributionHeatmap({\n data: { period, weeks },\n className = '',\n}: ContributionHeatmapProps) {\n // Add extra week if needed to match header span\n const adjustedWeeks = addExtraWeekIfNeeded(weeks);\n const months = getMonthsForHeader({ weeks: adjustedWeeks, period });\n\n return (\n <div className={`contribution-heatmap ${className}`}>\n <table className=\"contribution-heatmap__table\">\n <thead>\n <tr>\n <th className=\"contribution-heatmap__day-header\"></th>\n {months.map((month, index) => (\n <th\n key={index}\n className=\"contribution-heatmap__month-header\"\n colSpan={month.span}\n >\n {month.name}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {dayNames.map((dayName, dayIndex) => (\n <tr key={dayIndex}>\n <td className=\"contribution-heatmap__day-label\">\n {window.innerWidth > 768 ? dayName : dayName.charAt(0)}\n </td>\n {adjustedWeeks.map((week, weekIndex) => {\n const contribution = week[dayIndex];\n return (\n <td\n key={weekIndex}\n className={`contribution-heatmap__day contribution-heatmap__day--level-${contribution.level}`}\n title={formatTooltip(contribution, period)}\n aria-label={formatTooltip(contribution, period)}\n role=\"button\"\n tabIndex={0}\n data-count={contribution.count}\n data-date={contribution.date}\n style={{ \n '--animation-delay': `${(weekIndex * 7 + dayIndex) * 0.005}s` \n } as React.CSSProperties}\n ></td>\n );\n })}\n </tr>\n ))}\n </tbody>\n </table>\n\n <Legend />\n </div>\n );\n}\n\nexport { ContributionHeatmap };\n","import type { ContributionData } from '@/shared/models';\n\nconst getLevel = (count: number): ContributionData['level'] => {\n let level: 0 | 1 | 2 | 3 | 4 = 0;\n if (count === 0) level = 0;\n else if (count <= 2) level = 1;\n else if (count <= 5) level = 2;\n else if (count <= 8) level = 3;\n else level = 4;\n\n return level;\n};\n\nexport { getLevel };\n","import type { ContributionData } from '@/shared/models';\n\nconst isSummerMonth = (month: number) => {\n return month >= 5 && month <= 7;\n};\n\nexport function createRealisticMockedCount(\n date: Date,\n): ContributionData['count'] {\n // Create realistic patterns\n const dayOfWeek = date.getDay();\n const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;\n const month = date.getMonth();\n\n let baseCount = isWeekend ? 2 : 8;\n\n // Lower activity in summer months (June, July, August)\n if (isSummerMonth(month)) {\n baseCount = Math.max(0, baseCount - 3);\n }\n\n // Add some randomness\n const randomFactor = Math.random();\n let count = 0;\n\n if (randomFactor > 0.3) {\n count = Math.floor(Math.random() * baseCount);\n }\n\n // Occasional high activity days\n if (randomFactor > 0.95) {\n count += Math.floor(Math.random() * 10);\n }\n\n return count;\n}\n","import { createDateString, type ContributionData, type Period } from '@/shared/models';\nimport { getLevel } from '@/ContributionHeatmap/getLevel';\nimport { createRealisticMockedCount } from './createRealisticMockedCount';\n\nconst getRandomCount = () => Math.floor(Math.random() * 15);\n\nfunction getRange(period: Period | 'lastYear') {\n if (period !== 'lastYear') {\n return period;\n }\n const end = new Date(); // Today\n const start = new Date();\n start.setFullYear(start.getFullYear() - 1); // One year ago\n return { start, end };\n}\n\nfunction generateMockData({\n period,\n isRealistic,\n}: {\n period: Period | 'lastYear';\n isRealistic: boolean;\n}): ContributionData[] {\n const data: ContributionData[] = [];\n const { start, end } = getRange(period);\n\n for (\n let date = new Date(start);\n date <= end;\n date.setDate(date.getDate() + 1)\n ) {\n const count = isRealistic\n ? createRealisticMockedCount(date)\n : getRandomCount();\n data.push({\n date: createDateString(date),\n count,\n level: getLevel(count),\n });\n }\n\n return data;\n}\n\nexport { generateMockData };\n","import { createDateString, type ContributionData, type Week } from '@/shared/models';\n\nconst createEmpyContribution = (date: string): ContributionData => ({\n date,\n count: 0,\n level: 0,\n});\n\nconst createContributionMap = (\n contributions: ContributionData[],\n): Map<string, ContributionData> => {\n const contributionMap = new Map<string, ContributionData>();\n contributions.forEach((contribution) => {\n contributionMap.set(contribution.date, contribution);\n });\n return contributionMap;\n};\n\nconst getFirstSunday: (firstDate: Date) => Date = (firstDate) => {\n const startOfWeek = new Date(firstDate);\n startOfWeek.setDate(firstDate.getDate() - firstDate.getDay());\n return startOfWeek;\n};\n\nconst getLastSaturday: (lastDate: Date) => Date = (lastDate) => {\n const endOfWeek = new Date(lastDate);\n endOfWeek.setDate(lastDate.getDate() + (6 - lastDate.getDay()));\n return endOfWeek;\n};\n\nconst createWeek = (\n startDate: Date,\n contributionMap: Map<string, ContributionData>,\n): Week => {\n const week: ContributionData[] = [];\n const currentDate = new Date(startDate);\n for (let day = 0; day < 7; day++) {\n const dateString = createDateString(currentDate);\n const contribution = contributionMap.get(dateString);\n\n if (contribution) {\n week.push(contribution);\n } else {\n week.push(createEmpyContribution(dateString));\n }\n currentDate.setDate(currentDate.getDate() + 1);\n }\n\n return week as Week;\n};\n\nconst groupByWeeks: (contributions: ContributionData[]) => Week[] = (\n contributions,\n) => {\n const weeks: Week[] = [];\n const contributionMap = createContributionMap(contributions);\n\n const firstDay = getFirstSunday(new Date(contributions[0].date));\n const lastDate = getLastSaturday(\n new Date(contributions[contributions.length - 1].date),\n );\n\n const currentDate = new Date(firstDay);\n while (currentDate <= lastDate) {\n weeks.push(createWeek(currentDate, contributionMap));\n currentDate.setDate(currentDate.getDate() + 7);\n }\n\n return weeks;\n};\n\nexport { groupByWeeks };\n","import './controlGroups.scss';\nimport type { Theme } from '@/shared/models';\n\nexport function ControlGroups({\n actions: { theme, setTheme, hasRealisticData, setHasRealisticData },\n}: {\n actions: {\n theme: Theme;\n setTheme: (theme: Theme) => void;\n hasRealisticData: boolean;\n setHasRealisticData: (use: boolean) => void;\n };\n}) {\n return (\n <>\n <div className=\"control-group\">\n <label className=\"control-group__label\">Theme:</label>\n <div className=\"control-group__buttons\">\n <button\n className={`theme-button ${theme === '' ? 'theme-button--active' : ''}`}\n onClick={() => setTheme('')}\n >\n GitHub\n </button>\n <button\n className={`theme-button ${theme === 'ocean' ? 'theme-button--active' : ''}`}\n onClick={() => setTheme('ocean')}\n >\n Ocean\n </button>\n <button\n className={`theme-button ${theme === 'sunset' ? 'theme-button--active' : ''}`}\n onClick={() => setTheme('sunset')}\n >\n Sunset\n </button>\n <button\n className={`theme-button ${theme === 'purple' ? 'theme-button--active' : ''}`}\n onClick={() => setTheme('purple')}\n >\n Purple\n </button>\n </div>\n </div>\n <div className=\"control-group\">\n <label className=\"control-group__checkbox\">\n <input\n type=\"checkbox\"\n checked={hasRealisticData}\n onChange={(e) => setHasRealisticData(e.target.checked)}\n />\n Use realistic sample data\n </label>\n </div>\n </>\n );\n}\n","import { useState } from 'react';\nimport { ContributionHeatmap } from '@/ContributionHeatmap';\nimport { generateMockData } from '@/mocks/generateMockData';\nimport { getLastYearPeriod, type Theme } from '@/shared/models';\nimport { groupByWeeks } from '@/shared/groupByWeeks';\nimport './index.scss';\nimport { ControlGroups } from './ControlGroups';\n\nconst sampleData = generateMockData({ period: 'lastYear', isRealistic: true });\nconst period = getLastYearPeriod();\n\nfunction ContributionHeatmapExample() {\n const [theme, setTheme] = useState<Theme>('');\n const [hasRealisticData, setHasRealisticData] = useState(false);\n\n const contribution = hasRealisticData\n ? sampleData\n : generateMockData({\n period,\n isRealistic: false,\n });\n\n return (\n <>\n <div className=\"example__controls\">\n <ControlGroups\n actions={{ theme, setTheme, hasRealisticData, setHasRealisticData }}\n />\n </div>\n\n <div className=\"example__heatmap\">\n <ContributionHeatmap\n className={theme ? `contribution-heatmap--${theme}` : ''}\n data={{\n weeks: groupByWeeks(contribution),\n contribution,\n period,\n }}\n />\n </div>\n </>\n );\n}\n\nexport { ContributionHeatmapExample };\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pearpages/heatmap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/pearpages/heatmap"
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"test": "vitest"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"react": "
|
|
33
|
-
"react-dom": "
|
|
32
|
+
"react": "^19.1.1",
|
|
33
|
+
"react-dom": "^19.1.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@testing-library/react": "^16",
|