UNPKG

react-contribution-calendar

Version:
726 lines (725 loc) 21.6 kB
import './styles/index.css'; import { jsx as u, jsxs as C, Fragment as O } from "react/jsx-runtime"; import { useRef as ee, useState as j, useEffect as P, useMemo as E } from "react"; import { createPortal as ue } from "react-dom"; const he = "_calendarLabel_1itwh_1", ie = "_calendarLabelText_1itwh_7", G = { calendarLabel: he, calendarLabelText: ie }; function q({ children: e, textColor: l, style: r, colSpan: t, hide: d, ...c }) { return /* @__PURE__ */ u("td", { className: G.calendarLabel, style: r, colSpan: t, ...c, children: d ? void 0 : /* @__PURE__ */ u("span", { className: G.calendarLabelText, "aria-hidden": "true", style: { color: l }, children: e }) }); } const me = { // light themes empty: { level0: "#ffffff", level1: "#ffffff", level2: "#ffffff", level3: "#ffffff", level4: "#ffffff" }, grass: { level0: "#ebedf0", level1: "#9be9a8", level2: "#40c463", level3: "#30a14e", level4: "#216e39" }, cherry: { level0: "#fff0f6", level1: "#ffdeeb", level2: "#faa2c1", level3: "#f06595", level4: "#a61e4d" }, cherry_blossom: { level0: "#dedad2", level1: "#e4bcad", level2: "#df979e", level3: "#d7658b", level4: "#c80064" }, pink: { level0: "#ffeffc", level1: "#ffc2f6", level2: "#ffa4f1", level3: "#ff86ed", level4: "#ff68e9" }, ocean: { level0: "#ccf6ff", level1: "#80d0ff", level2: "#00d1ff", level3: "#00ffff", level4: "#0040ff" }, sky: { level0: "#ffffff", level1: "#badbdb", level2: "#98d1d1", level3: "#76c8c8", level4: "#54bebe" }, halloween: { level0: "#ebedf0", level1: "#ffee4a", level2: "#ffc501", level3: "#fe9600", level4: "#03001c" }, winter: { level0: "#ebedf0", level1: "#b6e3ff", level2: "#54aeff", level3: "#0969da", level4: "#0a3069" }, purquoise: { level0: "#dee6ee", level1: "#bdcddc", level2: "#9db4cb", level3: "#7c9bb9", level4: "#5b82a8" }, mustard: { level0: "#cc7b00", level1: "#f5b40d", level2: "#f9d26e", level3: "#fbe19e", level4: "#fdf0cf" }, gray: { level0: "#FFFFFF", level1: "#D4D4D4", level2: "#B4B4B4", level3: "#909090", level4: "#494848" }, vomit: { level0: "#badbdb", level1: "#669999", level2: "#666699", level3: "#663399", level4: "#660099" }, neonpunk: { level0: "#FFFFFF", level1: "#B6FFFE", level2: "#48FDFE", level3: "#F20BF8", level4: "#EE018F" }, citypop: { level0: "#c2b3ff", level1: "#5B33FE", level2: "#b84dff", level3: "#d52dff", level4: "#FA43F9" }, coral: { level0: "#fef3e7", level1: "#f7b267", level2: "#f79d65", level3: "#f4845f", level4: "#f25c54" }, emoji_positive: { level0: "🫥", level1: "😢", level2: "😞", level3: "🙂", level4: "😃" }, emoji_negative: { level0: "🫥", level1: "😃", level2: "🙂", level3: "😕", level4: "😢" }, // dark themes dark_empty: { level0: "#000000", level1: "#000000", level2: "#000000", level3: "#000000", level4: "#000000" }, dark_grass: { level0: "#161b22", level1: "#0e4429", level2: "#006d32", level3: "#26a641", level4: "#39d353" }, dark_cherry: { level0: "#1b1819", level2: "#250e16", level3: "#2e0513", level1: "#5d0926", level4: "#a21043" }, dark_cherry_blossom: { level0: "#1b1819", level1: "#5d0926", level2: "#a22a52", level3: "#c80064", level4: "#ffb094" }, dark_pink: { level0: "#000000", level1: "#33142e", level2: "#7f3474", level3: "#cc53ba", level4: "#ff68e9" }, dark_ocean: { level0: "#00004d", level1: "#0000b3", level2: "#0040ff", level3: "#00bfff", level4: "#00ffff" }, dark_sky: { level0: "#303636", level1: "#616b6b", level2: "#99a3a3", level3: "#86b6b6", level4: "#54bebe" }, dark_halloween: { level0: "#161b22", level1: "#631c03", level2: "#bd561d", level3: "#fa7a18", level4: "#fddf68" }, dark_winter: { level0: "#161b22", level1: "#0a3069", level2: "#0969da", level3: "#54aeff", level4: "#b6e3ff" }, dark_purquoise: { level0: "#303636", level1: "#7c8288", level2: "#8d9caa", level3: "#7c9bb9", level4: "#5b82a8" }, dark_mustard: { level0: "#2a2722", level1: "#4d2e00", level2: "#cc7b00", level3: "#dca009", level4: "#ffc905" }, dark_gray: { level0: "#333333", level1: "#555555", level2: "#777777", level3: "#999999", level4: "#D4D4D4" }, dark_vomit: { level0: "#261339", level1: "#663399", level2: "#666699", level3: "#669999", level4: "#66cc99" }, dark_neonpunk: { level0: "#3E1340", level1: "#EE018F", level2: "#FF00FE", level3: "#41FEFF", level4: "#BFFFFC" }, dark_citypop: { level0: "#514c67", level1: "#5B33FE", level2: "#B74FFB", level3: "#D52DE5", level4: "#FA43F9" }, dark_coral: { level0: "#504949", level2: "#df6d68", level3: "#f25c54", level1: "#f79d65", level4: "#f7b267" } }, be = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], ge = (e = /* @__PURE__ */ new Date()) => { const l = { Sun: "Sunday", Mon: "Monday", Tue: "Tuesday", Wed: "Wednesday", Thu: "Thursday", Fri: "Friday", Sat: "Saturday" }, r = { Jan: "January", Feb: "February", Mar: "March", Apr: "April", May: "May", Jun: "June", Jul: "July", Aug: "August", Sep: "September", Oct: "October", Nov: "November", Dec: "December" }, t = e.toString().split(" "); return { year: t[3], month: r[t[1]], day: parseInt(t[2], 10), date: l[t[0]] }; }, el = (e) => e.reduce((l, r) => l + r, 0), De = (e) => { const l = ge(/* @__PURE__ */ new Date(e + "T00:00")); return `${l.date}, ${l.month} ${l.day}, ${l.year}`; }, K = (e, l, r) => `${e}-${String(l + 1).padStart(2, "0")}-${String(r).padStart(2, "0")}`, _e = (e, l, r) => `${e}-${String(l).padStart(2, "0")}-${String(r).padStart(2, "0")}`, Y = (e) => ({ year: +e.slice(0, 4), month: +e.slice(5, 7), day: +e.slice(8, 10) }), $ = (e) => +e.slice(0, 4), Q = (e) => +e.slice(5, 7), ll = (e) => +e.slice(8, 10), ye = (e = A()) => e % 4 === 0 && e % 100 !== 0 || e % 400 === 0, U = (e = A()) => [31, ye(e) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], Fe = (e) => new Date(e).getDay(), x = (e = A()) => new Date(e, 0, 1).getDay(), rl = (e) => new Date(e).getDay(), A = () => (/* @__PURE__ */ new Date()).getFullYear(), tl = (e = A(), l, r) => { const t = U(e), d = x(e), c = []; let o = d; for (let a = 0; a < 12; a++) { const n = t[a]; let f = 0; for (let v = 0; v < n; v++) o === 0 && f++, o = (o + 1) % 7; a === 0 && d !== 0 && f++, c.push(f); } return e !== l && d !== 0 && l !== r && (c[0] -= 1), c; }, Se = (e) => { const l = /* @__PURE__ */ new Map(); return e.forEach((r) => { Object.keys(r).forEach((t) => { l.set(t, r[t]); }); }), l; }, le = (e) => typeof e == "string" ? me[e] : e, Te = (e, l) => { let r = 0; for (let t = e; t <= l; ++t) r += re(e, t === e); return new Array(7).fill(0).map(() => new Array(r).fill(0)); }, we = (e, l) => { let r = 0; for (let t = e; t <= l; ++t) r += re(e, t === e); return new Array(7).fill("").map(() => new Array(r).fill("")); }, re = (e, l) => { const r = x(e); return l || r === 0 ? 53 : 52; }, Me = (e, l, r) => { const t = $(e), d = $(l), c = Te(t, d); let o = 0, a = 1; for (let n = t; n <= d; ++n) { const f = r ? x(n) : (x(n) + 6) % 7, v = U(n); let s = 0, h = 1, b = f; for (; s < 12; ) { for (let i = 0; i < v[s]; ++i) c[b % 7][~~(b / 7) + o] = a, b++, h++, a++; h > v[s] && (h = 1, s++); } o += ~~(b / 7); } return c; }, te = (e, l, r) => { const t = $(e), d = $(l), c = we(t, d); let o = 0; for (let a = t; a <= d; ++a) { const n = r ? x(a) : (x(a) + 6) % 7, f = U(a); let v = 0, s = 1, h = n; for (; v < 12; ) { for (let b = 0; b < f[v]; ++b) { const i = _e(a, v + 1, s); c[h % 7][~~(h / 7) + o] = i, h++, s++; } s > f[v] && (s = 1, v++); } o += ~~(h / 7); } return c; }, R = (e, l, r) => { const t = `${e}-01-01`, d = ke(t, l), c = Me(t, l, r); for (let o = 0; o < c.length; ++o) for (let a = 0; a < c[o].length; ++a) if (d === c[o][a]) return { row: o, col: a }; return { row: 0, col: 0 }; }, ke = (e, l) => Math.abs(new Date(e).getTime() - new Date(l).getTime()) / (1e3 * 60 * 60 * 24) + 1, ne = (e, l, r, t) => { const { row: d, col: c } = R( $(e), e, t ), { col: o } = R($(e), l, t), a = [], n = []; let f = -1, v = 0; for (let s = c; s <= o; ++s) s === c ? v = Q(r[d][s]) - 1 : v = Q(r[0][s]) - 1, v !== f && (a.push(be[v]), f = v, n.push(0)), n[n.length - 1]++; return { months: a, colSpans: n }; }, Ce = "_thead_1cftj_1", Ee = "_tr_1cftj_9", Ne = "_dayOfTheWeek_1cftj_16", V = { thead: Ce, tr: Ee, dayOfTheWeek: Ne }; function $e({ start: e, end: l, textColor: r, startsOnSunday: t, cy: d }) { const c = te(e, l, t), { day: o } = Y(e), { year: a, month: n, day: f } = Y(l), v = Fe(`${a}-${n}-01`), { months: s, colSpans: h } = ne(e, l, c, t); return /* @__PURE__ */ u("thead", { className: V.thead, children: /* @__PURE__ */ C("tr", { className: V.tr, children: [ /* @__PURE__ */ u(q, { className: V.dayOfTheWeek, textColor: r, style: { fontSize: d }, colSpan: 1, children: " " }), s.map((b, i) => { let D = h[i]; h.length === 1 && h[0] === 1 ? D++ : s.length > 1 && f < 14 && v !== 0 && i === s.length - 2 ? D-- : (s.length > 1 && f < 14 && v !== 0 && i === s.length - 1 || s.length > 1 && f < 14 && i === s.length - 1) && D++; const M = i === 0 && s.length > 1 && D <= 1 && o >= 21; return /* @__PURE__ */ u( q, { textColor: r, style: { fontSize: d }, colSpan: D, hide: M, children: b }, i ); }) ] }) }); } const xe = "_calendarCell_1hhsm_1", Ae = "_top_1hhsm_11", pe = { calendarCell: xe, top: Ae }, Le = ({ content: e, offsetX: l, targetRect: r, fontSize: t = 12 }) => { if (!r) return null; const d = { position: "fixed", zIndex: 999, backgroundColor: "#25292E", color: "#ecf0f1", padding: "4px 8px", borderRadius: "5px", fontFamily: `-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'`, fontWeight: 400, whiteSpace: "nowrap", pointerEvents: "none", fontSize: `${t}px`, left: `${r.left + l}px`, top: `${r.top - 16 - t - ~~(t / 10)}px` }, c = { position: "fixed", zIndex: 999, width: 0, height: 0, borderLeft: "6px solid transparent", borderRight: "6px solid transparent", borderTop: "6px solid #25292E", pointerEvents: "none", left: `${r.left + r.width / 2 - 6}px`, top: `${r.top - 8}px` }; return ue( /* @__PURE__ */ C(O, { children: [ /* @__PURE__ */ u("div", { style: d, children: e }), /* @__PURE__ */ u("div", { style: c }) ] }), document.body ); }; function Be({ cx: e, theme: l, themeProps: r, dataLevel: t, style: d, dataTooltip: c, tooltipSize: o, ...a }) { const n = ee(null), [f, v] = j(-10), [s, h] = j(!1), [b, i] = j(null), D = (m) => { if (!m) return 0; let g = 0; return m.childNodes.forEach((F) => { F.nodeType === Node.ELEMENT_NODE && window.getComputedStyle(F).display !== "none" && g++; }), g; }, M = (m) => { if (!m || !m.parentNode) return -1; const g = Array.from(m.parentNode.childNodes); let F = 0; for (let y = 0; y < m.cellIndex; y++) g[y].style.display !== "none" && F++; return F; }; P(() => { const m = () => { var F; if (n.current) { const y = D((F = n.current) == null ? void 0 : F.parentNode), B = M(n.current); if (y) { let p = -10; B / y > 0.33 ? p = Math.max(~~(n.current.cellIndex * -9 * e) / y, -9 * e) : p = Math.max(~~n.current.cellIndex * -30 * e / y, -10), v(p); } i(n.current.getBoundingClientRect()), h(!0); } }, g = () => { h(!1); }; return n.current && (n.current.addEventListener("mouseover", m), n.current.addEventListener("mouseout", g)), () => { n.current && (n.current.removeEventListener("mouseover", m), n.current.removeEventListener("mouseout", g)); }; }, [e]); const T = (m) => { const g = typeof m == "string" ? !1 : m.isTextTheme || !1; return m === "emoji_positive" || m === "emoji_negative" || g; }; return /* @__PURE__ */ C(O, { children: [ /* @__PURE__ */ u( "td", { ref: n, className: pe.calendarCell, style: { ...d, "--tooltip-offset": `${f}px`, outline: T(l) ? "transparent" : "1px solid rgba(27, 31, 35, 0.06)", backgroundColor: T(l) ? "transparent" : r[`level${t}`] }, "data-level": t, ...a, children: T(l) ? r[`level${t}`] : void 0 } ), s && /* @__PURE__ */ u(Le, { content: c, offsetX: f, targetRect: b, fontSize: o }) ] }); } const Ie = "_tbody_108ph_1", We = "_tr_108ph_6", je = "_td_108ph_13", N = { tbody: Ie, tr: We, td: je }; function Ye({ data: e, start: l, end: r, daysOfTheWeek: t, textColor: d, startsOnSunday: c, includeBoundary: o, cx: a, cy: n, cr: f, theme: v, onClick: s, hideDayLabels: h = !1 }) { const { year: b, day: i } = Y(l), { day: D } = Y(r), { row: M, col: T } = R(b, l, c), { row: m, col: g } = R(b, r, c), F = te(l, r, c), { colSpans: y } = ne(l, r, F, c), B = le(v), p = Se(e), X = (S, _) => _ == g + 1 && y[y.length - 1] === 1, ae = (S, _) => _ < T || _ > g, ce = (S, _) => _ === T && S < M || _ === g && S > m, I = () => T === g || D - i <= 7, oe = c ? t : (() => { const S = [...t]; return S.push(S.shift() || ""), S; })(); return /* @__PURE__ */ u("tbody", { className: N.tbody, children: oe.map((S, _) => /* @__PURE__ */ C("tr", { className: N.tr, children: [ h === !1 && /* @__PURE__ */ u(q, { tabIndex: 0, textColor: d, style: { textAlign: "left", fontSize: n, lineHeight: 0 }, children: S }), F[_].map((J, w) => { if (g === 0 && w === 1) return /* @__PURE__ */ u( "td", { className: N.td, style: { padding: 0, width: I() ? a : 0, height: I() ? n : 0, outline: "none", borderRadius: f, outlineOffset: "-1px", shapeRendering: "geometricPrecision" } }, w ); if (X(_, w)) return /* @__PURE__ */ u("td", { className: N.td, style: { padding: "0", display: "block" } }, w); if (ce(_, w)) return /* @__PURE__ */ u( "td", { className: N.td, style: { padding: 0, width: I() ? a : 0, height: I() ? n : 0, outline: o ? `1px solid ${B.level0}` : "none", borderRadius: f, outlineOffset: "-1px", shapeRendering: "geometricPrecision" } }, w ); if (ae(_, w)) return /* @__PURE__ */ u("td", { className: N.td, style: { padding: "0", display: "none" } }, w); const k = p.get(J), fe = De(J), se = (de) => { const ve = { date: J, data: k == null ? void 0 : k.data }; s && s(de, ve); }; return /* @__PURE__ */ u( Be, { cx: a, tabIndex: -1, style: { width: a, height: n, borderRadius: f }, dataLevel: k !== void 0 ? k.level : 0, "data-content": JSON.stringify(k == null ? void 0 : k.data), dataTooltip: fe, tooltipSize: n, theme: v, themeProps: B, onClick: se }, w ); }) ] }, `${S}-${_}`)) }); } const Re = "_description_lo6s8_1", ze = "_themes_lo6s8_8", Je = "_cell_lo6s8_16", H = { description: Re, themes: ze, cell: Je }; function Ve({ textColor: e, cx: l, cy: r, cr: t, theme: d }) { const c = le(d), o = (n) => { const f = typeof n == "string" ? !1 : n.isTextTheme || !1; return n === "emoji_positive" || n === "emoji_negative" || f; }, a = (n, f) => o(n) ? { width: l, height: r, fontSize: l } : { width: l, height: r, borderRadius: t, backgroundColor: c[`level${f}`], outline: "1px solid #1b1f230f" }; return /* @__PURE__ */ u("div", { className: H.description, children: /* @__PURE__ */ C("div", { className: H.themes, children: [ /* @__PURE__ */ u("span", { style: { color: e, fontSize: l }, children: "Less" }), Array.from({ length: 5 }, (n, f) => f).map((n) => /* @__PURE__ */ u("div", { className: H.cell, style: { ...a(d, n) }, children: o(d) ? c[`level${n}`] : void 0 }, `description-level-${n}`)), /* @__PURE__ */ u("span", { style: { color: e, fontSize: l }, children: "More" }) ] }) }); } const He = "_base_1hm3v_1", Pe = "_container_1hm3v_15", qe = "_calendar_1hm3v_20", Ue = "_table_1hm3v_28", W = { base: He, container: Pe, calendar: qe, table: Ue }, z = (e, l) => { const r = new Error(l); return r.name = e, r; }; var L = /* @__PURE__ */ ((e) => (e.Number = "Number Error", e.String = "String Error", e.Date = "Date Error", e))(L || {}); const Z = (e) => { if (!/^\d{4}-\d{2}-\d{2}$/.test(e)) throw z(L.Date, `Invalid date string ${e}. The date string should be 'YYYY-MM-DD' format.`); try { return new Date(e).toISOString().slice(0, 10) === e; } catch { throw z(L.Date, `Invalid date string ${e}. Please check the date.`); } }, Xe = (e, l) => { if (e > l) throw z(L.Date, "The starting date should be earlier than the ending date."); }, Ge = (e) => { if (e.length !== 7) throw z(L.Number, "The length of the `daysOfTheWeek` should be exact 7."); }; function nl({ data: e, dateOptions: l, styleOptions: r, visibilityOptions: t, onCellClick: d = (o, a) => console.log(a), scroll: c = !1 }) { const o = E(() => (l == null ? void 0 : l.start) || K(A(), 0, 1), [l == null ? void 0 : l.start]), a = E(() => (l == null ? void 0 : l.end) || K(A(), 11, 31), [l == null ? void 0 : l.end]), n = E(() => (l == null ? void 0 : l.startsOnSunday) ?? !0, [l == null ? void 0 : l.startsOnSunday]), f = E( () => (l == null ? void 0 : l.daysOfTheWeek) || ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], [l == null ? void 0 : l.daysOfTheWeek] ), v = E(() => (r == null ? void 0 : r.textColor) || "#1f2328", [r == null ? void 0 : r.textColor]), s = E(() => (l == null ? void 0 : l.includeBoundary) ?? !0, [l == null ? void 0 : l.includeBoundary]), h = ee(null), [b, i] = j(0); return P(() => { Z(o), Z(a), Xe(o, a), Ge(f); }, [f, o, a]), P(() => { if (h.current) { const D = () => { var T; i(((T = h.current) == null ? void 0 : T.offsetWidth) || 0); }; D(); const M = new ResizeObserver(D); return M.observe(h.current), () => { h.current && M.unobserve(h.current); }; } }, []), /* @__PURE__ */ u("div", { className: `${W.base} ${W.container}`, style: r == null ? void 0 : r.style, children: /* @__PURE__ */ C("div", { className: W.calendar, style: { overflowX: c ? "scroll" : "clip", display: "block" }, children: [ /* @__PURE__ */ C("table", { ref: h, className: W.table, children: [ !(t != null && t.hideMonthLabels) && /* @__PURE__ */ u( $e, { start: o, end: a, textColor: v, startsOnSunday: n, cy: (r == null ? void 0 : r.cy) || 10 } ), /* @__PURE__ */ u( Ye, { data: e || [], start: o, end: a, daysOfTheWeek: f, textColor: v, startsOnSunday: n, includeBoundary: s, cx: (r == null ? void 0 : r.cx) || 10, cy: (r == null ? void 0 : r.cy) || 10, cr: (r == null ? void 0 : r.cr) || 2, theme: (r == null ? void 0 : r.theme) || "grass", onClick: d, hideDayLabels: (t == null ? void 0 : t.hideDayLabels) ?? !1 } ) ] }), !(t != null && t.hideDescription) && /* @__PURE__ */ u("div", { style: { width: b }, children: /* @__PURE__ */ u( Ve, { textColor: v, cx: (r == null ? void 0 : r.cx) || 10, cy: (r == null ? void 0 : r.cy) || 10, cr: (r == null ? void 0 : r.cr) || 2, theme: (r == null ? void 0 : r.theme) || "grass" } ) }) ] }) }); } export { nl as ContributionCalendar, le as createTheme, el as getArraySum, tl as getColumnSpansForYears, A as getCurrentYear, ge as getDateDetails, K as getDateString, De as getDateTooltip, te as getDayArray, Fe as getDayIndexFromDateString, rl as getDayIndexOfMonth, ke as getDaysBetween, x as getFirstDayIndexOfYear, ne as getMonthsAndColSpans, R as getRowAndColumnIndexFromDate, ye as isLeapYear, Y as parseDateFromDateString, ll as parseDayFromDateString, Se as parseInputData, Q as parseMonthFromDateString, $ as parseYearFromDateString };