Skip to content

Commit 658b2f4

Browse files
committed
fix(npm-stats): baseline series visibility, color picker layout, drag handler
- align baseline chip layout with non-baseline chips so the toggle-visibility button and EyeOff indicator are always present - portal the color picker popover to document.body so mounting it no longer reflows the chip row inside the Card's space-y stack - include baseline series in the chart when visible (renders as a flat 1.0 reference line) and default them to visible, both in the popular comparison and when a user promotes a series to baseline - bump @tanstack/dom-vite to 0.1.0-alpha.7 so react-colorful's drag handler gets the nativeEvent alias it needs on mousedown - drop unused useCallback/useDebouncedCallback imports in FilterComponents
1 parent 21bff8e commit 658b2f4

7 files changed

Lines changed: 70 additions & 55 deletions

File tree

src/components/FilterComponents.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react'
2-
import { useState, useRef, useEffect, useCallback } from 'react'
2+
import { useState, useRef, useEffect } from 'react'
33
import {
44
Table,
55
List,
@@ -9,7 +9,7 @@ import {
99
RotateCcw,
1010
SlidersHorizontal,
1111
} from 'lucide-react'
12-
import { useDebouncedCallback, useDebouncer } from '@tanstack/react-pacer'
12+
import { useDebouncer } from '@tanstack/react-pacer'
1313
import { twMerge } from 'tailwind-merge'
1414
type FeedViewMode = 'table' | 'timeline'
1515

src/components/npm-stats/ColorPickerPopover.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as React from 'react'
2+
import { createPortal } from 'react-dom'
23
import { HexColorPicker } from 'react-colorful'
34

45
export interface ColorPickerPopoverProps {
@@ -22,7 +23,9 @@ export function ColorPickerPopover({
2223
onReset,
2324
onClose,
2425
}: ColorPickerPopoverProps) {
25-
return (
26+
if (typeof document === 'undefined') return null
27+
28+
return createPortal(
2629
<div
2730
className="fixed z-50 bg-white dark:bg-gray-800 rounded-lg shadow-lg p-2"
2831
style={{
@@ -54,6 +57,7 @@ export function ColorPickerPopover({
5457
Done
5558
</button>
5659
</div>
57-
</div>
60+
</div>,
61+
document.body,
5862
)
5963
}

src/components/npm-stats/NPMStatsChart.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,12 +184,14 @@ export function NPMStatsChart({
184184
}
185185
})
186186

187-
// Filter out any top-level hidden packages
187+
// Filter out any top-level hidden packages. Baseline series stay in the
188+
// plot when visible — they render as a flat reference line at 1.0 (every
189+
// point divided by itself) so users can see the baseline alongside the
190+
// normalized series.
188191
const filteredPackageData = correctedPackageData.filter((_, index) => {
189192
const packageGroupWithHidden = packages[index]
190193
const isHidden = packageGroupWithHidden?.packages[0]?.hidden
191-
const isBaseline = packageGroupWithHidden?.baseline
192-
return !isBaseline && !isHidden
194+
return !isHidden
193195
})
194196

195197
const plotData = filteredPackageData.flatMap((d) => d.downloads)

src/components/npm-stats/PackagePills.tsx

Lines changed: 33 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -64,46 +64,41 @@ export function PackagePill({
6464
>
6565
<div className="flex items-center gap-1 w-full">
6666
{packageGroup.baseline ? (
67-
<>
68-
<Tooltip content="Remove baseline">
69-
<button
70-
onClick={() => onBaselineChange?.(mainPackage.name)}
71-
className="hover:text-blue-500"
72-
>
73-
<Pin className="w-3 h-3 sm:w-4 sm:h-4 text-blue-500" />
74-
</button>
75-
</Tooltip>
76-
<span>{mainPackage.name}</span>
77-
</>
67+
<Tooltip content="Remove baseline">
68+
<button
69+
onClick={() => onBaselineChange?.(mainPackage.name)}
70+
className="hover:text-blue-500"
71+
>
72+
<Pin className="w-3 h-3 sm:w-4 sm:h-4 text-blue-500" />
73+
</button>
74+
</Tooltip>
7875
) : (
79-
<>
80-
<Tooltip content="Change color">
81-
<button
82-
onClick={(e) => onColorClick(mainPackage.name, e)}
83-
className="hover:opacity-80"
84-
>
85-
<div
86-
className="w-3 h-3 sm:w-4 sm:h-4 rounded"
87-
style={{ backgroundColor: color }}
88-
/>
89-
</button>
90-
</Tooltip>
91-
<Tooltip content="Toggle package visibility">
92-
<button
93-
onClick={() => onToggleVisibility(index, mainPackage.name)}
94-
className={twMerge(
95-
'hover:text-blue-500 flex items-center gap-1',
96-
mainPackage.hidden ? 'opacity-50' : '',
97-
)}
98-
>
99-
{mainPackage.name}
100-
{mainPackage.hidden ? (
101-
<EyeOff className="w-3 h-3 sm:w-4 sm:h-4" />
102-
) : null}
103-
</button>
104-
</Tooltip>
105-
</>
76+
<Tooltip content="Change color">
77+
<button
78+
onClick={(e) => onColorClick(mainPackage.name, e)}
79+
className="hover:opacity-80"
80+
>
81+
<div
82+
className="w-3 h-3 sm:w-4 sm:h-4 rounded"
83+
style={{ backgroundColor: color }}
84+
/>
85+
</button>
86+
</Tooltip>
10687
)}
88+
<Tooltip content="Toggle package visibility">
89+
<button
90+
onClick={() => onToggleVisibility(index, mainPackage.name)}
91+
className={twMerge(
92+
'hover:text-blue-500 flex items-center gap-1',
93+
mainPackage.hidden ? 'opacity-50' : '',
94+
)}
95+
>
96+
{mainPackage.name}
97+
{mainPackage.hidden ? (
98+
<EyeOff className="w-3 h-3 sm:w-4 sm:h-4" />
99+
) : null}
100+
</button>
101+
</Tooltip>
107102
{isCombined ? (
108103
<span className="text-black/70 dark:text-white/70 text-[.7em] font-black py-0.5 px-1 leading-none rounded-md border-[1.5px] border-current opacity-80">
109104
+ {subPackages.length}

src/routes/$libraryId/$version.docs.npm-stats.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,12 +246,20 @@ function RouteComponent() {
246246
return {
247247
...prev,
248248
packageGroups: prev.packageGroups?.map((pkg) => {
249-
const baseline =
250-
pkg.packages[0]?.name === packageName ? !pkg.baseline : false
249+
const isTarget = pkg.packages[0]?.name === packageName
250+
const baseline = isTarget ? !pkg.baseline : false
251+
252+
const packages =
253+
isTarget && baseline
254+
? pkg.packages.map((p, i) =>
255+
i === 0 ? { ...p, hidden: false } : p,
256+
)
257+
: pkg.packages
251258

252259
return {
253260
...pkg,
254261
baseline,
262+
packages,
255263
}
256264
}),
257265
}

src/routes/stats/npm/-comparisons.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,7 @@ export function getPopularComparisons(): v.InferInput<
102102
color: '#f59e0b',
103103
},
104104
{
105-
packages: [
106-
{
107-
name: 'react',
108-
hidden: true,
109-
},
110-
],
105+
packages: [{ name: 'react' }],
111106
baseline: true,
112107
},
113108
],

src/routes/stats/npm/index.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,23 @@ function RouteComponent() {
265265
return {
266266
...prev,
267267
packageGroups: prev.packageGroups?.map((pkg) => {
268-
const baseline =
269-
pkg.packages[0].name === packageName ? !pkg.baseline : false
268+
const isTarget = pkg.packages[0].name === packageName
269+
const baseline = isTarget ? !pkg.baseline : false
270+
271+
// When promoting a series to baseline, force it visible so users
272+
// see the flat 1.0 reference line by default — matches every
273+
// other series' default-visible behavior.
274+
const packages =
275+
isTarget && baseline
276+
? pkg.packages.map((p, i) =>
277+
i === 0 ? { ...p, hidden: false } : p,
278+
)
279+
: pkg.packages
270280

271281
return {
272282
...pkg,
273283
baseline,
284+
packages,
274285
}
275286
}),
276287
}

0 commit comments

Comments
 (0)