contrib-graphs 0.1.0 → 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/README.md CHANGED
@@ -6,6 +6,10 @@ Contribution graph components for React: GitHub-style activity heatmaps in seven
6
6
 
7
7
  ```bash
8
8
  npm install contrib-graphs
9
+ # or
10
+ pnpm add contrib-graphs
11
+ yarn add contrib-graphs
12
+ bun add contrib-graphs
9
13
  ```
10
14
 
11
15
  ```tsx
@@ -26,6 +30,12 @@ Every component takes the same `{ date, count }[]` data. Adapters for GitHub and
26
30
 
27
31
  Requires React 18 or later.
28
32
 
33
+ Prefer to own the code? Copy any variant into your project with the shadcn CLI instead of installing the package:
34
+
35
+ ```bash
36
+ npx shadcn@latest add https://ingfranciscastillo.github.io/contrib-graphs/r/classic-graph.json
37
+ ```
38
+
29
39
  ## Next.js, Astro and server rendering
30
40
 
31
41
  - `contrib-graphs` exports the components and starts with `"use client"`, so you can render them straight from a Next.js Server Component.
package/dist/data.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
- * `contrib-graphs/data`: todo lo que no es un componente. Sin "use client", así
4
- * que se puede usar en Server Components, rutas de API, scripts de build, etc.
3
+ * `contrib-graphs/data`: everything that isn't a component. No "use client", so it
4
+ * works in Server Components, API routes, build scripts and so on.
5
5
  */
6
6
  import { A as ThemePalette, C as ContributionDay, D as GraphTheme, E as MonthLabel, M as themeNames, N as themeVars, O as LevelColors, P as themes, S as ColorMode, T as LevelScale, _ as formatDate, a as fromDates, b as Calendar, c as mergeSources, d as sampleProfiles, f as CalendarOptions, g as cropCalendar, h as computeStats, i as fetchGitLabContributions, j as resolveTheme, k as ThemeName, l as SampleProfile, m as buildCalendar, n as GitHubCalendarResponse, o as fromGitHub, p as GraphStats, r as fetchGitHubContributions, s as fromGitLab, t as GITHUB_CONTRIBUTIONS_QUERY, u as generateSampleData, v as makeLevelFn, w as Level, x as CalendarDay, y as BaseGraphProps } from "./data-DptvXfjH.cjs";
7
7
  export { type BaseGraphProps, type Calendar, type CalendarDay, type CalendarOptions, type ColorMode, type ContributionDay, GITHUB_CONTRIBUTIONS_QUERY, GitHubCalendarResponse, type GraphStats, type GraphTheme, type Level, type LevelColors, type LevelScale, type MonthLabel, type SampleProfile, type ThemeName, type ThemePalette, buildCalendar, computeStats, cropCalendar, fetchGitHubContributions, fetchGitLabContributions, formatDate, fromDates, fromGitHub, fromGitLab, generateSampleData, makeLevelFn, mergeSources, resolveTheme, sampleProfiles, themeNames, themeVars, themes };
package/dist/data.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
- * `contrib-graphs/data`: todo lo que no es un componente. Sin "use client", así
4
- * que se puede usar en Server Components, rutas de API, scripts de build, etc.
3
+ * `contrib-graphs/data`: everything that isn't a component. No "use client", so it
4
+ * works in Server Components, API routes, build scripts and so on.
5
5
  */
6
6
  import { A as ThemePalette, C as ContributionDay, D as GraphTheme, E as MonthLabel, M as themeNames, N as themeVars, O as LevelColors, P as themes, S as ColorMode, T as LevelScale, _ as formatDate, a as fromDates, b as Calendar, c as mergeSources, d as sampleProfiles, f as CalendarOptions, g as cropCalendar, h as computeStats, i as fetchGitLabContributions, j as resolveTheme, k as ThemeName, l as SampleProfile, m as buildCalendar, n as GitHubCalendarResponse, o as fromGitHub, p as GraphStats, r as fetchGitHubContributions, s as fromGitLab, t as GITHUB_CONTRIBUTIONS_QUERY, u as generateSampleData, v as makeLevelFn, w as Level, x as CalendarDay, y as BaseGraphProps } from "./data-DptvXfjH.js";
7
7
  export { type BaseGraphProps, type Calendar, type CalendarDay, type CalendarOptions, type ColorMode, type ContributionDay, GITHUB_CONTRIBUTIONS_QUERY, GitHubCalendarResponse, type GraphStats, type GraphTheme, type Level, type LevelColors, type LevelScale, type MonthLabel, type SampleProfile, type ThemeName, type ThemePalette, buildCalendar, computeStats, cropCalendar, fetchGitHubContributions, fetchGitLabContributions, formatDate, fromDates, fromGitHub, fromGitLab, generateSampleData, makeLevelFn, mergeSources, resolveTheme, sampleProfiles, themeNames, themeVars, themes };
package/dist/index.cjs CHANGED
@@ -5,11 +5,11 @@ let react = require("react");
5
5
  let react_jsx_runtime = require("react/jsx-runtime");
6
6
  // src/core.tsx
7
7
  /**
8
- * useLayoutEffect en el navegador (mide antes de pintar) y useEffect en el
9
- * servidor, donde los efectos no corren y React avisaría por cada componente.
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
10
  */
11
11
  const useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
12
- /** `:focus-visible` no existe en navegadores viejos (Safari < 15.4) ni en algunos entornos de test. */
12
+ /** `:focus-visible` doesn't exist in old browsers (Safari < 15.4) or in some test environments. */
13
13
  function isFocusVisible(el) {
14
14
  try {
15
15
  return el.matches(":focus-visible");
@@ -22,9 +22,9 @@ const indexOf = (target) => {
22
22
  return el ? Number(el.getAttribute("data-cg-i")) : null;
23
23
  };
24
24
  /**
25
- * Hover + navegación con teclado usando delegación de eventos: las celdas solo
26
- * llevan `data-cg-i`, así que no se crean cientos de handlers. Flechas izquierda/derecha
27
- * avanzan `stepX` elementos y arriba/abajo `stepY`.
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
28
  */
29
29
  function useGraphInteraction(opts) {
30
30
  const { rootRef, count, stepX, stepY, onActivate } = opts;
@@ -133,7 +133,7 @@ function useGraphInteraction(opts) {
133
133
  }
134
134
  };
135
135
  }
136
- /** Reduce las semanas visibles al ancho del contenedor (en vez de hacer scroll). */
136
+ /** Reduces the visible weeks to fit the container width (instead of scrolling). */
137
137
  function useFitWeeks(ref, requested, pitch, reserved, enabled) {
138
138
  const [fit, setFit] = (0, react.useState)(requested);
139
139
  useIsomorphicLayoutEffect(() => {
@@ -159,7 +159,7 @@ function useFitWeeks(ref, requested, pitch, reserved, enabled) {
159
159
  ]);
160
160
  return enabled ? fit : requested;
161
161
  }
162
- /** Monta calendario + interacción. Es la base de todas las variantes por día. */
162
+ /** Builds the calendar and the interaction. The base of every per-day variant. */
163
163
  function useCalendarGraph(props, opts = {}) {
164
164
  const rootRef = (0, react.useRef)(null);
165
165
  const requested = props.weeks ?? 53;
@@ -194,7 +194,7 @@ function useCalendarGraph(props, opts = {}) {
194
194
  stepY: opts.stepY ?? 1,
195
195
  onActivate
196
196
  });
197
- /** `periodTotal` es el total del periodo pedido aunque se muestren menos semanas. */
197
+ /** `periodTotal` is the total of the requested period, even when fewer weeks are shown. */
198
198
  return {
199
199
  calendar,
200
200
  periodTotal: full.total,
@@ -209,7 +209,7 @@ function describeDay(day, props) {
209
209
  subtitle: require_data.formatDate(day.date, props.locale)
210
210
  };
211
211
  }
212
- /** Texto del periodo según las semanas pedidas (no las recortadas por ancho). */
212
+ /** Period text from the requested weeks (not the ones cropped to fit). */
213
213
  function periodText(props) {
214
214
  const weeks = props.weeks ?? 53;
215
215
  const p = props.periodLabel;
@@ -227,7 +227,7 @@ function defaultTitle(total, props) {
227
227
  ] });
228
228
  }
229
229
  const cellDelay = (w) => ({ "--cg-w": w });
230
- /** Id estable y válido para usar en `url(#...)` dentro de SVG. */
230
+ /** Stable id that is valid inside SVG `url(#...)`. */
231
231
  function useSvgId(prefix) {
232
232
  return `${prefix}-${(0, react.useId)().replace(/[^a-zA-Z0-9_-]/g, "")}`;
233
233
  }
@@ -252,8 +252,8 @@ function Legend({ labels = ["Less", "More"], swatch }) {
252
252
  });
253
253
  }
254
254
  /**
255
- * Contenedor común: tema, modo claro/oscuro, encabezado, leyenda, tooltip
256
- * y región aria-live para anunciar el día activo al navegar con teclado.
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
257
  */
258
258
  function GraphShell({ props, interaction, variant, describe, summary, title, headerEnd, footerStart, legendSwatch, glow, surface, children }) {
259
259
  const theme = require_data.resolveTheme(props.theme);
@@ -477,9 +477,9 @@ function DotsGraph(props) {
477
477
  // src/isometric.ts
478
478
  const r = (v) => Math.round(v * 100) / 100;
479
479
  /**
480
- * Geometría de la vista isométrica, compartida por `IsometricGraph` y por
481
- * `renderIsometricSvg`: así el componente y el SVG estático se ven igual.
482
- * Las baldosas vienen ordenadas de atrás hacia adelante (orden de pintado).
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
483
  */
484
484
  function isometricLayout(calendar, { tileSize = 12, maxHeight = 48, heightBy = "count" } = {}) {
485
485
  const tw = tileSize;
@@ -522,7 +522,7 @@ function isometricLayout(calendar, { tileSize = 12, maxHeight = 48, heightBy = "
522
522
  })
523
523
  };
524
524
  }
525
- /** Porcentaje de color de la cara izquierda y derecha (el resto se mezcla con negro). */
525
+ /** Color percentage of the left and right faces (the rest is mixed with black). */
526
526
  const ISO_SHADES = {
527
527
  left: 78,
528
528
  right: 60
@@ -974,7 +974,10 @@ function TerminalGraph(props) {
974
974
  ]
975
975
  }),
976
976
  "\n\n",
977
- body,
977
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
978
+ "aria-hidden": "true",
979
+ children: body
980
+ }),
978
981
  "\n",
979
982
  (props.showTotal !== false || props.showLegend !== false) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
980
983
  className: "cg-foot",
package/dist/index.d.cts CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /**
3
- * `contrib-graphs`: los componentes. El build antepone "use client" a este
4
- * archivo para que se puedan importar desde Server Components (Next.js).
5
- * En código de servidor usa `contrib-graphs/data`.
3
+ * `contrib-graphs`: the components. The build prepends "use client" to this
4
+ * file so they can be imported from Server Components (Next.js).
5
+ * In server code, use `contrib-graphs/data`.
6
6
  */
7
7
  import { A as ThemePalette, C as ContributionDay, D as GraphTheme, E as MonthLabel, M as themeNames, N as themeVars, O as LevelColors, P as themes, S as ColorMode, T as LevelScale, _ as formatDate, a as fromDates, b as Calendar, c as mergeSources, d as sampleProfiles, f as CalendarOptions, g as cropCalendar, h as computeStats, i as fetchGitLabContributions, j as resolveTheme, k as ThemeName, l as SampleProfile, m as buildCalendar, n as GitHubCalendarResponse, o as fromGitHub, p as GraphStats, r as fetchGitHubContributions, s as fromGitLab, t as GITHUB_CONTRIBUTIONS_QUERY, u as generateSampleData, v as makeLevelFn, w as Level, x as CalendarDay, y as BaseGraphProps } from "./data-DptvXfjH.cjs";
8
8
  /** Props of `ClassicGraph` and `DotsGraph`. */
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /**
3
- * `contrib-graphs`: los componentes. El build antepone "use client" a este
4
- * archivo para que se puedan importar desde Server Components (Next.js).
5
- * En código de servidor usa `contrib-graphs/data`.
3
+ * `contrib-graphs`: the components. The build prepends "use client" to this
4
+ * file so they can be imported from Server Components (Next.js).
5
+ * In server code, use `contrib-graphs/data`.
6
6
  */
7
7
  import { A as ThemePalette, C as ContributionDay, D as GraphTheme, E as MonthLabel, M as themeNames, N as themeVars, O as LevelColors, P as themes, S as ColorMode, T as LevelScale, _ as formatDate, a as fromDates, b as Calendar, c as mergeSources, d as sampleProfiles, f as CalendarOptions, g as cropCalendar, h as computeStats, i as fetchGitLabContributions, j as resolveTheme, k as ThemeName, l as SampleProfile, m as buildCalendar, n as GitHubCalendarResponse, o as fromGitHub, p as GraphStats, r as fetchGitHubContributions, s as fromGitLab, t as GITHUB_CONTRIBUTIONS_QUERY, u as generateSampleData, v as makeLevelFn, w as Level, x as CalendarDay, y as BaseGraphProps } from "./data-DptvXfjH.js";
8
8
  /** Props of `ClassicGraph` and `DotsGraph`. */
package/dist/index.js CHANGED
@@ -4,11 +4,11 @@ import { Fragment, useCallback, useEffect, useId, useLayoutEffect, useMemo, useR
4
4
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
5
  // src/core.tsx
6
6
  /**
7
- * useLayoutEffect en el navegador (mide antes de pintar) y useEffect en el
8
- * servidor, donde los efectos no corren y React avisaría por cada componente.
7
+ * useLayoutEffect in the browser (measure before paint) and useEffect on the
8
+ * server, where effects don't run and React would warn once per component.
9
9
  */
10
10
  const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
11
- /** `:focus-visible` no existe en navegadores viejos (Safari < 15.4) ni en algunos entornos de test. */
11
+ /** `:focus-visible` doesn't exist in old browsers (Safari < 15.4) or in some test environments. */
12
12
  function isFocusVisible(el) {
13
13
  try {
14
14
  return el.matches(":focus-visible");
@@ -21,9 +21,9 @@ const indexOf = (target) => {
21
21
  return el ? Number(el.getAttribute("data-cg-i")) : null;
22
22
  };
23
23
  /**
24
- * Hover + navegación con teclado usando delegación de eventos: las celdas solo
25
- * llevan `data-cg-i`, así que no se crean cientos de handlers. Flechas izquierda/derecha
26
- * avanzan `stepX` elementos y arriba/abajo `stepY`.
24
+ * Hover and keyboard navigation through event delegation: cells only carry
25
+ * `data-cg-i`, so hundreds of handlers are never created. Left/right arrows move
26
+ * `stepX` items and up/down move `stepY`.
27
27
  */
28
28
  function useGraphInteraction(opts) {
29
29
  const { rootRef, count, stepX, stepY, onActivate } = opts;
@@ -132,7 +132,7 @@ function useGraphInteraction(opts) {
132
132
  }
133
133
  };
134
134
  }
135
- /** Reduce las semanas visibles al ancho del contenedor (en vez de hacer scroll). */
135
+ /** Reduces the visible weeks to fit the container width (instead of scrolling). */
136
136
  function useFitWeeks(ref, requested, pitch, reserved, enabled) {
137
137
  const [fit, setFit] = useState(requested);
138
138
  useIsomorphicLayoutEffect(() => {
@@ -158,7 +158,7 @@ function useFitWeeks(ref, requested, pitch, reserved, enabled) {
158
158
  ]);
159
159
  return enabled ? fit : requested;
160
160
  }
161
- /** Monta calendario + interacción. Es la base de todas las variantes por día. */
161
+ /** Builds the calendar and the interaction. The base of every per-day variant. */
162
162
  function useCalendarGraph(props, opts = {}) {
163
163
  const rootRef = useRef(null);
164
164
  const requested = props.weeks ?? 53;
@@ -193,7 +193,7 @@ function useCalendarGraph(props, opts = {}) {
193
193
  stepY: opts.stepY ?? 1,
194
194
  onActivate
195
195
  });
196
- /** `periodTotal` es el total del periodo pedido aunque se muestren menos semanas. */
196
+ /** `periodTotal` is the total of the requested period, even when fewer weeks are shown. */
197
197
  return {
198
198
  calendar,
199
199
  periodTotal: full.total,
@@ -208,7 +208,7 @@ function describeDay(day, props) {
208
208
  subtitle: formatDate(day.date, props.locale)
209
209
  };
210
210
  }
211
- /** Texto del periodo según las semanas pedidas (no las recortadas por ancho). */
211
+ /** Period text from the requested weeks (not the ones cropped to fit). */
212
212
  function periodText(props) {
213
213
  const weeks = props.weeks ?? 53;
214
214
  const p = props.periodLabel;
@@ -226,7 +226,7 @@ function defaultTitle(total, props) {
226
226
  ] });
227
227
  }
228
228
  const cellDelay = (w) => ({ "--cg-w": w });
229
- /** Id estable y válido para usar en `url(#...)` dentro de SVG. */
229
+ /** Stable id that is valid inside SVG `url(#...)`. */
230
230
  function useSvgId(prefix) {
231
231
  return `${prefix}-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
232
232
  }
@@ -251,8 +251,8 @@ function Legend({ labels = ["Less", "More"], swatch }) {
251
251
  });
252
252
  }
253
253
  /**
254
- * Contenedor común: tema, modo claro/oscuro, encabezado, leyenda, tooltip
255
- * y región aria-live para anunciar el día activo al navegar con teclado.
254
+ * Shared container: theme, light/dark mode, header, legend, tooltip and an
255
+ * aria-live region that announces the active day during keyboard navigation.
256
256
  */
257
257
  function GraphShell({ props, interaction, variant, describe, summary, title, headerEnd, footerStart, legendSwatch, glow, surface, children }) {
258
258
  const theme = resolveTheme(props.theme);
@@ -476,9 +476,9 @@ function DotsGraph(props) {
476
476
  // src/isometric.ts
477
477
  const r = (v) => Math.round(v * 100) / 100;
478
478
  /**
479
- * Geometría de la vista isométrica, compartida por `IsometricGraph` y por
480
- * `renderIsometricSvg`: así el componente y el SVG estático se ven igual.
481
- * Las baldosas vienen ordenadas de atrás hacia adelante (orden de pintado).
479
+ * Geometry of the isometric view, shared by `IsometricGraph` and
480
+ * `renderIsometricSvg` so the component and the static SVG look the same.
481
+ * Tiles are sorted back to front (paint order).
482
482
  */
483
483
  function isometricLayout(calendar, { tileSize = 12, maxHeight = 48, heightBy = "count" } = {}) {
484
484
  const tw = tileSize;
@@ -521,7 +521,7 @@ function isometricLayout(calendar, { tileSize = 12, maxHeight = 48, heightBy = "
521
521
  })
522
522
  };
523
523
  }
524
- /** Porcentaje de color de la cara izquierda y derecha (el resto se mezcla con negro). */
524
+ /** Color percentage of the left and right faces (the rest is mixed with black). */
525
525
  const ISO_SHADES = {
526
526
  left: 78,
527
527
  right: 60
@@ -973,7 +973,10 @@ function TerminalGraph(props) {
973
973
  ]
974
974
  }),
975
975
  "\n\n",
976
- body,
976
+ /* @__PURE__ */ jsx("span", {
977
+ "aria-hidden": "true",
978
+ children: body
979
+ }),
977
980
  "\n",
978
981
  (props.showTotal !== false || props.showLegend !== false) && /* @__PURE__ */ jsxs("span", {
979
982
  className: "cg-foot",
package/dist/styles.css CHANGED
@@ -1,7 +1,7 @@
1
1
  /* ============================================================
2
- Contribution Graph — estilos base
3
- Los colores llegan como --cg-*-light / --cg-*-dark desde el tema;
4
- aquí se elige cuál aplicar según data-mode y el esquema de color.
2
+ Contribution Graph — base styles
3
+ Colors arrive from the theme as --cg-*-light / --cg-*-dark;
4
+ this file picks one by data-mode and the color scheme.
5
5
  ============================================================ */
6
6
 
7
7
  .cg-root {
@@ -123,7 +123,7 @@
123
123
  font-size: 9px;
124
124
  }
125
125
 
126
- /* ---------- Celdas ---------- */
126
+ /* ---------- Cells ---------- */
127
127
  .cg-cell {
128
128
  cursor: pointer;
129
129
  transition: opacity 0.15s ease, filter 0.15s ease;
@@ -179,7 +179,7 @@
179
179
  white-space: nowrap;
180
180
  }
181
181
 
182
- /* ---------- Animación de entrada ---------- */
182
+ /* ---------- Entry animation ---------- */
183
183
  .cg-root[data-animate] .cg-cell {
184
184
  animation: cg-pop 0.5s cubic-bezier(0.2, 0.8, 0.3, 1.25) both;
185
185
  animation-delay: calc(var(--cg-w, 0) * 12ms);
@@ -227,7 +227,7 @@
227
227
  .cg-terminal .cg-prompt {
228
228
  color: var(--cg-text);
229
229
  }
230
- /* Las líneas de texto pueden partirse; la cuadrícula no (se recorta o escala). */
230
+ /* Text lines may wrap; the grid doesn't (it crops or scales). */
231
231
  .cg-terminal .cg-wrap {
232
232
  white-space: pre-wrap;
233
233
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contrib-graphs",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Contribution graph components for React: GitHub-style heatmaps in seven designs, with themes, dark mode, keyboard navigation and screen reader support.",
5
5
  "keywords": [
6
6
  "react",