@pearpages/heatmap 0.3.1 → 0.4.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 +71 -21
- package/dist/index.css +74 -68
- package/dist/index.css.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -172,19 +172,22 @@ Four palettes ship with the library. Apply one through `className`:
|
|
|
172
172
|
| Sunset | `contribution-heatmap--sunset` |
|
|
173
173
|
| Purple | `contribution-heatmap--purple` |
|
|
174
174
|
|
|
175
|
-
Themes are nothing more than overrides of the `--
|
|
176
|
-
custom properties, so you can define your own the same way:
|
|
175
|
+
Themes are nothing more than overrides of the `--contribution-heatmap-level-0` …
|
|
176
|
+
`--contribution-heatmap-level-4` custom properties, so you can define your own the same way:
|
|
177
177
|
|
|
178
178
|
```css
|
|
179
179
|
.contribution-heatmap--brand {
|
|
180
|
-
--
|
|
181
|
-
--
|
|
182
|
-
--
|
|
183
|
-
--
|
|
184
|
-
--
|
|
180
|
+
--contribution-heatmap-level-0: #eee;
|
|
181
|
+
--contribution-heatmap-level-1: #cfe8ff;
|
|
182
|
+
--contribution-heatmap-level-2: #7cc0ff;
|
|
183
|
+
--contribution-heatmap-level-3: #3b93f0;
|
|
184
|
+
--contribution-heatmap-level-4: #0b5cad;
|
|
185
185
|
}
|
|
186
186
|
```
|
|
187
187
|
|
|
188
|
+
A theme set this way applies in both light and dark. For a dark variant, set the same
|
|
189
|
+
properties again under your own dark selector.
|
|
190
|
+
|
|
188
191
|
### Light and dark
|
|
189
192
|
|
|
190
193
|
By default the component follows `prefers-color-scheme`. Two more classes force it:
|
|
@@ -205,23 +208,34 @@ scrollbar matches:
|
|
|
205
208
|
/>
|
|
206
209
|
```
|
|
207
210
|
|
|
208
|
-
###
|
|
211
|
+
### Custom properties
|
|
209
212
|
|
|
210
|
-
|
|
211
|
-
|
|
213
|
+
Everything else is restyled the same way, so there is no prop for any of it. Every
|
|
214
|
+
public property is prefixed `--contribution-heatmap-`, the component's own block name:
|
|
212
215
|
|
|
213
|
-
| Custom property | Default | What it does |
|
|
216
|
+
| Custom property (`--contribution-heatmap-…`) | Default | What it does |
|
|
214
217
|
| --- | --- | --- |
|
|
215
|
-
|
|
|
216
|
-
|
|
|
217
|
-
|
|
|
218
|
-
|
|
|
219
|
-
|
|
|
218
|
+
| `level-0` … `level-4` | GitHub greens | the five contribution colours |
|
|
219
|
+
| `bg`, `border` | white / `#e1e4e8` | the card's background and border |
|
|
220
|
+
| `fg`, `fg-muted` | `#24292f` / `#656d76` | day and month names; legend text |
|
|
221
|
+
| `radius`, `padding` | `6px`, `20px` (`15px` ≤768px, `10px` ≤480px) | the card |
|
|
222
|
+
| `shadow-color` | `rgba(0, 0, 0, 0.1)` | the card's shadow |
|
|
223
|
+
| `font-family` | a system UI stack | the font for every label |
|
|
224
|
+
| `label-size` | `11px` | day names, month names, legend text |
|
|
225
|
+
| `day-header-font-family` | a monospace stack | the day names above the reversed layout's columns |
|
|
226
|
+
| `day-size` | `12px`; `20px` minimum when reversed | the side of each square in the default layout |
|
|
227
|
+
| `day-gap` | `2px` (`1px` ≤768px) | the space between squares |
|
|
228
|
+
| `day-radius` | `2px` | the corners of each square |
|
|
229
|
+
| `tooltip-shadow` | a soft drop shadow | the shadow under a hovered square |
|
|
230
|
+
| `focus-ring` | `level-3` | the keyboard focus outline |
|
|
231
|
+
| `transition` | `all 0.2s ease` | hover transitions |
|
|
232
|
+
|
|
233
|
+
The colours above are the light defaults; dark mode swaps them for GitHub's dark palette.
|
|
220
234
|
|
|
221
235
|
```css
|
|
222
236
|
.contribution-heatmap {
|
|
223
|
-
--heatmap-font-family: "Inter", sans-serif;
|
|
224
|
-
--day-size: 16px;
|
|
237
|
+
--contribution-heatmap-font-family: "Inter", sans-serif;
|
|
238
|
+
--contribution-heatmap-day-size: 16px;
|
|
225
239
|
}
|
|
226
240
|
```
|
|
227
241
|
|
|
@@ -240,7 +254,7 @@ only thing in the card.
|
|
|
240
254
|
|
|
241
255
|
The squares keep their size on small screens rather than shrinking. A year is 53 weeks, so
|
|
242
256
|
the grid overflows a phone whatever size they take — it scrolls either way, and shrinking
|
|
243
|
-
would only cost legibility and tap area. Set `--day-size` yourself if you want a denser
|
|
257
|
+
would only cost legibility and tap area. Set `--contribution-heatmap-day-size` yourself if you want a denser
|
|
244
258
|
grid.
|
|
245
259
|
|
|
246
260
|
With `isReverse`, the root also carries `contribution-heatmap--reverse`. That layout puts
|
|
@@ -254,8 +268,8 @@ a monospace one renders all seven at an identical width — in a proportional fa
|
|
|
254
268
|
|
|
255
269
|
Because the column can be no narrower than its header, and that width depends on the
|
|
256
270
|
locale — `Wed` is 20px, French `mer.` is 26.5px — the reversed square **fills its cell**
|
|
257
|
-
rather than taking a fixed size. `--day-size` is only a floor there. That is what keeps the
|
|
258
|
-
squares flush in any language. Override `--heatmap-day-header-font-family` under that
|
|
271
|
+
rather than taking a fixed size. `--contribution-heatmap-day-size` is only a floor there. That is what keeps the
|
|
272
|
+
squares flush in any language. Override `--contribution-heatmap-day-header-font-family` under that
|
|
259
273
|
class to change the face.
|
|
260
274
|
|
|
261
275
|
The grid always renders whole weeks, so the first and last week can hold days outside your
|
|
@@ -286,6 +300,42 @@ weeks Monday to Sunday, so a translated heatmap that still starts on Sunday read
|
|
|
286
300
|
wrong. It defaults to `0` (Sunday, the GitHub convention), and the component picks the
|
|
287
301
|
order of its day labels up from the data.
|
|
288
302
|
|
|
303
|
+
## What's new in 0.4.1
|
|
304
|
+
|
|
305
|
+
**No empty table header.** The corner cell above the day-name column was an empty `<th>`,
|
|
306
|
+
which axe reports (`empty-table-header`) and a screen reader announces as a blank header.
|
|
307
|
+
It is now a `<td>`. Nothing renders differently.
|
|
308
|
+
|
|
309
|
+
## What's new in 0.4.0
|
|
310
|
+
|
|
311
|
+
**Every custom property now carries the component's prefix, `--contribution-heatmap-`.**
|
|
312
|
+
The old names were generic (`--color-bg`, `--day-size`, `--border-radius`) and could
|
|
313
|
+
collide with anything else on the page. The old names still work in 0.4.0 and are
|
|
314
|
+
removed in 0.5.0:
|
|
315
|
+
|
|
316
|
+
| Old | New |
|
|
317
|
+
| --- | --- |
|
|
318
|
+
| `--color-level-0` … `--color-level-4` | `--contribution-heatmap-level-0` … `-level-4` |
|
|
319
|
+
| `--color-bg` | `--contribution-heatmap-bg` |
|
|
320
|
+
| `--color-border` | `--contribution-heatmap-border` |
|
|
321
|
+
| `--color-text` | `--contribution-heatmap-fg` |
|
|
322
|
+
| `--color-text-muted` | `--contribution-heatmap-fg-muted` |
|
|
323
|
+
| `--border-radius` | `--contribution-heatmap-radius` |
|
|
324
|
+
| `--shadow-color` | `--contribution-heatmap-shadow-color` |
|
|
325
|
+
| `--transition` | `--contribution-heatmap-transition` |
|
|
326
|
+
| `--day-size` | `--contribution-heatmap-day-size` |
|
|
327
|
+
| `--day-gap` | `--contribution-heatmap-day-gap` |
|
|
328
|
+
| `--heatmap-font-family` | `--contribution-heatmap-font-family` |
|
|
329
|
+
| `--heatmap-label-size` | `--contribution-heatmap-label-size` |
|
|
330
|
+
| `--heatmap-day-header-font-family` | `--contribution-heatmap-day-header-font-family` |
|
|
331
|
+
|
|
332
|
+
**Four values that were fixed are now properties:** `padding`, `day-radius`,
|
|
333
|
+
`tooltip-shadow` and `focus-ring`. A design system can now reach every visual value.
|
|
334
|
+
|
|
335
|
+
To migrate, rename the properties you set. One difference: a theme written with the old
|
|
336
|
+
level names is replaced by the dark palette in dark mode, as before. A theme written with
|
|
337
|
+
the new names applies in both schemes.
|
|
338
|
+
|
|
289
339
|
## What's new in 0.3.1
|
|
290
340
|
|
|
291
341
|
**Dates are read as local calendar days.** In any time zone other than UTC, 0.3.0 could
|
package/dist/index.css
CHANGED
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
/* src/ContributionHeatmap/index.scss */
|
|
2
2
|
.contribution-heatmap {
|
|
3
|
-
--heatmap-font-family:
|
|
4
|
-
-apple-system,
|
|
5
|
-
BlinkMacSystemFont,
|
|
6
|
-
"Segoe UI",
|
|
7
|
-
"Noto Sans",
|
|
8
|
-
Helvetica,
|
|
9
|
-
Arial,
|
|
10
|
-
sans-serif;
|
|
11
|
-
--heatmap-label-size: 11px;
|
|
12
|
-
--heatmap-day-header-font-family:
|
|
13
|
-
ui-monospace,
|
|
14
|
-
SFMono-Regular,
|
|
15
|
-
Menlo,
|
|
16
|
-
Consolas,
|
|
17
|
-
monospace;
|
|
18
3
|
--day-size: 12px;
|
|
19
4
|
--day-gap: 2px;
|
|
20
5
|
--border-radius: 6px;
|
|
@@ -29,6 +14,27 @@
|
|
|
29
14
|
--color-level-2: #40c463;
|
|
30
15
|
--color-level-3: #30a14e;
|
|
31
16
|
--color-level-4: #216e39;
|
|
17
|
+
--contribution-heatmap-bg: var(--color-bg);
|
|
18
|
+
--contribution-heatmap-border: var(--color-border);
|
|
19
|
+
--contribution-heatmap-fg: var(--color-text);
|
|
20
|
+
--contribution-heatmap-fg-muted: var(--color-text-muted);
|
|
21
|
+
--contribution-heatmap-level-0: var(--color-level-0);
|
|
22
|
+
--contribution-heatmap-level-1: var(--color-level-1);
|
|
23
|
+
--contribution-heatmap-level-2: var(--color-level-2);
|
|
24
|
+
--contribution-heatmap-level-3: var(--color-level-3);
|
|
25
|
+
--contribution-heatmap-level-4: var(--color-level-4);
|
|
26
|
+
--contribution-heatmap-radius: var(--border-radius);
|
|
27
|
+
--contribution-heatmap-shadow-color: var(--shadow-color);
|
|
28
|
+
--contribution-heatmap-transition: var(--transition);
|
|
29
|
+
--contribution-heatmap-day-size: var(--day-size);
|
|
30
|
+
--contribution-heatmap-day-gap: var(--day-gap);
|
|
31
|
+
--contribution-heatmap-font-family: var( --heatmap-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif );
|
|
32
|
+
--contribution-heatmap-label-size: var(--heatmap-label-size, 11px);
|
|
33
|
+
--contribution-heatmap-day-header-font-family: var( --heatmap-day-header-font-family, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace );
|
|
34
|
+
--contribution-heatmap-padding: 20px;
|
|
35
|
+
--contribution-heatmap-day-radius: 2px;
|
|
36
|
+
--contribution-heatmap-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
|
37
|
+
--contribution-heatmap-focus-ring: var(--contribution-heatmap-level-3);
|
|
32
38
|
color-scheme: light dark;
|
|
33
39
|
}
|
|
34
40
|
@media (prefers-color-scheme: dark) {
|
|
@@ -60,16 +66,16 @@
|
|
|
60
66
|
color-scheme: light;
|
|
61
67
|
}
|
|
62
68
|
.contribution-heatmap {
|
|
63
|
-
font-family: var(--heatmap-font-family);
|
|
64
|
-
font-size: var(--heatmap-label-size);
|
|
69
|
+
font-family: var(--contribution-heatmap-font-family);
|
|
70
|
+
font-size: var(--contribution-heatmap-label-size);
|
|
65
71
|
line-height: 1;
|
|
66
|
-
color: var(--
|
|
67
|
-
background: var(--
|
|
68
|
-
border-radius: var(--
|
|
69
|
-
padding:
|
|
70
|
-
box-shadow: 0 2px 8px var(--shadow-color);
|
|
71
|
-
border: 1px solid var(--
|
|
72
|
-
transition: var(--transition);
|
|
72
|
+
color: var(--contribution-heatmap-fg-muted);
|
|
73
|
+
background: var(--contribution-heatmap-bg);
|
|
74
|
+
border-radius: var(--contribution-heatmap-radius);
|
|
75
|
+
padding: var(--contribution-heatmap-padding);
|
|
76
|
+
box-shadow: 0 2px 8px var(--contribution-heatmap-shadow-color);
|
|
77
|
+
border: 1px solid var(--contribution-heatmap-border);
|
|
78
|
+
transition: var(--contribution-heatmap-transition);
|
|
73
79
|
box-sizing: border-box;
|
|
74
80
|
max-width: 100%;
|
|
75
81
|
}
|
|
@@ -82,15 +88,15 @@
|
|
|
82
88
|
.contribution-heatmap__table {
|
|
83
89
|
width: max-content;
|
|
84
90
|
border-collapse: separate;
|
|
85
|
-
border-spacing: var(--day-gap);
|
|
91
|
+
border-spacing: var(--contribution-heatmap-day-gap);
|
|
86
92
|
}
|
|
87
93
|
.contribution-heatmap__month-header,
|
|
88
94
|
.contribution-heatmap__day-header,
|
|
89
95
|
.contribution-heatmap__day-label,
|
|
90
96
|
.contribution-heatmap__month-label {
|
|
91
|
-
font-size: var(--heatmap-label-size);
|
|
97
|
+
font-size: var(--contribution-heatmap-label-size);
|
|
92
98
|
font-weight: 500;
|
|
93
|
-
color: var(--
|
|
99
|
+
color: var(--contribution-heatmap-fg);
|
|
94
100
|
white-space: nowrap;
|
|
95
101
|
padding: 0;
|
|
96
102
|
border: none;
|
|
@@ -103,7 +109,7 @@
|
|
|
103
109
|
}
|
|
104
110
|
.contribution-heatmap__month-header {
|
|
105
111
|
position: relative;
|
|
106
|
-
height: calc(var(--heatmap-label-size) + 6px);
|
|
112
|
+
height: calc(var(--contribution-heatmap-label-size) + 6px);
|
|
107
113
|
}
|
|
108
114
|
.contribution-heatmap__month-header-text {
|
|
109
115
|
position: absolute;
|
|
@@ -122,7 +128,7 @@
|
|
|
122
128
|
position: sticky;
|
|
123
129
|
left: 0;
|
|
124
130
|
z-index: 1;
|
|
125
|
-
background: var(--
|
|
131
|
+
background: var(--contribution-heatmap-bg);
|
|
126
132
|
}
|
|
127
133
|
.contribution-heatmap__day-label {
|
|
128
134
|
vertical-align: middle;
|
|
@@ -131,25 +137,25 @@
|
|
|
131
137
|
vertical-align: top;
|
|
132
138
|
}
|
|
133
139
|
.contribution-heatmap:hover {
|
|
134
|
-
box-shadow: 0 4px 16px var(--shadow-color);
|
|
140
|
+
box-shadow: 0 4px 16px var(--contribution-heatmap-shadow-color);
|
|
135
141
|
}
|
|
136
142
|
@media (max-width: 768px) {
|
|
137
143
|
.contribution-heatmap {
|
|
138
144
|
--day-gap: 1px;
|
|
139
|
-
padding: 15px;
|
|
145
|
+
--contribution-heatmap-padding: 15px;
|
|
140
146
|
}
|
|
141
147
|
}
|
|
142
148
|
@media (max-width: 480px) {
|
|
143
149
|
.contribution-heatmap {
|
|
144
150
|
--day-gap: 1px;
|
|
145
|
-
padding: 10px;
|
|
151
|
+
--contribution-heatmap-padding: 10px;
|
|
146
152
|
}
|
|
147
153
|
}
|
|
148
154
|
.contribution-heatmap--reverse {
|
|
149
155
|
--day-size: 20px;
|
|
150
156
|
}
|
|
151
157
|
.contribution-heatmap--reverse .contribution-heatmap__day-header {
|
|
152
|
-
font-family: var(--heatmap-day-header-font-family);
|
|
158
|
+
font-family: var(--contribution-heatmap-day-header-font-family);
|
|
153
159
|
text-align: center;
|
|
154
160
|
}
|
|
155
161
|
.contribution-heatmap--reverse .contribution-heatmap__day {
|
|
@@ -166,9 +172,9 @@
|
|
|
166
172
|
}
|
|
167
173
|
}
|
|
168
174
|
.contribution-heatmap__day {
|
|
169
|
-
width: var(--day-size);
|
|
170
|
-
min-width: var(--day-size);
|
|
171
|
-
height: var(--day-size);
|
|
175
|
+
width: var(--contribution-heatmap-day-size);
|
|
176
|
+
min-width: var(--contribution-heatmap-day-size);
|
|
177
|
+
height: var(--contribution-heatmap-day-size);
|
|
172
178
|
padding: 0;
|
|
173
179
|
border: none;
|
|
174
180
|
cursor: pointer;
|
|
@@ -177,54 +183,54 @@
|
|
|
177
183
|
.contribution-heatmap__day::before {
|
|
178
184
|
content: "";
|
|
179
185
|
display: block;
|
|
180
|
-
width: var(--day-size);
|
|
181
|
-
height: var(--day-size);
|
|
186
|
+
width: var(--contribution-heatmap-day-size);
|
|
187
|
+
height: var(--contribution-heatmap-day-size);
|
|
182
188
|
margin-inline: auto;
|
|
183
189
|
box-sizing: border-box;
|
|
184
190
|
border: 1px solid transparent;
|
|
185
|
-
border-radius:
|
|
186
|
-
background-color: var(--
|
|
187
|
-
transition: var(--transition);
|
|
191
|
+
border-radius: var(--contribution-heatmap-day-radius);
|
|
192
|
+
background-color: var(--contribution-heatmap-level-0);
|
|
193
|
+
transition: var(--contribution-heatmap-transition);
|
|
188
194
|
}
|
|
189
195
|
.contribution-heatmap__day--level-0:hover::before {
|
|
190
|
-
background-color: var(--
|
|
191
|
-
border-color: var(--
|
|
196
|
+
background-color: var(--contribution-heatmap-level-1);
|
|
197
|
+
border-color: var(--contribution-heatmap-level-2);
|
|
192
198
|
}
|
|
193
199
|
.contribution-heatmap__day--level-1::before {
|
|
194
|
-
background-color: var(--
|
|
200
|
+
background-color: var(--contribution-heatmap-level-1);
|
|
195
201
|
}
|
|
196
202
|
.contribution-heatmap__day--level-1:hover::before {
|
|
197
|
-
background-color: var(--
|
|
198
|
-
border-color: var(--
|
|
203
|
+
background-color: var(--contribution-heatmap-level-2);
|
|
204
|
+
border-color: var(--contribution-heatmap-level-3);
|
|
199
205
|
}
|
|
200
206
|
.contribution-heatmap__day--level-2::before {
|
|
201
|
-
background-color: var(--
|
|
207
|
+
background-color: var(--contribution-heatmap-level-2);
|
|
202
208
|
}
|
|
203
209
|
.contribution-heatmap__day--level-2:hover::before {
|
|
204
|
-
background-color: var(--
|
|
205
|
-
border-color: var(--
|
|
210
|
+
background-color: var(--contribution-heatmap-level-3);
|
|
211
|
+
border-color: var(--contribution-heatmap-level-4);
|
|
206
212
|
}
|
|
207
213
|
.contribution-heatmap__day--level-3::before {
|
|
208
|
-
background-color: var(--
|
|
214
|
+
background-color: var(--contribution-heatmap-level-3);
|
|
209
215
|
}
|
|
210
216
|
.contribution-heatmap__day--level-3:hover::before {
|
|
211
|
-
background-color: var(--
|
|
212
|
-
border-color: var(--
|
|
217
|
+
background-color: var(--contribution-heatmap-level-4);
|
|
218
|
+
border-color: var(--contribution-heatmap-level-4);
|
|
213
219
|
}
|
|
214
220
|
.contribution-heatmap__day--level-4::before {
|
|
215
|
-
background-color: var(--
|
|
221
|
+
background-color: var(--contribution-heatmap-level-4);
|
|
216
222
|
}
|
|
217
223
|
.contribution-heatmap__day--level-4:hover::before {
|
|
218
224
|
filter: brightness(1.1);
|
|
219
|
-
border-color: var(--
|
|
225
|
+
border-color: var(--contribution-heatmap-level-4);
|
|
220
226
|
}
|
|
221
227
|
.contribution-heatmap__day:hover {
|
|
222
228
|
z-index: 10;
|
|
223
229
|
}
|
|
224
230
|
.contribution-heatmap__day:hover::before {
|
|
225
231
|
transform: scale(1.2);
|
|
226
|
-
box-shadow:
|
|
227
|
-
border-radius:
|
|
232
|
+
box-shadow: var(--contribution-heatmap-tooltip-shadow);
|
|
233
|
+
border-radius: calc(var(--contribution-heatmap-day-radius) + 1px);
|
|
228
234
|
}
|
|
229
235
|
.contribution-heatmap__day--outside {
|
|
230
236
|
cursor: default;
|
|
@@ -236,7 +242,7 @@
|
|
|
236
242
|
outline: none;
|
|
237
243
|
}
|
|
238
244
|
.contribution-heatmap__day:focus-visible::before {
|
|
239
|
-
outline: 2px solid var(--
|
|
245
|
+
outline: 2px solid var(--contribution-heatmap-focus-ring);
|
|
240
246
|
outline-offset: 2px;
|
|
241
247
|
}
|
|
242
248
|
.contribution-heatmap__legend {
|
|
@@ -254,8 +260,8 @@
|
|
|
254
260
|
}
|
|
255
261
|
}
|
|
256
262
|
.contribution-heatmap__legend-text {
|
|
257
|
-
color: var(--
|
|
258
|
-
font-size: var(--heatmap-label-size);
|
|
263
|
+
color: var(--contribution-heatmap-fg-muted);
|
|
264
|
+
font-size: var(--contribution-heatmap-label-size);
|
|
259
265
|
font-weight: 500;
|
|
260
266
|
margin: 0 4px;
|
|
261
267
|
}
|
|
@@ -267,10 +273,10 @@
|
|
|
267
273
|
.contribution-heatmap__legend-item {
|
|
268
274
|
width: 12px;
|
|
269
275
|
height: 12px;
|
|
270
|
-
border-radius:
|
|
276
|
+
border-radius: var(--contribution-heatmap-day-radius);
|
|
271
277
|
cursor: help;
|
|
272
|
-
transition: var(--transition);
|
|
273
|
-
border: 1px solid var(--
|
|
278
|
+
transition: var(--contribution-heatmap-transition);
|
|
279
|
+
border: 1px solid var(--contribution-heatmap-border);
|
|
274
280
|
}
|
|
275
281
|
@media (max-width: 768px) {
|
|
276
282
|
.contribution-heatmap__legend-item {
|
|
@@ -280,22 +286,22 @@
|
|
|
280
286
|
}
|
|
281
287
|
.contribution-heatmap__legend-item:hover {
|
|
282
288
|
transform: scale(1.2);
|
|
283
|
-
border-color: var(--
|
|
289
|
+
border-color: var(--contribution-heatmap-fg-muted);
|
|
284
290
|
}
|
|
285
291
|
.contribution-heatmap__legend-item--level-0 {
|
|
286
|
-
background-color: var(--
|
|
292
|
+
background-color: var(--contribution-heatmap-level-0);
|
|
287
293
|
}
|
|
288
294
|
.contribution-heatmap__legend-item--level-1 {
|
|
289
|
-
background-color: var(--
|
|
295
|
+
background-color: var(--contribution-heatmap-level-1);
|
|
290
296
|
}
|
|
291
297
|
.contribution-heatmap__legend-item--level-2 {
|
|
292
|
-
background-color: var(--
|
|
298
|
+
background-color: var(--contribution-heatmap-level-2);
|
|
293
299
|
}
|
|
294
300
|
.contribution-heatmap__legend-item--level-3 {
|
|
295
|
-
background-color: var(--
|
|
301
|
+
background-color: var(--contribution-heatmap-level-3);
|
|
296
302
|
}
|
|
297
303
|
.contribution-heatmap__legend-item--level-4 {
|
|
298
|
-
background-color: var(--
|
|
304
|
+
background-color: var(--contribution-heatmap-level-4);
|
|
299
305
|
}
|
|
300
306
|
@keyframes fadeInUp {
|
|
301
307
|
from {
|
package/dist/index.css.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ContributionHeatmap/index.scss"],"sourcesContent":["// ContributionHeatmap.scss\n// GitHub-style contribution heatmap with BEM methodology\n@use 'sass:meta';\n@use '../shared/typography';\n\n@mixin dark-tokens {\n --color-bg: #0d1117;\n --color-border: #30363d;\n --color-text: #f0f6fc;\n --color-text-muted: #8b949e;\n --color-level-0: #161b22;\n --color-level-1: #0e4429;\n --color-level-2: #006d32;\n --color-level-3: #26a641;\n --color-level-4: #39d353;\n}\n\n.contribution-heatmap {\n // Typography - overridable exactly like the colour tokens below\n // meta.inspect keeps the quotes that plain interpolation would strip.\n --heatmap-font-family: #{meta.inspect(typography.$font-stack)};\n --heatmap-label-size: 11px;\n --heatmap-day-header-font-family: #{meta.inspect(typography.$mono-stack)};\n\n // Component variables\n --day-size: 12px;\n --day-gap: 2px;\n --border-radius: 6px;\n --transition: all 0.2s ease;\n --shadow-color: rgba(0, 0, 0, 0.1);\n\n // Color scheme - GitHub-inspired\n --color-bg: #ffffff;\n --color-border: #e1e4e8;\n --color-text: #24292f;\n --color-text-muted: #656d76;\n --color-level-0: #ebedf0;\n --color-level-1: #9be9a8;\n --color-level-2: #40c463;\n --color-level-3: #30a14e;\n --color-level-4: #216e39;\n\n // Dark mode. Follows the system by default; --light and --dark force it either way,\n // which is why the palette is a mixin - it has to be emitted twice, once guarded by\n // :not(--light) so forcing light wins under a dark system, and once unguarded on\n // --dark so forcing dark wins under a light one.\n color-scheme: light dark;\n\n @media (prefers-color-scheme: dark) {\n &:not(.contribution-heatmap--light) {\n @include dark-tokens;\n }\n }\n\n &--dark {\n @include dark-tokens;\n color-scheme: dark;\n }\n\n &--light {\n color-scheme: light;\n }\n\n font-family: var(--heatmap-font-family);\n font-size: var(--heatmap-label-size);\n line-height: 1;\n color: var(--color-text-muted);\n background: var(--color-bg);\n border-radius: var(--border-radius);\n padding: 20px;\n box-shadow: 0 2px 8px var(--shadow-color);\n border: 1px solid var(--color-border);\n transition: var(--transition);\n // An ordinary full-width block. It used to shrink-wrap its grid so the legend stayed\n // with it, but WebKit would not do that by any means tried - width: fit-content,\n // -webkit-fit-content, and CSS 2.1 inline-block all render full width on iOS while\n // Chrome shrink-wraps all three. The common factor is the scroll container child\n // (__scroll), though that was never confirmed. Rather than guess a fourth time, the\n // legend is aligned to the start instead, so a full-width card reads correctly\n // whatever the reason - and every browser now renders the same thing.\n //\n // border-box matters here: the library ships no reset, and under content-box the\n // padding is added on top of max-width and the card overflows its parent.\n box-sizing: border-box;\n max-width: 100%;\n\n // Only the grid scrolls - the padding, border and legend stay put.\n &__scroll {\n overflow-x: auto;\n overscroll-behavior-x: contain;\n scrollbar-width: thin;\n // overflow-x:auto makes overflow-y compute to auto too, which would clip the\n // :hover scale on the top and bottom rows. Give it room.\n padding-block: 3px;\n }\n\n // Intrinsic width: the columns are sized by the cells, never stretched to the\n // container. This is what makes --day-size mean something and lets the grid\n // scroll instead of squashing.\n &__table {\n width: max-content;\n border-collapse: separate;\n border-spacing: var(--day-gap);\n }\n\n // Sun/Mon/... and the month names. The two classes swap roles between the\n // default and reversed layouts, so both need the same treatment.\n &__month-header,\n &__day-header,\n &__day-label,\n &__month-label {\n font-size: var(--heatmap-label-size);\n font-weight: 500;\n color: var(--color-text);\n white-space: nowrap;\n padding: 0;\n border: none;\n background: none;\n }\n\n &__month-header,\n &__day-header {\n text-align: left;\n padding-bottom: 4px;\n }\n\n // A month at the edge of the period can span a single week, and its own label is\n // wider than one column. Taking the text out of flow stops it setting the column\n // width - otherwise that one week stretches and opens a gap in the grid.\n &__month-header {\n position: relative;\n height: calc(var(--heatmap-label-size) + 6px);\n }\n\n &__month-header-text {\n position: absolute;\n left: 0;\n bottom: 4px;\n }\n\n // The trailing month is the one that can span a single week, and out of flow its\n // label would overhang the last column - widening the scroll area for the sake of\n // a few pixels of text. Anchor it to the right so it overhangs inwards instead.\n &__month-header--last &__month-header-text {\n left: auto;\n right: 0;\n }\n\n // Shrink-to-fit, so the label column keeps its own width instead of\n // collapsing to a day column. Pinned, so it survives a horizontal scroll -\n // the background has to be opaque because cells slide underneath.\n &__day-label,\n &__month-label {\n width: 1%;\n text-align: right;\n padding-right: 6px;\n position: sticky;\n left: 0;\n z-index: 1;\n background: var(--color-bg);\n }\n\n &__day-label {\n vertical-align: middle;\n }\n\n // Sits against a rowSpan in the reversed layout.\n &__month-label {\n vertical-align: top;\n }\n\n // Hover effect for the entire component\n &:hover {\n box-shadow: 0 4px 16px var(--shadow-color);\n }\n\n // Mobile responsiveness. --day-size deliberately does NOT shrink here: a year is\n // 53 weeks plus a label column, so the grid overflows a phone at every size it\n // could reasonably take (507px at 8px squares, against ~373px of usable width).\n // It scrolls either way, so shrinking only cost legibility and left a 9px tap\n // target on cells that are role=\"button\". Reclaiming the padding is free, and so\n // is the tighter gap - border-spacing is not part of a cell's hit area.\n @media (max-width: 768px) {\n --day-gap: 1px;\n padding: 15px;\n }\n\n @media (max-width: 480px) {\n --day-gap: 1px;\n padding: 10px;\n }\n\n // The reversed layout puts the day names above the columns, so no column can be\n // narrower than \"Wed\". Grow the squares to match instead of leaving every one of\n // them floating in a wider cell. Only seven columns, so it fits at any width.\n &--reverse {\n // Sized to clear the widest day header, which the monospace face below brings\n // down to 19.87px from the proportional \"Wed\" at 23.7px.\n --day-size: 20px;\n\n // The day names sit above their own column here, rather than being row labels,\n // so their differing widths show up as uneven spacing. Monospace makes all\n // seven identical - if a fallback face renders wider, every column widens by\n // the same amount, so the rhythm still can't go uneven.\n .contribution-heatmap__day-header {\n font-family: var(--heatmap-day-header-font-family);\n text-align: center;\n }\n\n // The column is only ever as narrow as its day-name header, and that width is\n // locale-dependent: \"Wed\" is three characters, French \"mer.\" is four. Fill the\n // cell rather than sitting at a fixed px size, so the square tracks whatever the\n // header needs and never leaves slack. --day-size above is the floor.\n .contribution-heatmap__day {\n height: auto;\n\n &::before {\n width: 100%;\n height: auto;\n aspect-ratio: 1;\n }\n }\n\n // On a phone the month grid is the only thing in the card, so let it fill the\n // width - 20px squares marooned in a full-width card look lost. The square\n // already fills its cell above, so widening the table is all that is needed.\n // Auto layout, so __month-label's width: 1% still collapses the Aug/Sep column;\n // table-layout: fixed would divide the width equally and hand the label a full\n // day column.\n @media (max-width: 480px) {\n .contribution-heatmap__table {\n width: 100%;\n }\n }\n }\n\n // Individual day. The cell is only a slot: the visible square is drawn by\n // ::before so that a column wider than --day-size - the reversed layout sizes\n // its columns to the Sun/Mon/... headers - can never stretch the square.\n &__day {\n width: var(--day-size);\n min-width: var(--day-size);\n height: var(--day-size);\n padding: 0;\n border: none;\n cursor: pointer;\n position: relative;\n\n &::before {\n content: '';\n display: block;\n width: var(--day-size);\n height: var(--day-size);\n margin-inline: auto;\n box-sizing: border-box;\n border: 1px solid transparent;\n border-radius: 2px;\n background-color: var(--color-level-0);\n transition: var(--transition);\n }\n\n // Contribution levels\n &--level-0:hover::before {\n background-color: var(--color-level-1);\n border-color: var(--color-level-2);\n }\n\n &--level-1::before {\n background-color: var(--color-level-1);\n }\n\n &--level-1:hover::before {\n background-color: var(--color-level-2);\n border-color: var(--color-level-3);\n }\n\n &--level-2::before {\n background-color: var(--color-level-2);\n }\n\n &--level-2:hover::before {\n background-color: var(--color-level-3);\n border-color: var(--color-level-4);\n }\n\n &--level-3::before {\n background-color: var(--color-level-3);\n }\n\n &--level-3:hover::before {\n background-color: var(--color-level-4);\n border-color: var(--color-level-4);\n }\n\n &--level-4::before {\n background-color: var(--color-level-4);\n }\n\n &--level-4:hover::before {\n filter: brightness(1.1);\n border-color: var(--color-level-4);\n }\n\n // Hover effects\n &:hover {\n z-index: 10;\n }\n\n &:hover::before {\n transform: scale(1.2);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n border-radius: 3px;\n }\n\n // Padding days from groupByWeeks' whole-week fill: outside the period, so\n // they hold the column open but draw nothing. visibility rather than display\n // keeps their contribution to the column width.\n &--outside {\n cursor: default;\n\n &::before {\n visibility: hidden;\n }\n }\n\n // Focus styles for accessibility\n &:focus-visible {\n outline: none;\n }\n\n &:focus-visible::before {\n outline: 2px solid var(--color-level-3);\n outline-offset: 2px;\n }\n }\n\n // Legend\n &__legend {\n display: flex;\n align-items: center;\n // Start-aligned, not centred: the card is as wide as its container while the grid\n // is only as wide as its content, so centring floats the legend away from the\n // squares it describes.\n justify-content: flex-start;\n gap: 4px;\n margin-top: 12px;\n flex-wrap: wrap;\n\n @media (max-width: 768px) {\n gap: 3px;\n margin-top: 8px;\n }\n }\n\n &__legend-text {\n color: var(--color-text-muted);\n font-size: var(--heatmap-label-size);\n font-weight: 500;\n margin: 0 4px;\n\n @media (max-width: 768px) {\n margin: 0 2px;\n }\n }\n\n &__legend-item {\n width: 12px;\n height: 12px;\n border-radius: 2px;\n cursor: help;\n transition: var(--transition);\n border: 1px solid var(--color-border);\n\n @media (max-width: 768px) {\n width: 10px;\n height: 10px;\n }\n\n &:hover {\n transform: scale(1.2);\n border-color: var(--color-text-muted);\n }\n\n &--level-0 {\n background-color: var(--color-level-0);\n }\n &--level-1 {\n background-color: var(--color-level-1);\n }\n &--level-2 {\n background-color: var(--color-level-2);\n }\n &--level-3 {\n background-color: var(--color-level-3);\n }\n &--level-4 {\n background-color: var(--color-level-4);\n }\n }\n}\n\n// Animation for initial load\n@keyframes fadeInUp {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n// A year is 371 staggered cells plus the card itself; none of it runs for users who\n// have asked their OS for less motion. The cells have no `from` state outside the\n// animation, so with it off they simply appear in place.\n@media (prefers-reduced-motion: no-preference) {\n .contribution-heatmap {\n animation: fadeInUp 0.6s ease-out;\n\n // --animation-delay is set inline per cell and inherits into the pseudo-element.\n &__day::before {\n animation: fadeInUp 0.3s ease-out;\n animation-delay: var(--animation-delay, 0s);\n animation-fill-mode: both;\n }\n }\n}\n\n// Utilities for different themes\n.contribution-heatmap {\n // Ocean theme\n &--ocean {\n --color-level-0: #e6f3ff;\n --color-level-1: #b3daff;\n --color-level-2: #66b3ff;\n --color-level-3: #1a8cff;\n --color-level-4: #0066cc;\n }\n\n // Sunset theme\n &--sunset {\n --color-level-0: #fff2e6;\n --color-level-1: #ffcc99;\n --color-level-2: #ff9933;\n --color-level-3: #ff6600;\n --color-level-4: #cc3300;\n }\n\n // Purple theme\n &--purple {\n --color-level-0: #f3e6ff;\n --color-level-1: #d9b3ff;\n --color-level-2: #b366ff;\n --color-level-3: #8a1aff;\n --color-level-4: #6600cc;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/ContributionHeatmap/index.scss"],"sourcesContent":["// ContributionHeatmap.scss\n// GitHub-style contribution heatmap with BEM methodology\n@use 'sass:meta';\n@use '../shared/typography';\n\n@mixin dark-tokens {\n --color-bg: #0d1117;\n --color-border: #30363d;\n --color-text: #f0f6fc;\n --color-text-muted: #8b949e;\n --color-level-0: #161b22;\n --color-level-1: #0e4429;\n --color-level-2: #006d32;\n --color-level-3: #26a641;\n --color-level-4: #39d353;\n}\n\n.contribution-heatmap {\n // The public styling surface is --contribution-heatmap-*, one prefix owned by this\n // block (ADR-0012). Every rule below reads only those names.\n //\n // Deprecated in 0.4.0, removed in 0.5.0: the un-prefixed names (--color-level-N,\n // --color-bg, --day-size, ...). Until then they hold the defaults - here, in the\n // dark-tokens mixin and in the themes - and each public name is an alias of its old\n // one, so a consumer class that still sets an old name keeps today's precedence\n // exactly, dark mode included. Setting a public name replaces the alias.\n --day-size: 12px;\n --day-gap: 2px;\n --border-radius: 6px;\n --transition: all 0.2s ease;\n --shadow-color: rgba(0, 0, 0, 0.1);\n\n // Color scheme - GitHub-inspired\n --color-bg: #ffffff;\n --color-border: #e1e4e8;\n --color-text: #24292f;\n --color-text-muted: #656d76;\n --color-level-0: #ebedf0;\n --color-level-1: #9be9a8;\n --color-level-2: #40c463;\n --color-level-3: #30a14e;\n --color-level-4: #216e39;\n\n // The public names.\n --contribution-heatmap-bg: var(--color-bg);\n --contribution-heatmap-border: var(--color-border);\n --contribution-heatmap-fg: var(--color-text);\n --contribution-heatmap-fg-muted: var(--color-text-muted);\n --contribution-heatmap-level-0: var(--color-level-0);\n --contribution-heatmap-level-1: var(--color-level-1);\n --contribution-heatmap-level-2: var(--color-level-2);\n --contribution-heatmap-level-3: var(--color-level-3);\n --contribution-heatmap-level-4: var(--color-level-4);\n --contribution-heatmap-radius: var(--border-radius);\n --contribution-heatmap-shadow-color: var(--shadow-color);\n --contribution-heatmap-transition: var(--transition);\n --contribution-heatmap-day-size: var(--day-size);\n --contribution-heatmap-day-gap: var(--day-gap);\n\n // The old typography names are only read as fallbacks, never declared here: a\n // declaration on this element would shadow an inherited --heatmap-* value, and a\n // design system that wraps this component (pulp's Heatmap) names its own tokens\n // exactly that. Fonts have no dark variant, so there is no precedence to keep.\n // meta.inspect keeps the quotes that plain interpolation would strip.\n --contribution-heatmap-font-family: var(\n --heatmap-font-family,\n #{meta.inspect(typography.$font-stack)}\n );\n --contribution-heatmap-label-size: var(--heatmap-label-size, 11px);\n --contribution-heatmap-day-header-font-family: var(\n --heatmap-day-header-font-family,\n #{meta.inspect(typography.$mono-stack)}\n );\n\n // New in 0.4.0: values that used to be literals.\n --contribution-heatmap-padding: 20px;\n --contribution-heatmap-day-radius: 2px;\n --contribution-heatmap-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n --contribution-heatmap-focus-ring: var(--contribution-heatmap-level-3);\n\n // Dark mode. Follows the system by default; --light and --dark force it either way,\n // which is why the palette is a mixin - it has to be emitted twice, once guarded by\n // :not(--light) so forcing light wins under a dark system, and once unguarded on\n // --dark so forcing dark wins under a light one.\n color-scheme: light dark;\n\n @media (prefers-color-scheme: dark) {\n &:not(.contribution-heatmap--light) {\n @include dark-tokens;\n }\n }\n\n &--dark {\n @include dark-tokens;\n color-scheme: dark;\n }\n\n &--light {\n color-scheme: light;\n }\n\n font-family: var(--contribution-heatmap-font-family);\n font-size: var(--contribution-heatmap-label-size);\n line-height: 1;\n color: var(--contribution-heatmap-fg-muted);\n background: var(--contribution-heatmap-bg);\n border-radius: var(--contribution-heatmap-radius);\n padding: var(--contribution-heatmap-padding);\n box-shadow: 0 2px 8px var(--contribution-heatmap-shadow-color);\n border: 1px solid var(--contribution-heatmap-border);\n transition: var(--contribution-heatmap-transition);\n // An ordinary full-width block. It used to shrink-wrap its grid so the legend stayed\n // with it, but WebKit would not do that by any means tried - width: fit-content,\n // -webkit-fit-content, and CSS 2.1 inline-block all render full width on iOS while\n // Chrome shrink-wraps all three. The common factor is the scroll container child\n // (__scroll), though that was never confirmed. Rather than guess a fourth time, the\n // legend is aligned to the start instead, so a full-width card reads correctly\n // whatever the reason - and every browser now renders the same thing.\n //\n // border-box matters here: the library ships no reset, and under content-box the\n // padding is added on top of max-width and the card overflows its parent.\n box-sizing: border-box;\n max-width: 100%;\n\n // Only the grid scrolls - the padding, border and legend stay put.\n &__scroll {\n overflow-x: auto;\n overscroll-behavior-x: contain;\n scrollbar-width: thin;\n // overflow-x:auto makes overflow-y compute to auto too, which would clip the\n // :hover scale on the top and bottom rows. Give it room.\n padding-block: 3px;\n }\n\n // Intrinsic width: the columns are sized by the cells, never stretched to the\n // container. This is what makes --day-size mean something and lets the grid\n // scroll instead of squashing.\n &__table {\n width: max-content;\n border-collapse: separate;\n border-spacing: var(--contribution-heatmap-day-gap);\n }\n\n // Sun/Mon/... and the month names. The two classes swap roles between the\n // default and reversed layouts, so both need the same treatment.\n &__month-header,\n &__day-header,\n &__day-label,\n &__month-label {\n font-size: var(--contribution-heatmap-label-size);\n font-weight: 500;\n color: var(--contribution-heatmap-fg);\n white-space: nowrap;\n padding: 0;\n border: none;\n background: none;\n }\n\n &__month-header,\n &__day-header {\n text-align: left;\n padding-bottom: 4px;\n }\n\n // A month at the edge of the period can span a single week, and its own label is\n // wider than one column. Taking the text out of flow stops it setting the column\n // width - otherwise that one week stretches and opens a gap in the grid.\n &__month-header {\n position: relative;\n height: calc(var(--contribution-heatmap-label-size) + 6px);\n }\n\n &__month-header-text {\n position: absolute;\n left: 0;\n bottom: 4px;\n }\n\n // The trailing month is the one that can span a single week, and out of flow its\n // label would overhang the last column - widening the scroll area for the sake of\n // a few pixels of text. Anchor it to the right so it overhangs inwards instead.\n &__month-header--last &__month-header-text {\n left: auto;\n right: 0;\n }\n\n // Shrink-to-fit, so the label column keeps its own width instead of\n // collapsing to a day column. Pinned, so it survives a horizontal scroll -\n // the background has to be opaque because cells slide underneath.\n &__day-label,\n &__month-label {\n width: 1%;\n text-align: right;\n padding-right: 6px;\n position: sticky;\n left: 0;\n z-index: 1;\n background: var(--contribution-heatmap-bg);\n }\n\n &__day-label {\n vertical-align: middle;\n }\n\n // Sits against a rowSpan in the reversed layout.\n &__month-label {\n vertical-align: top;\n }\n\n // Hover effect for the entire component\n &:hover {\n box-shadow: 0 4px 16px var(--contribution-heatmap-shadow-color);\n }\n\n // Mobile responsiveness. --day-size deliberately does NOT shrink here: a year is\n // 53 weeks plus a label column, so the grid overflows a phone at every size it\n // could reasonably take (507px at 8px squares, against ~373px of usable width).\n // It scrolls either way, so shrinking only cost legibility and left a 9px tap\n // target on cells that are role=\"button\". Reclaiming the padding is free, and so\n // is the tighter gap - border-spacing is not part of a cell's hit area.\n @media (max-width: 768px) {\n --day-gap: 1px;\n --contribution-heatmap-padding: 15px;\n }\n\n @media (max-width: 480px) {\n --day-gap: 1px;\n --contribution-heatmap-padding: 10px;\n }\n\n // The reversed layout puts the day names above the columns, so no column can be\n // narrower than \"Wed\". Grow the squares to match instead of leaving every one of\n // them floating in a wider cell. Only seven columns, so it fits at any width.\n &--reverse {\n // Sized to clear the widest day header, which the monospace face below brings\n // down to 19.87px from the proportional \"Wed\" at 23.7px.\n --day-size: 20px;\n\n // The day names sit above their own column here, rather than being row labels,\n // so their differing widths show up as uneven spacing. Monospace makes all\n // seven identical - if a fallback face renders wider, every column widens by\n // the same amount, so the rhythm still can't go uneven.\n .contribution-heatmap__day-header {\n font-family: var(--contribution-heatmap-day-header-font-family);\n text-align: center;\n }\n\n // The column is only ever as narrow as its day-name header, and that width is\n // locale-dependent: \"Wed\" is three characters, French \"mer.\" is four. Fill the\n // cell rather than sitting at a fixed px size, so the square tracks whatever the\n // header needs and never leaves slack. --day-size above is the floor.\n .contribution-heatmap__day {\n height: auto;\n\n &::before {\n width: 100%;\n height: auto;\n aspect-ratio: 1;\n }\n }\n\n // On a phone the month grid is the only thing in the card, so let it fill the\n // width - 20px squares marooned in a full-width card look lost. The square\n // already fills its cell above, so widening the table is all that is needed.\n // Auto layout, so __month-label's width: 1% still collapses the Aug/Sep column;\n // table-layout: fixed would divide the width equally and hand the label a full\n // day column.\n @media (max-width: 480px) {\n .contribution-heatmap__table {\n width: 100%;\n }\n }\n }\n\n // Individual day. The cell is only a slot: the visible square is drawn by\n // ::before so that a column wider than --day-size - the reversed layout sizes\n // its columns to the Sun/Mon/... headers - can never stretch the square.\n &__day {\n width: var(--contribution-heatmap-day-size);\n min-width: var(--contribution-heatmap-day-size);\n height: var(--contribution-heatmap-day-size);\n padding: 0;\n border: none;\n cursor: pointer;\n position: relative;\n\n &::before {\n content: '';\n display: block;\n width: var(--contribution-heatmap-day-size);\n height: var(--contribution-heatmap-day-size);\n margin-inline: auto;\n box-sizing: border-box;\n border: 1px solid transparent;\n border-radius: var(--contribution-heatmap-day-radius);\n background-color: var(--contribution-heatmap-level-0);\n transition: var(--contribution-heatmap-transition);\n }\n\n // Contribution levels\n &--level-0:hover::before {\n background-color: var(--contribution-heatmap-level-1);\n border-color: var(--contribution-heatmap-level-2);\n }\n\n &--level-1::before {\n background-color: var(--contribution-heatmap-level-1);\n }\n\n &--level-1:hover::before {\n background-color: var(--contribution-heatmap-level-2);\n border-color: var(--contribution-heatmap-level-3);\n }\n\n &--level-2::before {\n background-color: var(--contribution-heatmap-level-2);\n }\n\n &--level-2:hover::before {\n background-color: var(--contribution-heatmap-level-3);\n border-color: var(--contribution-heatmap-level-4);\n }\n\n &--level-3::before {\n background-color: var(--contribution-heatmap-level-3);\n }\n\n &--level-3:hover::before {\n background-color: var(--contribution-heatmap-level-4);\n border-color: var(--contribution-heatmap-level-4);\n }\n\n &--level-4::before {\n background-color: var(--contribution-heatmap-level-4);\n }\n\n &--level-4:hover::before {\n filter: brightness(1.1);\n border-color: var(--contribution-heatmap-level-4);\n }\n\n // Hover effects\n &:hover {\n z-index: 10;\n }\n\n &:hover::before {\n transform: scale(1.2);\n box-shadow: var(--contribution-heatmap-tooltip-shadow);\n border-radius: calc(var(--contribution-heatmap-day-radius) + 1px);\n }\n\n // Padding days from groupByWeeks' whole-week fill: outside the period, so\n // they hold the column open but draw nothing. visibility rather than display\n // keeps their contribution to the column width.\n &--outside {\n cursor: default;\n\n &::before {\n visibility: hidden;\n }\n }\n\n // Focus styles for accessibility\n &:focus-visible {\n outline: none;\n }\n\n &:focus-visible::before {\n outline: 2px solid var(--contribution-heatmap-focus-ring);\n outline-offset: 2px;\n }\n }\n\n // Legend\n &__legend {\n display: flex;\n align-items: center;\n // Start-aligned, not centred: the card is as wide as its container while the grid\n // is only as wide as its content, so centring floats the legend away from the\n // squares it describes.\n justify-content: flex-start;\n gap: 4px;\n margin-top: 12px;\n flex-wrap: wrap;\n\n @media (max-width: 768px) {\n gap: 3px;\n margin-top: 8px;\n }\n }\n\n &__legend-text {\n color: var(--contribution-heatmap-fg-muted);\n font-size: var(--contribution-heatmap-label-size);\n font-weight: 500;\n margin: 0 4px;\n\n @media (max-width: 768px) {\n margin: 0 2px;\n }\n }\n\n &__legend-item {\n width: 12px;\n height: 12px;\n border-radius: var(--contribution-heatmap-day-radius);\n cursor: help;\n transition: var(--contribution-heatmap-transition);\n border: 1px solid var(--contribution-heatmap-border);\n\n @media (max-width: 768px) {\n width: 10px;\n height: 10px;\n }\n\n &:hover {\n transform: scale(1.2);\n border-color: var(--contribution-heatmap-fg-muted);\n }\n\n &--level-0 {\n background-color: var(--contribution-heatmap-level-0);\n }\n &--level-1 {\n background-color: var(--contribution-heatmap-level-1);\n }\n &--level-2 {\n background-color: var(--contribution-heatmap-level-2);\n }\n &--level-3 {\n background-color: var(--contribution-heatmap-level-3);\n }\n &--level-4 {\n background-color: var(--contribution-heatmap-level-4);\n }\n }\n}\n\n// Animation for initial load\n@keyframes fadeInUp {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n// A year is 371 staggered cells plus the card itself; none of it runs for users who\n// have asked their OS for less motion. The cells have no `from` state outside the\n// animation, so with it off they simply appear in place.\n@media (prefers-reduced-motion: no-preference) {\n .contribution-heatmap {\n animation: fadeInUp 0.6s ease-out;\n\n // --animation-delay is set inline per cell and inherits into the pseudo-element.\n &__day::before {\n animation: fadeInUp 0.3s ease-out;\n animation-delay: var(--animation-delay, 0s);\n animation-fill-mode: both;\n }\n }\n}\n\n// Utilities for different themes. They still write the deprecated names in 0.4.0: moved\n// to the public ones, they would start applying in dark mode, where today the\n// dark-tokens mixin (higher specificity) replaces them.\n.contribution-heatmap {\n // Ocean theme\n &--ocean {\n --color-level-0: #e6f3ff;\n --color-level-1: #b3daff;\n --color-level-2: #66b3ff;\n --color-level-3: #1a8cff;\n --color-level-4: #0066cc;\n }\n\n // Sunset theme\n &--sunset {\n --color-level-0: #fff2e6;\n --color-level-1: #ffcc99;\n --color-level-2: #ff9933;\n --color-level-3: #ff6600;\n --color-level-4: #cc3300;\n }\n\n // Purple theme\n &--purple {\n --color-level-0: #f3e6ff;\n --color-level-1: #d9b3ff;\n --color-level-2: #b366ff;\n --color-level-3: #8a1aff;\n --color-level-4: #6600cc;\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -186,7 +186,7 @@ function ContributionHeatmap({
|
|
|
186
186
|
children: [
|
|
187
187
|
/* @__PURE__ */ jsx("div", { className: "contribution-heatmap__scroll", children: /* @__PURE__ */ jsx("table", { className: "contribution-heatmap__table", children: isReverse ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
188
188
|
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
189
|
-
/* @__PURE__ */ jsx("
|
|
189
|
+
/* @__PURE__ */ jsx("td", { className: "contribution-heatmap__month-header" }),
|
|
190
190
|
dayNames2.map((dayName, dayIndex) => /* @__PURE__ */ jsx("th", { className: "contribution-heatmap__day-header", children: dayName }, dayIndex))
|
|
191
191
|
] }) }),
|
|
192
192
|
/* @__PURE__ */ jsx("tbody", { children: weeks.map((week, weekIndex) => {
|
|
@@ -216,7 +216,7 @@ function ContributionHeatmap({
|
|
|
216
216
|
}) })
|
|
217
217
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
218
218
|
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
219
|
-
/* @__PURE__ */ jsx("
|
|
219
|
+
/* @__PURE__ */ jsx("td", { className: "contribution-heatmap__day-header" }),
|
|
220
220
|
months.map((month, index) => /* @__PURE__ */ jsx(
|
|
221
221
|
"th",
|
|
222
222
|
{
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shared/models.tsx","../src/shared/formatTooltip.tsx","../src/ContributionHeatmap/getMonthsForHeader.ts","../src/shared/intl.ts","../src/shared/Legend.tsx","../src/ContributionHeatmap/index.tsx","../src/shared/groupByWeeks.ts","../src/mocks/createRealisticMockedCount.ts","../src/mocks/index.tsx"],"names":["monthNames","jsx","dayNames","jsxs"],"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\n// The strings Intl cannot derive from a locale. Day and month names are not here:\n// those come from the locale itself, via src/shared/intl.ts.\ninterface HeatmapLabels {\n less?: string;\n more?: string;\n level?: (level: number) => string;\n noContributions?: string;\n contributions?: (count: number) => string;\n}\n\nconst defaultLabels: Required<HeatmapLabels> = {\n less: 'Less',\n more: 'More',\n level: (level) => `Level ${level}`,\n noContributions: 'No contributions',\n contributions: (count) => `${count} contribution${count !== 1 ? 's' : ''}`,\n};\n\nconst DEFAULT_LOCALE = 'en-US';\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\n// Local midnight, `months` whole months away, with the day-of-month clamped to the\n// target month's length: Date would otherwise roll Feb 31 forward into March.\nfunction shiftMonthsClamped(date: Date, months: number): Date {\n const year = date.getFullYear();\n const month = date.getMonth() + months;\n const daysInTarget = new Date(year, month + 1, 0).getDate();\n return new Date(year, month, Math.min(date.getDate(), daysInTarget));\n}\n\nconst startOfToday = (): Date => {\n const now = new Date();\n return new Date(now.getFullYear(), now.getMonth(), now.getDate());\n};\n\n// Both helpers span back to the day after the same date one unit ago, so today is\n// the last day and the window is exactly one year / one month long.\nfunction getLastYearPeriod(): Period {\n const end = startOfToday();\n const start = shiftMonthsClamped(end, -12);\n start.setDate(start.getDate() + 1);\n return { start, end };\n}\n\nfunction getLastMonthPeriod(): Period {\n const end = startOfToday();\n const start = shiftMonthsClamped(end, -1);\n start.setDate(start.getDate() + 1);\n return { start, end };\n}\n\n// The library reads every Date as a calendar day in the local time zone, and these two\n// are the only conversions between Date and the YYYY-MM-DD strings the data carries.\n// Neither goes through toISOString() or `new Date(string)`: both of those are UTC, and\n// mixing them with local Dates shifts the first and last day of a period by one\n// anywhere outside Greenwich.\nconst pad = (n: number): string => String(n).padStart(2, '0');\n\nconst createDateString = (date: Date): string =>\n `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;\n\nconst parseDateString = (dateString: string): Date => {\n const [year, month, day] = dateString.split('-').map(Number);\n return new Date(year, month - 1, day);\n};\n\nexport type { ContributionData, Week, Period, Theme, HeatmapLabels };\nexport {\n monthNames,\n dayNames,\n defaultLabels,\n DEFAULT_LOCALE,\n createDateString,\n parseDateString,\n getLastYearPeriod,\n getLastMonthPeriod,\n};\n","import {\n createDateString,\n parseDateString,\n defaultLabels,\n DEFAULT_LOCALE,\n type ContributionData,\n type HeatmapLabels,\n type Period,\n} from '@/shared/models';\n\n// Compares whole days, in the same YYYY-MM-DD form the contributions carry.\n// Period boundaries are Date objects that keep a time of day, so comparing them\n// directly against a date-only value put the first and last day of the period\n// out of range. ISO date strings also sort correctly, so > and < still work.\nfunction isInRange(date: string, { start, end }: Period): boolean {\n return date >= createDateString(start) && date <= createDateString(end);\n}\n\ninterface FormatTooltipOptions {\n locale?: string;\n labels?: HeatmapLabels;\n}\n\nconst formatTooltip = (\n contribution: ContributionData,\n { start, end }: Period,\n { locale = DEFAULT_LOCALE, labels }: FormatTooltipOptions = {},\n): string => {\n const text = { ...defaultLabels, ...labels };\n // parseDateString gives local midnight, so formatting in the local zone names the\n // right day. `new Date(string)` would parse as UTC midnight, which is the previous\n // day anywhere west of Greenwich.\n const formattedDate = parseDateString(contribution.date).toLocaleDateString(locale, {\n weekday: 'short',\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n\n if (!isInRange(contribution.date, { start, end }) || contribution.count === 0) {\n return `${formattedDate}: ${text.noContributions}`;\n }\n\n return `${formattedDate}: ${text.contributions(contribution.count)}`;\n};\n\nexport { formatTooltip, isInRange };\nexport type { FormatTooltipOptions };\n","import { isInRange } from '@/shared/formatTooltip';\nimport {\n monthNames as defaultMonthNames,\n parseDateString,\n type Period,\n type Week,\n} from '@/shared/models';\n\nfunction getMonthsForHeader({\n weeks,\n period,\n monthNames = defaultMonthNames,\n}: {\n weeks: Week[];\n period: Period;\n // Locale-derived; falls back to the exported English constants.\n monthNames?: readonly string[];\n}): {\n name: string;\n span: number;\n start: number;\n}[] {\n const months: { name: string; span: number; start: number }[] = [];\n let currentMonth = -1;\n let currentSpan = 0;\n\n weeks.forEach((week, weekIndex) => {\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\n for (const day of week) {\n if (isInRange(day.date, period)) {\n monthToUse = parseDateString(day.date).getMonth();\n break;\n }\n }\n\n // If no day in the week is in our actual range, use the middle of the week\n // (index 3 - which weekday that is depends on weekStartsOn)\n if (monthToUse === -1) {\n const middleDay = week[3];\n monthToUse = parseDateString(middleDay.date).getMonth();\n }\n\n if (monthToUse !== currentMonth) {\n if (currentMonth !== -1) {\n months.push({ name: monthNames[currentMonth], span: currentSpan, start: weekIndex - 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, start: weeks.length - currentSpan });\n }\n\n return months;\n}\n\nexport { getMonthsForHeader };\n","// Day and month names derived from a locale, so the component ships no translations.\n//\n// timeZone is pinned to UTC throughout: the reference dates below are built with\n// Date.UTC, and formatting them in a local zone would shift them across a day boundary\n// in negative offsets and hand back the wrong name.\n\n// 7 Jan 2024 is a Sunday, so this week runs Sunday -> Saturday.\nconst REFERENCE_WEEK_START = Date.UTC(2024, 0, 7);\nconst DAYS_IN_WEEK = 7;\n\nfunction getDayNames(locale: string, weekStartsOn: number = 0): string[] {\n const format = new Intl.DateTimeFormat(locale, {\n weekday: 'short',\n timeZone: 'UTC',\n });\n\n return Array.from({ length: DAYS_IN_WEEK }, (_, index) => {\n const dayOfWeek = (weekStartsOn + index) % DAYS_IN_WEEK;\n return format.format(new Date(REFERENCE_WEEK_START + dayOfWeek * 86400000));\n });\n}\n\nfunction getMonthNames(locale: string): string[] {\n const format = new Intl.DateTimeFormat(locale, {\n month: 'short',\n timeZone: 'UTC',\n });\n\n // The 15th avoids any month-length edge case.\n return Array.from({ length: 12 }, (_, month) =>\n format.format(new Date(Date.UTC(2024, month, 15))),\n );\n}\n\nexport { getDayNames, getMonthNames };\n","import { defaultLabels, type HeatmapLabels } from '@/shared/models';\n\nfunction Legend({ labels }: { labels?: HeatmapLabels }): React.ReactNode {\n const text = { ...defaultLabels, ...labels };\n\n return (\n <div className=\"contribution-heatmap__legend\">\n <span className=\"contribution-heatmap__legend-text\">{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={text.level(level)}\n ></div>\n ))}\n <span className=\"contribution-heatmap__legend-text\">{text.more}</span>\n </div>\n );\n}\n\nexport { Legend };\n","import './index.scss';\nimport type {\n ContributionData,\n HeatmapLabels,\n Period,\n Week as WeekType,\n} from '../shared/models';\nimport { getMonthsForHeader } from './getMonthsForHeader';\nimport { formatTooltip, isInRange } from '@/shared/formatTooltip';\nimport { DEFAULT_LOCALE, parseDateString } from '@/shared/models';\nimport { getDayNames, getMonthNames } from '@/shared/intl';\nimport { Legend } from '@/shared/Legend';\n\n\ninterface DayCellProps {\n contribution: ContributionData;\n period: Period;\n locale: string;\n labels?: HeatmapLabels;\n // Position in the grid, used to stagger the load animation.\n delayIndex: number;\n}\n\n// groupByWeeks pads every week out to Sun-Sat, so the first and last week carry days\n// that fall outside the period. They keep their slot - the columns depend on seven\n// cells per row - but render no square and stay out of the a11y tree.\nfunction DayCell({ contribution, period, locale, labels, delayIndex }: DayCellProps) {\n const inRange = isInRange(contribution.date, period);\n const tooltip = formatTooltip(contribution, period, { locale, labels });\n\n return (\n <td\n className={[\n 'contribution-heatmap__day',\n `contribution-heatmap__day--level-${contribution.level}`,\n inRange ? '' : 'contribution-heatmap__day--outside',\n ]\n .filter(Boolean)\n .join(' ')}\n title={inRange ? tooltip : undefined}\n aria-label={inRange ? tooltip : undefined}\n role={inRange ? 'button' : undefined}\n tabIndex={inRange ? 0 : undefined}\n data-count={contribution.count}\n data-date={contribution.date}\n style={{ '--animation-delay': `${delayIndex * 0.005}s` } as React.CSSProperties}\n ></td>\n );\n}\n\ninterface ContributionHeatmapProps {\n data: { contribution: ContributionData[]; period: Period; weeks: WeekType[] };\n className?: string;\n isReverse?: boolean;\n // Drives day names, month names and the tooltip date through Intl.\n locale?: string;\n // The handful of strings Intl cannot derive.\n labels?: HeatmapLabels;\n}\n\nfunction ContributionHeatmap({\n data: { period, weeks },\n className = '',\n isReverse = false,\n locale = DEFAULT_LOCALE,\n labels,\n}: ContributionHeatmapProps) {\n // Read the week start off the data rather than taking a prop: groupByWeeks already\n // decided it, and a prop could disagree with the weeks it was handed.\n const weekStartsOn = weeks.length ? parseDateString(weeks[0][0].date).getDay() : 0;\n const dayNames = getDayNames(locale, weekStartsOn);\n const months = getMonthsForHeader({ weeks, period, monthNames: getMonthNames(locale) });\n\n return (\n <div\n className={`contribution-heatmap${isReverse ? ' contribution-heatmap--reverse' : ''} ${className}`}\n >\n {/* Only the grid scrolls; the padding and the legend stay put. */}\n <div className=\"contribution-heatmap__scroll\">\n <table className=\"contribution-heatmap__table\">\n {isReverse ? (\n <>\n <thead>\n <tr>\n <th className=\"contribution-heatmap__month-header\"></th>\n {dayNames.map((dayName, dayIndex) => (\n <th key={dayIndex} className=\"contribution-heatmap__day-header\">\n {dayName}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {weeks.map((week, weekIndex) => {\n // Find month info for this week\n const month = months.find(m => weekIndex === m.start);\n const showMonthLabel = !!month;\n return (\n <tr key={weekIndex}>\n {showMonthLabel && (\n <td\n className=\"contribution-heatmap__month-label\"\n rowSpan={month.span}\n >\n {month.name}\n </td>\n )}\n {week.map((contribution, dayIndex) => (\n <DayCell\n key={dayIndex}\n contribution={contribution}\n period={period}\n locale={locale}\n labels={labels}\n delayIndex={weekIndex * 7 + dayIndex}\n />\n ))}\n </tr>\n );\n })}\n </tbody>\n </>\n ) : (\n <>\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 index === months.length - 1\n ? ' contribution-heatmap__month-header--last'\n : ''\n }`}\n colSpan={month.span}\n >\n <span className=\"contribution-heatmap__month-header-text\">\n {month.name}\n </span>\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 {dayName}\n </td>\n {weeks.map((week, weekIndex) => {\n const contribution = week[dayIndex];\n return (\n <DayCell\n key={weekIndex}\n contribution={contribution}\n period={period}\n locale={locale}\n labels={labels}\n delayIndex={weekIndex * 7 + dayIndex}\n />\n );\n })}\n </tr>\n ))}\n </tbody>\n </>\n )}\n </table>\n </div>\n <Legend labels={labels} />\n </div>\n );\n}\n\nexport { ContributionHeatmap };\n","import {\n createDateString,\n parseDateString,\n type ContributionData,\n type Week,\n} 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\n// Days from weekStartsOn back to the given date's weekday, e.g. with a Monday start\n// (1) a Sunday (0) is six days into the week, not minus one.\nconst daysIntoWeek = (date: Date, weekStartsOn: number): number =>\n (date.getDay() - weekStartsOn + 7) % 7;\n\nconst getFirstDayOfWeek = (firstDate: Date, weekStartsOn: number): Date => {\n const startOfWeek = new Date(firstDate);\n startOfWeek.setDate(firstDate.getDate() - daysIntoWeek(firstDate, weekStartsOn));\n return startOfWeek;\n};\n\nconst getLastDayOfWeek = (lastDate: Date, weekStartsOn: number): Date => {\n const endOfWeek = new Date(lastDate);\n endOfWeek.setDate(lastDate.getDate() + (6 - daysIntoWeek(lastDate, weekStartsOn)));\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\ninterface GroupByWeeksOptions {\n // 0 = Sunday (the default, and the US/GitHub convention), 1 = Monday, and so on.\n weekStartsOn?: number;\n}\n\nconst groupByWeeks = (\n contributions: ContributionData[],\n { weekStartsOn = 0 }: GroupByWeeksOptions = {},\n): Week[] => {\n const weeks: Week[] = [];\n const contributionMap = createContributionMap(contributions);\n\n const firstDay = getFirstDayOfWeek(parseDateString(contributions[0].date), weekStartsOn);\n const lastDate = getLastDayOfWeek(\n parseDateString(contributions[contributions.length - 1].date),\n weekStartsOn,\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 };\nexport type { GroupByWeeksOptions };\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 { createRealisticMockedCount } from './createRealisticMockedCount';\n\nconst getRandomCount = () => Math.floor(Math.random() * 15);\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\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/shared/models.tsx","../src/shared/formatTooltip.tsx","../src/ContributionHeatmap/getMonthsForHeader.ts","../src/shared/intl.ts","../src/shared/Legend.tsx","../src/ContributionHeatmap/index.tsx","../src/shared/groupByWeeks.ts","../src/mocks/createRealisticMockedCount.ts","../src/mocks/index.tsx"],"names":["monthNames","jsx","dayNames","jsxs"],"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\n// The strings Intl cannot derive from a locale. Day and month names are not here:\n// those come from the locale itself, via src/shared/intl.ts.\ninterface HeatmapLabels {\n less?: string;\n more?: string;\n level?: (level: number) => string;\n noContributions?: string;\n contributions?: (count: number) => string;\n}\n\nconst defaultLabels: Required<HeatmapLabels> = {\n less: 'Less',\n more: 'More',\n level: (level) => `Level ${level}`,\n noContributions: 'No contributions',\n contributions: (count) => `${count} contribution${count !== 1 ? 's' : ''}`,\n};\n\nconst DEFAULT_LOCALE = 'en-US';\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\n// Local midnight, `months` whole months away, with the day-of-month clamped to the\n// target month's length: Date would otherwise roll Feb 31 forward into March.\nfunction shiftMonthsClamped(date: Date, months: number): Date {\n const year = date.getFullYear();\n const month = date.getMonth() + months;\n const daysInTarget = new Date(year, month + 1, 0).getDate();\n return new Date(year, month, Math.min(date.getDate(), daysInTarget));\n}\n\nconst startOfToday = (): Date => {\n const now = new Date();\n return new Date(now.getFullYear(), now.getMonth(), now.getDate());\n};\n\n// Both helpers span back to the day after the same date one unit ago, so today is\n// the last day and the window is exactly one year / one month long.\nfunction getLastYearPeriod(): Period {\n const end = startOfToday();\n const start = shiftMonthsClamped(end, -12);\n start.setDate(start.getDate() + 1);\n return { start, end };\n}\n\nfunction getLastMonthPeriod(): Period {\n const end = startOfToday();\n const start = shiftMonthsClamped(end, -1);\n start.setDate(start.getDate() + 1);\n return { start, end };\n}\n\n// The library reads every Date as a calendar day in the local time zone, and these two\n// are the only conversions between Date and the YYYY-MM-DD strings the data carries.\n// Neither goes through toISOString() or `new Date(string)`: both of those are UTC, and\n// mixing them with local Dates shifts the first and last day of a period by one\n// anywhere outside Greenwich.\nconst pad = (n: number): string => String(n).padStart(2, '0');\n\nconst createDateString = (date: Date): string =>\n `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;\n\nconst parseDateString = (dateString: string): Date => {\n const [year, month, day] = dateString.split('-').map(Number);\n return new Date(year, month - 1, day);\n};\n\nexport type { ContributionData, Week, Period, Theme, HeatmapLabels };\nexport {\n monthNames,\n dayNames,\n defaultLabels,\n DEFAULT_LOCALE,\n createDateString,\n parseDateString,\n getLastYearPeriod,\n getLastMonthPeriod,\n};\n","import {\n createDateString,\n parseDateString,\n defaultLabels,\n DEFAULT_LOCALE,\n type ContributionData,\n type HeatmapLabels,\n type Period,\n} from '@/shared/models';\n\n// Compares whole days, in the same YYYY-MM-DD form the contributions carry.\n// Period boundaries are Date objects that keep a time of day, so comparing them\n// directly against a date-only value put the first and last day of the period\n// out of range. ISO date strings also sort correctly, so > and < still work.\nfunction isInRange(date: string, { start, end }: Period): boolean {\n return date >= createDateString(start) && date <= createDateString(end);\n}\n\ninterface FormatTooltipOptions {\n locale?: string;\n labels?: HeatmapLabels;\n}\n\nconst formatTooltip = (\n contribution: ContributionData,\n { start, end }: Period,\n { locale = DEFAULT_LOCALE, labels }: FormatTooltipOptions = {},\n): string => {\n const text = { ...defaultLabels, ...labels };\n // parseDateString gives local midnight, so formatting in the local zone names the\n // right day. `new Date(string)` would parse as UTC midnight, which is the previous\n // day anywhere west of Greenwich.\n const formattedDate = parseDateString(contribution.date).toLocaleDateString(locale, {\n weekday: 'short',\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n\n if (!isInRange(contribution.date, { start, end }) || contribution.count === 0) {\n return `${formattedDate}: ${text.noContributions}`;\n }\n\n return `${formattedDate}: ${text.contributions(contribution.count)}`;\n};\n\nexport { formatTooltip, isInRange };\nexport type { FormatTooltipOptions };\n","import { isInRange } from '@/shared/formatTooltip';\nimport {\n monthNames as defaultMonthNames,\n parseDateString,\n type Period,\n type Week,\n} from '@/shared/models';\n\nfunction getMonthsForHeader({\n weeks,\n period,\n monthNames = defaultMonthNames,\n}: {\n weeks: Week[];\n period: Period;\n // Locale-derived; falls back to the exported English constants.\n monthNames?: readonly string[];\n}): {\n name: string;\n span: number;\n start: number;\n}[] {\n const months: { name: string; span: number; start: number }[] = [];\n let currentMonth = -1;\n let currentSpan = 0;\n\n weeks.forEach((week, weekIndex) => {\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\n for (const day of week) {\n if (isInRange(day.date, period)) {\n monthToUse = parseDateString(day.date).getMonth();\n break;\n }\n }\n\n // If no day in the week is in our actual range, use the middle of the week\n // (index 3 - which weekday that is depends on weekStartsOn)\n if (monthToUse === -1) {\n const middleDay = week[3];\n monthToUse = parseDateString(middleDay.date).getMonth();\n }\n\n if (monthToUse !== currentMonth) {\n if (currentMonth !== -1) {\n months.push({ name: monthNames[currentMonth], span: currentSpan, start: weekIndex - 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, start: weeks.length - currentSpan });\n }\n\n return months;\n}\n\nexport { getMonthsForHeader };\n","// Day and month names derived from a locale, so the component ships no translations.\n//\n// timeZone is pinned to UTC throughout: the reference dates below are built with\n// Date.UTC, and formatting them in a local zone would shift them across a day boundary\n// in negative offsets and hand back the wrong name.\n\n// 7 Jan 2024 is a Sunday, so this week runs Sunday -> Saturday.\nconst REFERENCE_WEEK_START = Date.UTC(2024, 0, 7);\nconst DAYS_IN_WEEK = 7;\n\nfunction getDayNames(locale: string, weekStartsOn: number = 0): string[] {\n const format = new Intl.DateTimeFormat(locale, {\n weekday: 'short',\n timeZone: 'UTC',\n });\n\n return Array.from({ length: DAYS_IN_WEEK }, (_, index) => {\n const dayOfWeek = (weekStartsOn + index) % DAYS_IN_WEEK;\n return format.format(new Date(REFERENCE_WEEK_START + dayOfWeek * 86400000));\n });\n}\n\nfunction getMonthNames(locale: string): string[] {\n const format = new Intl.DateTimeFormat(locale, {\n month: 'short',\n timeZone: 'UTC',\n });\n\n // The 15th avoids any month-length edge case.\n return Array.from({ length: 12 }, (_, month) =>\n format.format(new Date(Date.UTC(2024, month, 15))),\n );\n}\n\nexport { getDayNames, getMonthNames };\n","import { defaultLabels, type HeatmapLabels } from '@/shared/models';\n\nfunction Legend({ labels }: { labels?: HeatmapLabels }): React.ReactNode {\n const text = { ...defaultLabels, ...labels };\n\n return (\n <div className=\"contribution-heatmap__legend\">\n <span className=\"contribution-heatmap__legend-text\">{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={text.level(level)}\n ></div>\n ))}\n <span className=\"contribution-heatmap__legend-text\">{text.more}</span>\n </div>\n );\n}\n\nexport { Legend };\n","import './index.scss';\nimport type {\n ContributionData,\n HeatmapLabels,\n Period,\n Week as WeekType,\n} from '../shared/models';\nimport { getMonthsForHeader } from './getMonthsForHeader';\nimport { formatTooltip, isInRange } from '@/shared/formatTooltip';\nimport { DEFAULT_LOCALE, parseDateString } from '@/shared/models';\nimport { getDayNames, getMonthNames } from '@/shared/intl';\nimport { Legend } from '@/shared/Legend';\n\n\ninterface DayCellProps {\n contribution: ContributionData;\n period: Period;\n locale: string;\n labels?: HeatmapLabels;\n // Position in the grid, used to stagger the load animation.\n delayIndex: number;\n}\n\n// groupByWeeks pads every week out to Sun-Sat, so the first and last week carry days\n// that fall outside the period. They keep their slot - the columns depend on seven\n// cells per row - but render no square and stay out of the a11y tree.\nfunction DayCell({ contribution, period, locale, labels, delayIndex }: DayCellProps) {\n const inRange = isInRange(contribution.date, period);\n const tooltip = formatTooltip(contribution, period, { locale, labels });\n\n return (\n <td\n className={[\n 'contribution-heatmap__day',\n `contribution-heatmap__day--level-${contribution.level}`,\n inRange ? '' : 'contribution-heatmap__day--outside',\n ]\n .filter(Boolean)\n .join(' ')}\n title={inRange ? tooltip : undefined}\n aria-label={inRange ? tooltip : undefined}\n role={inRange ? 'button' : undefined}\n tabIndex={inRange ? 0 : undefined}\n data-count={contribution.count}\n data-date={contribution.date}\n style={{ '--animation-delay': `${delayIndex * 0.005}s` } as React.CSSProperties}\n ></td>\n );\n}\n\ninterface ContributionHeatmapProps {\n data: { contribution: ContributionData[]; period: Period; weeks: WeekType[] };\n className?: string;\n isReverse?: boolean;\n // Drives day names, month names and the tooltip date through Intl.\n locale?: string;\n // The handful of strings Intl cannot derive.\n labels?: HeatmapLabels;\n}\n\nfunction ContributionHeatmap({\n data: { period, weeks },\n className = '',\n isReverse = false,\n locale = DEFAULT_LOCALE,\n labels,\n}: ContributionHeatmapProps) {\n // Read the week start off the data rather than taking a prop: groupByWeeks already\n // decided it, and a prop could disagree with the weeks it was handed.\n const weekStartsOn = weeks.length ? parseDateString(weeks[0][0].date).getDay() : 0;\n const dayNames = getDayNames(locale, weekStartsOn);\n const months = getMonthsForHeader({ weeks, period, monthNames: getMonthNames(locale) });\n\n return (\n <div\n className={`contribution-heatmap${isReverse ? ' contribution-heatmap--reverse' : ''} ${className}`}\n >\n {/* Only the grid scrolls; the padding and the legend stay put. */}\n <div className=\"contribution-heatmap__scroll\">\n <table className=\"contribution-heatmap__table\">\n {isReverse ? (\n <>\n <thead>\n <tr>\n {/* The corner above the label column heads nothing, so it is a td: an empty th\n is a header with no text, which axe reports and a screen reader announces. */}\n <td className=\"contribution-heatmap__month-header\"></td>\n {dayNames.map((dayName, dayIndex) => (\n <th key={dayIndex} className=\"contribution-heatmap__day-header\">\n {dayName}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {weeks.map((week, weekIndex) => {\n // Find month info for this week\n const month = months.find(m => weekIndex === m.start);\n const showMonthLabel = !!month;\n return (\n <tr key={weekIndex}>\n {showMonthLabel && (\n <td\n className=\"contribution-heatmap__month-label\"\n rowSpan={month.span}\n >\n {month.name}\n </td>\n )}\n {week.map((contribution, dayIndex) => (\n <DayCell\n key={dayIndex}\n contribution={contribution}\n period={period}\n locale={locale}\n labels={labels}\n delayIndex={weekIndex * 7 + dayIndex}\n />\n ))}\n </tr>\n );\n })}\n </tbody>\n </>\n ) : (\n <>\n <thead>\n <tr>\n {/* The corner above the label column heads nothing, so it is a td: an empty th\n is a header with no text, which axe reports and a screen reader announces. */}\n <td className=\"contribution-heatmap__day-header\"></td>\n {months.map((month, index) => (\n <th\n key={index}\n className={`contribution-heatmap__month-header${\n index === months.length - 1\n ? ' contribution-heatmap__month-header--last'\n : ''\n }`}\n colSpan={month.span}\n >\n <span className=\"contribution-heatmap__month-header-text\">\n {month.name}\n </span>\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 {dayName}\n </td>\n {weeks.map((week, weekIndex) => {\n const contribution = week[dayIndex];\n return (\n <DayCell\n key={weekIndex}\n contribution={contribution}\n period={period}\n locale={locale}\n labels={labels}\n delayIndex={weekIndex * 7 + dayIndex}\n />\n );\n })}\n </tr>\n ))}\n </tbody>\n </>\n )}\n </table>\n </div>\n <Legend labels={labels} />\n </div>\n );\n}\n\nexport { ContributionHeatmap };\n","import {\n createDateString,\n parseDateString,\n type ContributionData,\n type Week,\n} 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\n// Days from weekStartsOn back to the given date's weekday, e.g. with a Monday start\n// (1) a Sunday (0) is six days into the week, not minus one.\nconst daysIntoWeek = (date: Date, weekStartsOn: number): number =>\n (date.getDay() - weekStartsOn + 7) % 7;\n\nconst getFirstDayOfWeek = (firstDate: Date, weekStartsOn: number): Date => {\n const startOfWeek = new Date(firstDate);\n startOfWeek.setDate(firstDate.getDate() - daysIntoWeek(firstDate, weekStartsOn));\n return startOfWeek;\n};\n\nconst getLastDayOfWeek = (lastDate: Date, weekStartsOn: number): Date => {\n const endOfWeek = new Date(lastDate);\n endOfWeek.setDate(lastDate.getDate() + (6 - daysIntoWeek(lastDate, weekStartsOn)));\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\ninterface GroupByWeeksOptions {\n // 0 = Sunday (the default, and the US/GitHub convention), 1 = Monday, and so on.\n weekStartsOn?: number;\n}\n\nconst groupByWeeks = (\n contributions: ContributionData[],\n { weekStartsOn = 0 }: GroupByWeeksOptions = {},\n): Week[] => {\n const weeks: Week[] = [];\n const contributionMap = createContributionMap(contributions);\n\n const firstDay = getFirstDayOfWeek(parseDateString(contributions[0].date), weekStartsOn);\n const lastDate = getLastDayOfWeek(\n parseDateString(contributions[contributions.length - 1].date),\n weekStartsOn,\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 };\nexport type { GroupByWeeksOptions };\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 { createRealisticMockedCount } from './createRealisticMockedCount';\n\nconst getRandomCount = () => Math.floor(Math.random() * 15);\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\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"]}
|