contrib-graphs 0.0.0-stage → 0.1.1

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/dist/index.cjs ADDED
@@ -0,0 +1,1127 @@
1
+ 'use client';
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const require_data = require("./data-w1Mb5e5D.cjs");
4
+ let react = require("react");
5
+ let react_jsx_runtime = require("react/jsx-runtime");
6
+ // src/core.tsx
7
+ /**
8
+ * useLayoutEffect in the browser (measure before paint) and useEffect on the
9
+ * server, where effects don't run and React would warn once per component.
10
+ */
11
+ const useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
12
+ /** `:focus-visible` doesn't exist in old browsers (Safari < 15.4) or in some test environments. */
13
+ function isFocusVisible(el) {
14
+ try {
15
+ return el.matches(":focus-visible");
16
+ } catch {
17
+ return false;
18
+ }
19
+ }
20
+ const indexOf = (target) => {
21
+ const el = target?.closest?.("[data-cg-i]");
22
+ return el ? Number(el.getAttribute("data-cg-i")) : null;
23
+ };
24
+ /**
25
+ * Hover and keyboard navigation through event delegation: cells only carry
26
+ * `data-cg-i`, so hundreds of handlers are never created. Left/right arrows move
27
+ * `stepX` items and up/down move `stepY`.
28
+ */
29
+ function useGraphInteraction(opts) {
30
+ const { rootRef, count, stepX, stepY, onActivate } = opts;
31
+ const [state, setState] = (0, react.useState)(null);
32
+ const [pos, setPos] = (0, react.useState)(null);
33
+ const index = state && state.index < count ? state.index : null;
34
+ useIsomorphicLayoutEffect(() => {
35
+ const root = rootRef.current;
36
+ if (!root) return;
37
+ const el = index == null ? null : root.querySelector(`[data-cg-i="${index}"]`);
38
+ root.querySelectorAll("[data-active]").forEach((n) => n !== el && n.removeAttribute("data-active"));
39
+ el?.setAttribute("data-active", "");
40
+ });
41
+ useIsomorphicLayoutEffect(() => {
42
+ const root = rootRef.current;
43
+ const el = index == null || !root ? null : root.querySelector(`[data-cg-i="${index}"]`);
44
+ if (!root || !el) {
45
+ setPos(null);
46
+ return;
47
+ }
48
+ const r = root.getBoundingClientRect();
49
+ const e = el.getBoundingClientRect();
50
+ setPos({
51
+ x: e.left + e.width / 2 - r.left,
52
+ y: e.top - r.top
53
+ });
54
+ }, [
55
+ rootRef,
56
+ index,
57
+ count
58
+ ]);
59
+ const onKeyDown = (0, react.useCallback)((e) => {
60
+ const cur = index ?? count - 1;
61
+ let next = null;
62
+ switch (e.key) {
63
+ case "ArrowRight":
64
+ next = cur + stepX;
65
+ break;
66
+ case "ArrowLeft":
67
+ next = cur - stepX;
68
+ break;
69
+ case "ArrowDown":
70
+ next = stepY ? cur + stepY : null;
71
+ break;
72
+ case "ArrowUp":
73
+ next = stepY ? cur - stepY : null;
74
+ break;
75
+ case "Home":
76
+ next = 0;
77
+ break;
78
+ case "End":
79
+ next = count - 1;
80
+ break;
81
+ case "Escape":
82
+ setState(null);
83
+ return;
84
+ case "Enter":
85
+ case " ":
86
+ if (index != null) {
87
+ e.preventDefault();
88
+ onActivate?.(index);
89
+ }
90
+ return;
91
+ default: return;
92
+ }
93
+ if (next == null || count === 0) return;
94
+ e.preventDefault();
95
+ setState({
96
+ index: Math.max(0, Math.min(count - 1, next)),
97
+ via: "keyboard"
98
+ });
99
+ }, [
100
+ index,
101
+ count,
102
+ stepX,
103
+ stepY,
104
+ onActivate
105
+ ]);
106
+ return {
107
+ rootRef,
108
+ active: index,
109
+ via: state?.via ?? null,
110
+ pos,
111
+ handlers: {
112
+ tabIndex: 0,
113
+ onKeyDown,
114
+ onPointerOver: (e) => {
115
+ const i = indexOf(e.target);
116
+ if (i != null && i !== index) setState({
117
+ index: i,
118
+ via: "pointer"
119
+ });
120
+ },
121
+ onPointerLeave: () => setState((s) => s?.via === "pointer" ? null : s),
122
+ onClick: (e) => {
123
+ const i = indexOf(e.target);
124
+ if (i != null) onActivate?.(i);
125
+ },
126
+ onFocus: (e) => {
127
+ if (e.target === e.currentTarget && isFocusVisible(e.currentTarget)) setState((s) => s ?? {
128
+ index: count - 1,
129
+ via: "keyboard"
130
+ });
131
+ },
132
+ onBlur: () => setState((s) => s?.via === "keyboard" ? null : s)
133
+ }
134
+ };
135
+ }
136
+ /** Reduces the visible weeks to fit the container width (instead of scrolling). */
137
+ function useFitWeeks(ref, requested, pitch, reserved, enabled) {
138
+ const [fit, setFit] = (0, react.useState)(requested);
139
+ useIsomorphicLayoutEffect(() => {
140
+ const el = ref.current;
141
+ if (!enabled || !el || typeof ResizeObserver === "undefined") {
142
+ setFit(requested);
143
+ return;
144
+ }
145
+ const update = () => {
146
+ const w = el.clientWidth;
147
+ if (w > 0) setFit(Math.max(4, Math.min(requested, Math.floor((w - reserved) / pitch))));
148
+ };
149
+ update();
150
+ const ro = new ResizeObserver(update);
151
+ ro.observe(el);
152
+ return () => ro.disconnect();
153
+ }, [
154
+ ref,
155
+ requested,
156
+ pitch,
157
+ reserved,
158
+ enabled
159
+ ]);
160
+ return enabled ? fit : requested;
161
+ }
162
+ /** Builds the calendar and the interaction. The base of every per-day variant. */
163
+ function useCalendarGraph(props, opts = {}) {
164
+ const rootRef = (0, react.useRef)(null);
165
+ const requested = props.weeks ?? 53;
166
+ const weeks = useFitWeeks(rootRef, requested, opts.fit?.pitch ?? 1, opts.fit?.reserved ?? 0, opts.fit?.enabled ?? false);
167
+ const endKey = props.endDate instanceof Date ? props.endDate.getTime() : props.endDate;
168
+ const scaleKey = typeof props.scale === "string" ? props.scale : props.scale?.join(",");
169
+ const full = (0, react.useMemo)(() => require_data.buildCalendar(props.data, {
170
+ weeks: requested,
171
+ endDate: props.endDate,
172
+ weekStart: props.weekStart,
173
+ scale: props.scale,
174
+ locale: props.locale
175
+ }), [
176
+ props.data,
177
+ requested,
178
+ endKey,
179
+ props.weekStart,
180
+ scaleKey,
181
+ props.locale
182
+ ]);
183
+ const calendar = (0, react.useMemo)(() => require_data.cropCalendar(full, weeks, props.locale), [
184
+ full,
185
+ weeks,
186
+ props.locale
187
+ ]);
188
+ const { onDayClick } = props;
189
+ const onActivate = (0, react.useCallback)((i) => onDayClick?.(calendar.days[i]), [onDayClick, calendar]);
190
+ const interaction = useGraphInteraction({
191
+ rootRef,
192
+ count: calendar.days.length,
193
+ stepX: opts.stepX ?? 7,
194
+ stepY: opts.stepY ?? 1,
195
+ onActivate
196
+ });
197
+ /** `periodTotal` is the total of the requested period, even when fewer weeks are shown. */
198
+ return {
199
+ calendar,
200
+ periodTotal: full.total,
201
+ interaction,
202
+ theme: require_data.resolveTheme(props.theme)
203
+ };
204
+ }
205
+ function describeDay(day, props) {
206
+ const n = day.count;
207
+ return {
208
+ title: `${require_data.formatNumber(n, props.locale)} ${require_data.pluralize(n, props.unit)}`,
209
+ subtitle: require_data.formatDate(day.date, props.locale)
210
+ };
211
+ }
212
+ /** Period text from the requested weeks (not the ones cropped to fit). */
213
+ function periodText(props) {
214
+ const weeks = props.weeks ?? 53;
215
+ const p = props.periodLabel;
216
+ if (typeof p === "function") return p(weeks);
217
+ if (typeof p === "string") return p;
218
+ return weeks >= 52 ? "in the last year" : `in the last ${weeks} weeks`;
219
+ }
220
+ function defaultTitle(total, props) {
221
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
222
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: require_data.formatNumber(total, props.locale) }),
223
+ " ",
224
+ require_data.pluralize(total, props.unit),
225
+ " ",
226
+ periodText(props)
227
+ ] });
228
+ }
229
+ const cellDelay = (w) => ({ "--cg-w": w });
230
+ /** Stable id that is valid inside SVG `url(#...)`. */
231
+ function useSvgId(prefix) {
232
+ return `${prefix}-${(0, react.useId)().replace(/[^a-zA-Z0-9_-]/g, "")}`;
233
+ }
234
+ function Legend({ labels = ["Less", "More"], swatch }) {
235
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
236
+ className: "cg-legend",
237
+ "aria-hidden": "true",
238
+ children: [
239
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: labels[0] }),
240
+ [
241
+ 0,
242
+ 1,
243
+ 2,
244
+ 3,
245
+ 4
246
+ ].map((l) => swatch ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: swatch(l) }, l) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
247
+ className: "cg-swatch",
248
+ style: { background: `var(--cg-l${l})` }
249
+ }, l)),
250
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: labels[1] })
251
+ ]
252
+ });
253
+ }
254
+ /**
255
+ * Shared container: theme, light/dark mode, header, legend, tooltip and an
256
+ * aria-live region that announces the active day during keyboard navigation.
257
+ */
258
+ function GraphShell({ props, interaction, variant, describe, summary, title, headerEnd, footerStart, legendSwatch, glow, surface, children }) {
259
+ const theme = require_data.resolveTheme(props.theme);
260
+ const { active, pos, via } = interaction;
261
+ const desc = active != null ? describe(active) : null;
262
+ const tipRef = (0, react.useRef)(null);
263
+ const [shift, setShift] = (0, react.useState)(0);
264
+ useIsomorphicLayoutEffect(() => {
265
+ const tip = tipRef.current;
266
+ const root = interaction.rootRef.current;
267
+ if (!tip || !root || !pos) return;
268
+ const half = tip.offsetWidth / 2;
269
+ const w = root.clientWidth;
270
+ setShift(pos.x - half < 0 ? half - pos.x : pos.x + half > w ? w - half - pos.x : 0);
271
+ }, [
272
+ pos,
273
+ desc?.title,
274
+ desc?.subtitle,
275
+ interaction.rootRef
276
+ ]);
277
+ const showHeader = props.showTotal !== false || headerEnd;
278
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
279
+ ref: interaction.rootRef,
280
+ className: [
281
+ "cg-root",
282
+ `cg-${variant}`,
283
+ props.className
284
+ ].filter(Boolean).join(" "),
285
+ style: {
286
+ ...require_data.themeVars(theme),
287
+ ...props.style
288
+ },
289
+ "data-mode": props.colorMode ?? "auto",
290
+ "data-animate": props.animate ? "" : void 0,
291
+ "data-glow": glow ? "" : void 0,
292
+ "data-surface": surface ? "" : void 0,
293
+ "data-has-active": active != null ? "" : void 0,
294
+ role: "group",
295
+ "aria-label": props["aria-label"] ?? `${summary}. Use arrow keys to explore.`,
296
+ ...interaction.handlers,
297
+ children: [
298
+ showHeader && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
299
+ className: "cg-header",
300
+ children: [props.showTotal !== false ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
301
+ className: "cg-title",
302
+ children: props.title ?? title
303
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {}), headerEnd]
304
+ }),
305
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
306
+ className: "cg-body",
307
+ children
308
+ }),
309
+ (props.showLegend !== false || footerStart) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
310
+ className: "cg-footer",
311
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: footerStart }), props.showLegend !== false && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Legend, {
312
+ labels: props.legendLabels,
313
+ swatch: legendSwatch
314
+ })]
315
+ }),
316
+ desc && pos && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
317
+ ref: tipRef,
318
+ className: "cg-tooltip",
319
+ style: {
320
+ left: pos.x + shift,
321
+ top: pos.y,
322
+ "--cg-arrow": `${-shift}px`
323
+ },
324
+ "aria-hidden": "true",
325
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: desc.title }), desc.subtitle && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [" · ", desc.subtitle] })]
326
+ }),
327
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
328
+ className: "cg-sr-only",
329
+ "aria-live": "polite",
330
+ children: via === "keyboard" && desc ? `${desc.title}, ${desc.subtitle ?? ""}` : ""
331
+ })
332
+ ]
333
+ });
334
+ }
335
+ function summaryOf(calendar, props) {
336
+ return `${require_data.formatNumber(calendar.total, props.locale)} ${require_data.pluralize(calendar.total, props.unit)} from ${require_data.formatDate(calendar.start, props.locale)} to ${require_data.formatDate(calendar.end, props.locale)}`;
337
+ }
338
+ // src/variants/GridGraph.tsx
339
+ function useGrid(props, shape) {
340
+ const { cellSize = 11, gap = 3, radius = 2, showWeekdays = true, showMonths = true, fit = "crop" } = props;
341
+ const pitch = cellSize + gap;
342
+ const left = showWeekdays ? 30 : 0;
343
+ const top = showMonths ? 15 : 0;
344
+ const { calendar, periodTotal, interaction } = useCalendarGraph(props, { fit: {
345
+ pitch,
346
+ reserved: left - gap,
347
+ enabled: fit === "crop"
348
+ } });
349
+ const glow = props.glow ?? false;
350
+ const filterId = useSvgId("cg-glow");
351
+ const weekdays = (0, react.useMemo)(() => require_data.weekdayLabels(props.locale, props.weekStart ?? 0), [props.locale, props.weekStart]);
352
+ const width = left + calendar.weeks.length * pitch - gap;
353
+ const height = top + 7 * pitch - gap;
354
+ const svg = (0, react.useMemo)(() => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
355
+ width: fit === "scale" ? "100%" : width,
356
+ height: fit === "scale" ? void 0 : height,
357
+ viewBox: `0 0 ${width} ${height}`,
358
+ "aria-hidden": "true",
359
+ children: [
360
+ glow && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("filter", {
361
+ id: filterId,
362
+ x: "-50%",
363
+ y: "-50%",
364
+ width: "200%",
365
+ height: "200%",
366
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("feGaussianBlur", {
367
+ stdDeviation: cellSize / 4,
368
+ result: "b"
369
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("feMerge", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("feMergeNode", { in: "b" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("feMergeNode", { in: "SourceGraphic" })] })]
370
+ }) }),
371
+ showMonths && calendar.months.map((m) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
372
+ className: "cg-label",
373
+ x: left + m.weekIndex * pitch,
374
+ y: 9,
375
+ children: m.label
376
+ }, `${m.year}-${m.month}`)),
377
+ showWeekdays && [
378
+ 1,
379
+ 3,
380
+ 5
381
+ ].map((r) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
382
+ className: "cg-label",
383
+ x: 0,
384
+ y: top + r * pitch + cellSize - 2,
385
+ children: weekdays[r]
386
+ }, r)),
387
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("g", { children: calendar.days.map((d) => {
388
+ const { kind, attrs } = shape.cell({
389
+ x: left + d.weekIndex * pitch,
390
+ y: top + d.dayIndex * pitch,
391
+ size: cellSize,
392
+ level: d.level,
393
+ radius
394
+ });
395
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(kind, {
396
+ ...attrs,
397
+ className: `cg-cell${glow && d.level >= 3 ? " cg-glow" : ""}`,
398
+ "data-cg-i": d.index,
399
+ "data-level": d.level,
400
+ fill: `var(--cg-l${d.level})`,
401
+ style: cellDelay(d.weekIndex)
402
+ }, d.date);
403
+ }) })
404
+ ]
405
+ }), [
406
+ calendar,
407
+ width,
408
+ height,
409
+ fit,
410
+ glow,
411
+ filterId,
412
+ cellSize,
413
+ showMonths,
414
+ showWeekdays,
415
+ left,
416
+ top,
417
+ pitch,
418
+ radius,
419
+ weekdays,
420
+ shape
421
+ ]);
422
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GraphShell, {
423
+ props,
424
+ interaction,
425
+ variant: shape.variant,
426
+ describe: (i) => describeDay(calendar.days[i], props),
427
+ summary: summaryOf(calendar, props),
428
+ title: defaultTitle(periodTotal, props),
429
+ glow,
430
+ legendSwatch: shape.variant === "dots" ? (l) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
431
+ className: "cg-swatch",
432
+ style: {
433
+ background: `var(--cg-l${l})`,
434
+ borderRadius: "50%",
435
+ transform: `scale(${.55 + l * .11})`
436
+ }
437
+ }) : void 0,
438
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
439
+ style: glow ? { "--cg-glow-filter": `url(#${filterId})` } : void 0,
440
+ children: svg
441
+ })
442
+ });
443
+ }
444
+ const classicShape = {
445
+ variant: "classic",
446
+ cell: ({ x, y, size, radius }) => ({
447
+ kind: "rect",
448
+ attrs: {
449
+ x,
450
+ y,
451
+ width: size,
452
+ height: size,
453
+ rx: radius,
454
+ ry: radius
455
+ }
456
+ })
457
+ };
458
+ const dotsShape = {
459
+ variant: "dots",
460
+ cell: ({ x, y, size, level }) => ({
461
+ kind: "circle",
462
+ attrs: {
463
+ cx: x + size / 2,
464
+ cy: y + size / 2,
465
+ r: size / 2 * (level === 0 ? .42 : .55 + level * .115)
466
+ }
467
+ })
468
+ };
469
+ /** The classic weeks × days grid. */
470
+ function ClassicGraph(props) {
471
+ return useGrid(props, classicShape);
472
+ }
473
+ /** Circles whose size also encodes intensity, so it still reads in monochrome. */
474
+ function DotsGraph(props) {
475
+ return useGrid(props, dotsShape);
476
+ }
477
+ // src/isometric.ts
478
+ const r = (v) => Math.round(v * 100) / 100;
479
+ /**
480
+ * Geometry of the isometric view, shared by `IsometricGraph` and
481
+ * `renderIsometricSvg` so the component and the static SVG look the same.
482
+ * Tiles are sorted back to front (paint order).
483
+ */
484
+ function isometricLayout(calendar, { tileSize = 12, maxHeight = 48, heightBy = "count" } = {}) {
485
+ const tw = tileSize;
486
+ const th = tileSize / 2;
487
+ const W = calendar.weeks.length;
488
+ const width = (W + 7) * (tw / 2);
489
+ const height = (W + 7) * (th / 2) + maxHeight + 2;
490
+ const ox = 7 * (tw / 2);
491
+ const max = Math.max(1, calendar.max);
492
+ return {
493
+ width,
494
+ height,
495
+ tiles: [...calendar.days].sort((a, b) => a.weekIndex + a.dayIndex - (b.weekIndex + b.dayIndex) || a.weekIndex - b.weekIndex).map((day) => {
496
+ const X = ox + (day.weekIndex - day.dayIndex) * (tw / 2);
497
+ const Y = maxHeight + (day.weekIndex + day.dayIndex) * (th / 2);
498
+ const h = day.count === 0 ? 0 : heightBy === "level" ? day.level / 4 * maxHeight : Math.max(3, day.count / max * maxHeight);
499
+ const p = (x, y) => `${r(x)},${r(y)}`;
500
+ return {
501
+ day,
502
+ height: h,
503
+ top: [
504
+ p(X, Y - h),
505
+ p(X + tw / 2, Y + th / 2 - h),
506
+ p(X, Y + th - h),
507
+ p(X - tw / 2, Y + th / 2 - h)
508
+ ].join(" "),
509
+ left: [
510
+ p(X - tw / 2, Y + th / 2 - h),
511
+ p(X, Y + th - h),
512
+ p(X, Y + th),
513
+ p(X - tw / 2, Y + th / 2)
514
+ ].join(" "),
515
+ right: [
516
+ p(X, Y + th - h),
517
+ p(X + tw / 2, Y + th / 2 - h),
518
+ p(X + tw / 2, Y + th / 2),
519
+ p(X, Y + th)
520
+ ].join(" ")
521
+ };
522
+ })
523
+ };
524
+ }
525
+ /** Color percentage of the left and right faces (the rest is mixed with black). */
526
+ const ISO_SHADES = {
527
+ left: 78,
528
+ right: 60
529
+ };
530
+ // src/variants/IsometricGraph.tsx
531
+ const shade = (level, pct) => `color-mix(in oklab, var(--cg-l${level}) ${pct}%, var(--cg-mix))`;
532
+ /** Isometric columns whose height shows each day's activity. */
533
+ function IsometricGraph(props) {
534
+ const { tileSize = 12, maxHeight = 48, heightBy = "count", showStats = true, statLabels = [
535
+ "longest streak",
536
+ "current streak",
537
+ "best day"
538
+ ] } = props;
539
+ const { calendar, periodTotal, interaction } = useCalendarGraph(props);
540
+ const stats = (0, react.useMemo)(() => require_data.computeStats(calendar.days), [calendar]);
541
+ const svg = (0, react.useMemo)(() => {
542
+ const { width, height, tiles } = isometricLayout(calendar, {
543
+ tileSize,
544
+ maxHeight,
545
+ heightBy
546
+ });
547
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
548
+ width,
549
+ height,
550
+ viewBox: `0 0 ${width} ${height}`,
551
+ "aria-hidden": "true",
552
+ children: tiles.map(({ day: d, height: h, top, left, right }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
553
+ className: "cg-cell cg-rise",
554
+ "data-cg-i": d.index,
555
+ style: cellDelay(d.weekIndex),
556
+ children: [
557
+ h > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("polygon", {
558
+ points: left,
559
+ style: { fill: shade(d.level, ISO_SHADES.left) }
560
+ }),
561
+ h > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("polygon", {
562
+ points: right,
563
+ style: { fill: shade(d.level, ISO_SHADES.right) }
564
+ }),
565
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("polygon", {
566
+ points: top,
567
+ style: { fill: `var(--cg-l${d.level})` }
568
+ })
569
+ ]
570
+ }, d.date))
571
+ });
572
+ }, [
573
+ calendar,
574
+ tileSize,
575
+ maxHeight,
576
+ heightBy
577
+ ]);
578
+ const n = (v) => require_data.formatNumber(v, props.locale);
579
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GraphShell, {
580
+ props,
581
+ interaction,
582
+ variant: "isometric",
583
+ describe: (i) => describeDay(calendar.days[i], props),
584
+ summary: summaryOf(calendar, props),
585
+ title: defaultTitle(periodTotal, props),
586
+ headerEnd: showStats && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
587
+ className: "cg-stats",
588
+ children: [
589
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: n(stats.longestStreak) }), statLabels[0]] }),
590
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: n(stats.currentStreak) }), statLabels[1]] }),
591
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
592
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: n(stats.best?.count ?? 0) }),
593
+ statLabels[2],
594
+ stats.best && ` · ${require_data.formatDate(stats.best.date, props.locale, {
595
+ month: "short",
596
+ day: "numeric"
597
+ })}`
598
+ ] })
599
+ ]
600
+ }),
601
+ children: svg
602
+ });
603
+ }
604
+ // src/variants/RadialGraph.tsx
605
+ function sector(cx, cy, r0, r1, a0, a1) {
606
+ const p = (r, a) => `${(cx + r * Math.cos(a)).toFixed(2)} ${(cy + r * Math.sin(a)).toFixed(2)}`;
607
+ return `M${p(r1, a0)}A${r1} ${r1} 0 0 1 ${p(r1, a1)}L${p(r0, a1)}A${r0} ${r0} 0 0 0 ${p(r0, a0)}Z`;
608
+ }
609
+ /** The year as a ring: each week is a slice and each weekday a band. */
610
+ function RadialGraph(props) {
611
+ const { size = 320, innerRadius = .38, showMonths = true } = props;
612
+ const { calendar, interaction } = useCalendarGraph(props);
613
+ const pad = showMonths ? 22 : 4;
614
+ const R = size / 2;
615
+ const outer = R - pad;
616
+ const inner = outer * innerRadius;
617
+ const ring = (outer - inner) / 7;
618
+ const W = calendar.weeks.length;
619
+ const slice = Math.PI * 2 / W;
620
+ const start = -Math.PI / 2;
621
+ const gapA = Math.min(.012, slice * .12);
622
+ const svg = (0, react.useMemo)(() => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
623
+ width: size,
624
+ height: size,
625
+ viewBox: `0 0 ${size} ${size}`,
626
+ "aria-hidden": "true",
627
+ children: [
628
+ calendar.days.map((d) => {
629
+ const a0 = start + d.weekIndex * slice + gapA;
630
+ const a1 = start + (d.weekIndex + 1) * slice - gapA;
631
+ const r0 = inner + d.dayIndex * ring + .6;
632
+ const r1 = inner + (d.dayIndex + 1) * ring - .6;
633
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
634
+ d: sector(R, R, r0, r1, a0, a1),
635
+ className: "cg-cell",
636
+ "data-cg-i": d.index,
637
+ fill: `var(--cg-l${d.level})`,
638
+ style: cellDelay(d.weekIndex)
639
+ }, d.date);
640
+ }),
641
+ showMonths && calendar.months.map((m) => {
642
+ const a = start + (m.weekIndex + .5) * slice;
643
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
644
+ className: "cg-label",
645
+ x: R + (outer + 11) * Math.cos(a),
646
+ y: R + (outer + 11) * Math.sin(a),
647
+ textAnchor: "middle",
648
+ dominantBaseline: "middle",
649
+ children: m.label
650
+ }, `${m.year}-${m.month}`);
651
+ }),
652
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
653
+ x: R,
654
+ y: R - 4,
655
+ textAnchor: "middle",
656
+ style: {
657
+ fill: "var(--cg-text)",
658
+ fontSize: size / 11,
659
+ fontWeight: 650
660
+ },
661
+ children: require_data.formatNumber(calendar.total, props.locale)
662
+ }),
663
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
664
+ x: R,
665
+ y: R + size / 18,
666
+ textAnchor: "middle",
667
+ className: "cg-label",
668
+ style: { fontSize: 11 },
669
+ children: require_data.pluralize(calendar.total, props.unit)
670
+ })
671
+ ]
672
+ }), [
673
+ calendar,
674
+ size,
675
+ R,
676
+ inner,
677
+ ring,
678
+ outer,
679
+ slice,
680
+ start,
681
+ gapA,
682
+ showMonths,
683
+ props.locale,
684
+ props.unit
685
+ ]);
686
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GraphShell, {
687
+ props: {
688
+ ...props,
689
+ showTotal: props.showTotal ?? false
690
+ },
691
+ interaction,
692
+ variant: "radial",
693
+ describe: (i) => describeDay(calendar.days[i], props),
694
+ summary: summaryOf(calendar, props),
695
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
696
+ style: {
697
+ display: "flex",
698
+ justifyContent: "center"
699
+ },
700
+ children: svg
701
+ })
702
+ });
703
+ }
704
+ // src/variants/SkylineGraph.tsx
705
+ /** One building per week: your year as a city skyline. */
706
+ function SkylineGraph(props) {
707
+ const { height = 110, barWidth = 9, gap = 3, windows = true, fit = "crop" } = props;
708
+ const pitch = barWidth + gap;
709
+ const rootRef = (0, react.useRef)(null);
710
+ const weeksN = useFitWeeks(rootRef, props.weeks ?? 53, pitch, -gap, fit === "crop");
711
+ const endKey = props.endDate instanceof Date ? props.endDate.getTime() : props.endDate;
712
+ const requested = props.weeks ?? 53;
713
+ const full = (0, react.useMemo)(() => require_data.buildCalendar(props.data, {
714
+ weeks: requested,
715
+ endDate: props.endDate,
716
+ weekStart: props.weekStart,
717
+ locale: props.locale
718
+ }), [
719
+ props.data,
720
+ requested,
721
+ endKey,
722
+ props.weekStart,
723
+ props.locale
724
+ ]);
725
+ const calendar = (0, react.useMemo)(() => require_data.cropCalendar(full, weeksN, props.locale), [
726
+ full,
727
+ weeksN,
728
+ props.locale
729
+ ]);
730
+ const allWeeks = (0, react.useMemo)(() => {
731
+ const raw = full.weeks.map((w, index) => {
732
+ const days = w.filter((d) => d !== null);
733
+ return {
734
+ index,
735
+ days,
736
+ total: days.reduce((s, d) => s + d.count, 0),
737
+ activeDays: days.filter((d) => d.count > 0).length,
738
+ level: 0
739
+ };
740
+ });
741
+ const levelOf = require_data.makeLevelFn(raw.map((w) => w.total), props.scale);
742
+ raw.forEach((w) => w.level = levelOf(w.total));
743
+ return raw;
744
+ }, [full, typeof props.scale === "string" ? props.scale : props.scale?.join(",")]);
745
+ const maxWeek = Math.max(1, ...allWeeks.map((w) => w.total));
746
+ const weeks = (0, react.useMemo)(() => allWeeks.slice(allWeeks.length - calendar.weeks.length).map((w, index) => ({
747
+ ...w,
748
+ index,
749
+ days: calendar.weeks[index].filter((d) => d !== null)
750
+ })), [allWeeks, calendar]);
751
+ const { onWeekClick } = props;
752
+ const onActivate = (0, react.useCallback)((i) => onWeekClick?.(weeks[i]), [onWeekClick, weeks]);
753
+ const interaction = useGraphInteraction({
754
+ rootRef,
755
+ count: weeks.length,
756
+ stepX: 1,
757
+ stepY: 0,
758
+ onActivate
759
+ });
760
+ const labelH = 14;
761
+ const minH = windows ? 30 : 3;
762
+ const width = weeks.length * pitch - gap;
763
+ const svgH = height + labelH;
764
+ const svg = (0, react.useMemo)(() => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
765
+ width: fit === "scale" ? "100%" : width,
766
+ height: fit === "scale" ? void 0 : svgH,
767
+ viewBox: `0 0 ${width} ${svgH}`,
768
+ "aria-hidden": "true",
769
+ children: [
770
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
771
+ x1: 0,
772
+ x2: width,
773
+ y1: height + .5,
774
+ y2: height + .5,
775
+ stroke: "var(--cg-border)"
776
+ }),
777
+ weeks.map((w) => {
778
+ const h = w.total === 0 ? minH * .8 : minH + w.total / maxWeek * (height - minH);
779
+ const x = w.index * pitch;
780
+ const y = height - h;
781
+ const ww = Math.max(2, barWidth - 4);
782
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
783
+ className: "cg-cell cg-rise",
784
+ "data-cg-i": w.index,
785
+ style: cellDelay(w.index),
786
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
787
+ x,
788
+ y,
789
+ width: barWidth,
790
+ height: h,
791
+ rx: 1.5,
792
+ fill: `var(--cg-l${w.level})`
793
+ }), windows && w.days.map((d) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
794
+ x: x + (barWidth - ww) / 2,
795
+ y: y + 3 + d.dayIndex * 3.6,
796
+ width: ww,
797
+ height: 2.2,
798
+ rx: .5,
799
+ fill: d.count > 0 ? "#fff6c8" : "currentColor",
800
+ opacity: d.count > 0 ? .92 : .12,
801
+ style: { color: "var(--cg-mix)" }
802
+ }, d.date))]
803
+ }, w.index);
804
+ }),
805
+ calendar.months.map((m) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
806
+ className: "cg-label",
807
+ x: m.weekIndex * pitch,
808
+ y: svgH - 2,
809
+ children: m.label
810
+ }, `${m.year}-${m.month}`))
811
+ ]
812
+ }), [
813
+ weeks,
814
+ calendar.months,
815
+ width,
816
+ svgH,
817
+ height,
818
+ pitch,
819
+ barWidth,
820
+ maxWeek,
821
+ minH,
822
+ windows,
823
+ fit
824
+ ]);
825
+ const describe = (i) => {
826
+ const w = weeks[i];
827
+ return {
828
+ title: `${require_data.formatNumber(w.total, props.locale)} ${require_data.pluralize(w.total, props.unit)}`,
829
+ subtitle: w.days[0] ? `${require_data.formatDate(w.days[0].date, props.locale, {
830
+ month: "short",
831
+ day: "numeric",
832
+ year: "numeric"
833
+ })} · ${w.activeDays}/7` : void 0
834
+ };
835
+ };
836
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GraphShell, {
837
+ props,
838
+ interaction,
839
+ variant: "skyline",
840
+ describe,
841
+ summary: summaryOf(calendar, props),
842
+ title: defaultTitle(full.total, props),
843
+ children: svg
844
+ });
845
+ }
846
+ // src/variants/TerminalGraph.tsx
847
+ const terminalCharsets = {
848
+ blocks: [
849
+ "··",
850
+ "░░",
851
+ "▒▒",
852
+ "▓▓",
853
+ "██"
854
+ ],
855
+ squares: [
856
+ "□ ",
857
+ "▪ ",
858
+ "■ ",
859
+ "■ ",
860
+ "■ "
861
+ ],
862
+ ascii: [
863
+ ". ",
864
+ ": ",
865
+ "+ ",
866
+ "# ",
867
+ "@ "
868
+ ],
869
+ dots: [
870
+ "· ",
871
+ "• ",
872
+ "• ",
873
+ "● ",
874
+ "● "
875
+ ]
876
+ };
877
+ const CHAR_W = 7.22;
878
+ const MIN_FONT = 6;
879
+ /** Real monospace text, for portfolios with a terminal look. */
880
+ function TerminalGraph(props) {
881
+ const { charset = "blocks", command = "git log --since='1 year ago' | heatmap", prompt = "~ $", colored = true, fit = "crop" } = props;
882
+ const chars = terminalCharsets[charset];
883
+ const { calendar, periodTotal, interaction } = useCalendarGraph(props, { fit: (() => {
884
+ const k = fit === "scale" ? MIN_FONT / 12 : 1;
885
+ return {
886
+ pitch: CHAR_W * 2 * k,
887
+ reserved: CHAR_W * 5 * k + 34,
888
+ enabled: true
889
+ };
890
+ })() });
891
+ const weekdays = (0, react.useMemo)(() => require_data.weekdayLabels(props.locale, props.weekStart ?? 0), [props.locale, props.weekStart]);
892
+ const [fontSize, setFontSize] = (0, react.useState)(12);
893
+ const { rootRef } = interaction;
894
+ const cols = 5 + calendar.weeks.length * 2;
895
+ useIsomorphicLayoutEffect(() => {
896
+ const el = rootRef.current;
897
+ if (fit !== "scale" || !el || typeof ResizeObserver === "undefined") {
898
+ setFontSize(12);
899
+ return;
900
+ }
901
+ const update = () => {
902
+ const avail = el.clientWidth - 34;
903
+ if (avail > 0) setFontSize(Math.max(MIN_FONT, Math.min(12, avail / cols * (12 / CHAR_W))));
904
+ };
905
+ update();
906
+ const ro = new ResizeObserver(update);
907
+ ro.observe(el);
908
+ return () => ro.disconnect();
909
+ }, [
910
+ fit,
911
+ cols,
912
+ rootRef
913
+ ]);
914
+ const color = (l) => colored ? `var(--cg-l${l === 0 ? 2 : l})` : "var(--cg-text)";
915
+ const op = (l) => l === 0 ? .35 : colored ? 1 : .4 + l * .15;
916
+ const body = (0, react.useMemo)(() => {
917
+ const cols = calendar.weeks.length * 2;
918
+ const header = Array.from({ length: cols }, () => " ");
919
+ for (const m of calendar.months) {
920
+ const lbl = m.label.replace(".", "").slice(0, 3);
921
+ for (let i = 0; i < lbl.length && m.weekIndex * 2 + i < cols; i++) header[m.weekIndex * 2 + i] = lbl[i];
922
+ }
923
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
924
+ " ",
925
+ header.join(""),
926
+ "\n",
927
+ Array.from({ length: 7 }, (_, r) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [
928
+ (r % 2 === 1 ? weekdays[r].replace(".", "").slice(0, 3) : "").padEnd(5),
929
+ calendar.weeks.map((w, wi) => {
930
+ const d = w[r];
931
+ if (!d) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: " " }, wi);
932
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
933
+ className: "cg-cell",
934
+ "data-cg-i": d.index,
935
+ style: {
936
+ ...cellDelay(wi),
937
+ color: color(d.level),
938
+ opacity: op(d.level)
939
+ },
940
+ children: chars[d.level]
941
+ }, d.date);
942
+ }),
943
+ "\n"
944
+ ] }, r))
945
+ ] });
946
+ }, [
947
+ calendar,
948
+ weekdays,
949
+ chars,
950
+ colored
951
+ ]);
952
+ const [less, more] = props.legendLabels ?? ["less", "more"];
953
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GraphShell, {
954
+ props: {
955
+ ...props,
956
+ showTotal: false,
957
+ showLegend: false
958
+ },
959
+ interaction,
960
+ variant: "terminal",
961
+ surface: true,
962
+ describe: (i) => describeDay(calendar.days[i], props),
963
+ summary: summaryOf(calendar, props),
964
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("pre", {
965
+ className: "cg-term",
966
+ style: fontSize !== 12 ? { fontSize } : void 0,
967
+ children: [
968
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
969
+ className: "cg-prompt cg-wrap",
970
+ children: [
971
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: prompt }),
972
+ " ",
973
+ command
974
+ ]
975
+ }),
976
+ "\n\n",
977
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
978
+ "aria-hidden": "true",
979
+ children: body
980
+ }),
981
+ "\n",
982
+ (props.showTotal !== false || props.showLegend !== false) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
983
+ className: "cg-foot",
984
+ children: [props.showTotal !== false && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
985
+ className: "cg-prompt",
986
+ children: props.title ?? `${require_data.formatNumber(periodTotal, props.locale)} ${require_data.pluralize(periodTotal, props.unit)} ${periodText(props)}`
987
+ }), props.showLegend !== false && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
988
+ less,
989
+ " ",
990
+ [
991
+ 0,
992
+ 1,
993
+ 2,
994
+ 3,
995
+ 4
996
+ ].map((l) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
997
+ style: {
998
+ color: color(l),
999
+ opacity: op(l)
1000
+ },
1001
+ children: chars[l]
1002
+ }, l)),
1003
+ more
1004
+ ] })]
1005
+ }),
1006
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1007
+ className: "cg-prompt",
1008
+ children: [
1009
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: prompt }),
1010
+ " ",
1011
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "cg-caret" })
1012
+ ]
1013
+ })
1014
+ ]
1015
+ })
1016
+ });
1017
+ }
1018
+ // src/variants/CompactGraph.tsx
1019
+ /** A single row with the last N days, for headers, cards and footers. */
1020
+ function CompactGraph(props) {
1021
+ const { days: n = 30, cellSize = 10, gap = 3, radius = 2, showStreak = true } = props;
1022
+ const rootRef = (0, react.useRef)(null);
1023
+ const endKey = props.endDate instanceof Date ? props.endDate.getTime() : props.endDate;
1024
+ const scaleKey = typeof props.scale === "string" ? props.scale : props.scale?.join(",");
1025
+ const days = (0, react.useMemo)(() => {
1026
+ const slice = require_data.buildCalendar(props.data, {
1027
+ weeks: Math.ceil(n / 7) + 1,
1028
+ endDate: props.endDate
1029
+ }).days.slice(-n);
1030
+ const levelOf = require_data.makeLevelFn(slice.map((d) => d.count), props.scale);
1031
+ return slice.map((d, i) => ({
1032
+ ...d,
1033
+ index: i,
1034
+ weekIndex: i,
1035
+ level: levelOf(d.count)
1036
+ }));
1037
+ }, [
1038
+ props.data,
1039
+ n,
1040
+ endKey,
1041
+ scaleKey
1042
+ ]);
1043
+ const stats = (0, react.useMemo)(() => require_data.computeStats(days), [days]);
1044
+ const { onDayClick } = props;
1045
+ const onActivate = (0, react.useCallback)((i) => onDayClick?.(days[i]), [onDayClick, days]);
1046
+ const interaction = useGraphInteraction({
1047
+ rootRef,
1048
+ count: days.length,
1049
+ stepX: 1,
1050
+ stepY: 0,
1051
+ onActivate
1052
+ });
1053
+ const pitch = cellSize + gap;
1054
+ const width = days.length * pitch - gap;
1055
+ const svg = (0, react.useMemo)(() => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
1056
+ width,
1057
+ height: cellSize,
1058
+ viewBox: `0 0 ${width} ${cellSize}`,
1059
+ "aria-hidden": "true",
1060
+ children: days.map((d) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
1061
+ className: "cg-cell",
1062
+ "data-cg-i": d.index,
1063
+ x: d.index * pitch,
1064
+ y: 0,
1065
+ width: cellSize,
1066
+ height: cellSize,
1067
+ rx: radius,
1068
+ fill: `var(--cg-l${d.level})`,
1069
+ style: cellDelay(d.index / 3)
1070
+ }, d.date))
1071
+ }), [
1072
+ days,
1073
+ width,
1074
+ cellSize,
1075
+ pitch,
1076
+ radius
1077
+ ]);
1078
+ const streak = props.streakLabel ?? ((s) => `${s} day streak`);
1079
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GraphShell, {
1080
+ props: {
1081
+ ...props,
1082
+ showLegend: props.showLegend ?? false
1083
+ },
1084
+ interaction,
1085
+ variant: "compact",
1086
+ describe: (i) => describeDay(days[i], props),
1087
+ summary: `${stats.total} ${require_data.pluralize(stats.total, props.unit)} in the last ${n} days`,
1088
+ title: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1089
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: require_data.formatNumber(stats.total, props.locale) }),
1090
+ " ",
1091
+ require_data.pluralize(stats.total, props.unit),
1092
+ " ",
1093
+ (props.rangeLabel ?? ((d) => `in the last ${d} days`))(n)
1094
+ ] }),
1095
+ headerEnd: showStreak && stats.currentStreak > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1096
+ style: { color: "var(--cg-muted)" },
1097
+ children: streak(stats.currentStreak)
1098
+ }),
1099
+ children: svg
1100
+ });
1101
+ }
1102
+ exports.ClassicGraph = ClassicGraph;
1103
+ exports.CompactGraph = CompactGraph;
1104
+ exports.DotsGraph = DotsGraph;
1105
+ exports.GITHUB_CONTRIBUTIONS_QUERY = require_data.GITHUB_CONTRIBUTIONS_QUERY;
1106
+ exports.IsometricGraph = IsometricGraph;
1107
+ exports.RadialGraph = RadialGraph;
1108
+ exports.SkylineGraph = SkylineGraph;
1109
+ exports.TerminalGraph = TerminalGraph;
1110
+ exports.buildCalendar = require_data.buildCalendar;
1111
+ exports.computeStats = require_data.computeStats;
1112
+ exports.cropCalendar = require_data.cropCalendar;
1113
+ exports.fetchGitHubContributions = require_data.fetchGitHubContributions;
1114
+ exports.fetchGitLabContributions = require_data.fetchGitLabContributions;
1115
+ exports.formatDate = require_data.formatDate;
1116
+ exports.fromDates = require_data.fromDates;
1117
+ exports.fromGitHub = require_data.fromGitHub;
1118
+ exports.fromGitLab = require_data.fromGitLab;
1119
+ exports.generateSampleData = require_data.generateSampleData;
1120
+ exports.makeLevelFn = require_data.makeLevelFn;
1121
+ exports.mergeSources = require_data.mergeSources;
1122
+ exports.resolveTheme = require_data.resolveTheme;
1123
+ exports.sampleProfiles = require_data.sampleProfiles;
1124
+ exports.terminalCharsets = terminalCharsets;
1125
+ exports.themeNames = require_data.themeNames;
1126
+ exports.themeVars = require_data.themeVars;
1127
+ exports.themes = require_data.themes;