Skip to content

feat: add copy PNG buttons to charts - #3132

Merged
gameroman merged 4 commits into
npmx-dev:mainfrom
BlankParticle:feature/feat/copy-chart-png
Aug 4, 2026
Merged

feat: add copy PNG buttons to charts#3132
gameroman merged 4 commits into
npmx-dev:mainfrom
BlankParticle:feature/feat/copy-chart-png

Conversation

@BlankParticle

Copy link
Copy Markdown
Contributor

copy chart PNG exports directly to the clipboard with the watermark preserved

🔗 Linked issue

fixes #2325

🧭 Context

I wanted a to directly copy the chart to my clipboard to post on discord/twitter

📚 Description

Adds a copy button to all the charts, this temporarily enables the watermark, renders the image as png and copies it to the clipboard.
I don't know how to write vue or what patterns are normally used, so that part was written by Claude Fable with what I asked for, I and other models have reviewed this and it looks like the patterns people normally use in vue. I have verified the runtime functionality.

- Copy chart PNG exports directly to the clipboard
- Preserve chart watermarks during clipboard export
@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview Aug 4, 2026 9:23am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Aug 4, 2026 9:23am
npmx-lunaria Ignored Ignored Aug 4, 2026 9:23am

Request Review

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Hello! Thank you for opening your first PR to npmx, @BlankParticle! 🚀

Here’s what will happen next:

  1. Our GitHub bots will run to check your changes.
    If they spot any issues you will see some error messages on this PR.
    Don’t hesitate to ask any questions if you’re not sure what these mean!

  2. In a few minutes, you’ll be able to see a preview of your changes on Vercel

  3. One or more of our maintainers will take a look and may ask you to make changes.
    We try to be responsive, but don’t worry if this takes a few days.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 71d1fe27-d70e-4984-a9bf-68bc410fd6ee

📥 Commits

Reviewing files that changed from the base of the PR and between bb69071 and 3287ba1.

📒 Files selected for processing (2)
  • app/components/Chart/CopyPngButton.vue
  • app/composables/useCopyChartPng.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/composables/useCopyChartPng.ts

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added “Copy PNG” actions to chart menus across comparison, timeline, trends, and version distribution charts.
    • Charts retain their watermark when PNGs are copied.
    • Copy controls display loading and confirmation states with localised feedback.
  • Accessibility
    • Added accessible labelling, button semantics, and busy-state announcements for assistive technologies.
  • Localisation
    • Added English translation support for the “Copy {fileType}” action.

Walkthrough

The PR adds PNG clipboard copying for compare and package charts. It adds shared copy logic, an accessible copy button, watermark support during PNG generation, localisation, and accessibility tests.

Changes

PNG chart copy

Layer / File(s) Summary
Copy composable and button
app/composables/useCopyChartPng.ts, app/components/Chart/CopyPngButton.vue, i18n/..., test/nuxt/a11y.spec.ts
Adds PNG clipboard export logic, copy-state UI, translation schema entries, and accessibility tests.
Compare chart integration
app/components/Compare/FacetBarChart.vue, app/components/Compare/FacetScatterChart.vue
Adds PNG copy actions, chart references, copy state, and watermark handling to bar and scatter charts.
Package chart integration
app/components/Package/TimelineChart.vue, app/components/Package/TrendsChart.vue, app/components/Package/VersionDistribution.vue, app/components/Package/*SvgSlot.vue
Adds PNG copy actions and watermark state to package charts and timeline SVG slots.

Sequence Diagram(s)

sequenceDiagram
  participant ChartComponent
  participant useCopyChartPng
  participant ChartWithImageExport
  participant ClipboardAPI
  ChartComponent->>useCopyChartPng: copyChartPng()
  useCopyChartPng->>ChartWithImageExport: generate PNG data
  ChartWithImageExport-->>useCopyChartPng: return data URI
  useCopyChartPng->>ClipboardAPI: write PNG ClipboardItem
Loading

Possibly related PRs

  • npmx-dev/npmx.dev#2663: Extends TimelineChart.vue with PNG-copy functionality and wires its SVG slots to display the watermark during copying.
  • npmx-dev/npmx.dev#2688: Modifies TimelineChart.vue and TrendsChart.vue chart reference handling.

Suggested reviewers: ghostdevv

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding PNG copy buttons to charts.
Description check ✅ Passed The description directly explains the PNG clipboard-copy feature, watermark behaviour, implementation scope, and testing.
Linked Issues check ✅ Passed The changes satisfy issue #2325 by adding Copy as PNG actions that copy chart images to the clipboard without downloading.
Out of Scope Changes check ✅ Passed The component, composable, localisation, watermark, and accessibility-test changes support the linked issue objectives.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Lunaria Status Overview

🌕 This pull request will trigger status changes.

Learn more

By default, every PR changing files present in the Lunaria configuration's files property will be considered and trigger status changes accordingly.

You can change this by adding one of the keywords present in the ignoreKeywords property in your Lunaria configuration file in the PR's title (ignoring all files) or by including a tracker directive in the merged commit's description.

Tracked Files

File Note
i18n/locales/en.json Source changed, localizations will be marked as outdated.
Warnings reference
Icon Description
🔄️ The source for this localization has been updated since the creation of this pull request, make sure all changes in the source have been applied.

@codecov

codecov Bot commented Aug 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 41.17647% with 20 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
app/composables/useCopyChartPng.ts 27.77% 12 Missing and 1 partial ⚠️
app/components/Package/VersionDistribution.vue 0.00% 3 Missing ⚠️
app/components/Package/TimelineChart.vue 33.33% 2 Missing ⚠️
app/components/Compare/FacetScatterChart.vue 66.66% 1 Missing ⚠️
app/components/Package/TrendsChart.vue 50.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/components/Chart/CopyPngButton.vue`:
- Around line 10-22: Update the successful copy flow in CopyPngButton, using
useCommandPalette().announce(message) to announce a localized copy-success
message after the clipboard operation completes successfully. Keep the existing
copied icon state and accessible button label unchanged, and do not announce
failed copies.

In `@app/composables/useCopyChartPng.ts`:
- Around line 23-32: Update copyChartPng to return immediately when
isCopyingPng.value is already true, before setting the flag or awaiting
nextTick, so concurrent getImage and clipboard operations cannot overlap.
Preserve the existing flag reset in the getImage completion path.
- Around line 27-38: Update copyChartPng so it creates the ClipboardItem
synchronously and calls copy immediately with a promise-valued PNG Blob,
preserving the user activation through the clipboard write; perform
chart.getImage() and data-URI decoding inside that promise. Add a fallback for
browsers that reject promise-valued ClipboardItems, while retaining the existing
isCopyingPng cleanup behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c3d8afb5-78ad-451a-84b6-64e485000e28

📥 Commits

Reviewing files that changed from the base of the PR and between 1f4d06b and 165172d.

📒 Files selected for processing (11)
  • app/components/Chart/CopyPngButton.vue
  • app/components/Compare/FacetBarChart.vue
  • app/components/Compare/FacetScatterChart.vue
  • app/components/Package/TimelineChart.vue
  • app/components/Package/TimelineChartDepSizeSvgSlot.vue
  • app/components/Package/TimelineChartXySvgSlot.vue
  • app/components/Package/TrendsChart.vue
  • app/components/Package/VersionDistribution.vue
  • app/composables/useCopyChartPng.ts
  • i18n/locales/en.json
  • i18n/schema.json

Comment thread app/components/Chart/CopyPngButton.vue Outdated
Comment thread app/composables/useCopyChartPng.ts Outdated
Comment thread app/composables/useCopyChartPng.ts Outdated

@gameroman gameroman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd use cursor-pointer

Also while it's copying, there is no visual feedback

I'd use some "loading" icon while it's copying

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/composables/useCopyChartPng.ts`:
- Around line 20-47: The guard clause in copyChartPng currently only checks
isSupported.value, which does not guarantee ClipboardItem is available, causing
the new ClipboardItem constructor call to throw. Add a separate check for typeof
ClipboardItem === 'undefined' to the existing early return guard alongside the
checks for chart, isSupported.value, and isCopyingPng.value to ensure
ClipboardItem is defined before attempting to instantiate it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f3602d8b-09b2-4cfa-91c9-d3f420f2ead5

📥 Commits

Reviewing files that changed from the base of the PR and between b1a3a7d and bb69071.

📒 Files selected for processing (8)
  • app/components/Chart/CopyPngButton.vue
  • app/components/Compare/FacetBarChart.vue
  • app/components/Compare/FacetScatterChart.vue
  • app/components/Package/TimelineChart.vue
  • app/components/Package/TrendsChart.vue
  • app/components/Package/VersionDistribution.vue
  • app/composables/useCopyChartPng.ts
  • test/nuxt/a11y.spec.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • test/nuxt/a11y.spec.ts
  • app/components/Package/TrendsChart.vue
  • app/components/Compare/FacetBarChart.vue
  • app/components/Package/TimelineChart.vue
  • app/components/Package/VersionDistribution.vue
  • app/components/Compare/FacetScatterChart.vue

Comment thread app/composables/useCopyChartPng.ts Outdated
@BlankParticle

Copy link
Copy Markdown
Contributor Author

I have updated and simplified the button, now it shows a matching tooltip and has a loading state

@gameroman gameroman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice! Lets see what others think

@gameroman
gameroman requested a review from a team August 4, 2026 09:26

@graphieros graphieros left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect usage of the chart library, and very cool feature 👍 🌿

@gameroman
gameroman added this pull request to the merge queue Aug 4, 2026
Merged via the queue into npmx-dev:main with commit deda790 Aug 4, 2026
24 checks passed
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Thanks for your first contribution, @BlankParticle! 👏

We'd love to welcome you to the npmx community. Come and say hi on Discord! And once you've joined, visit npmx.wamellow.com to claim the contributor role.

@BlankParticle
BlankParticle deleted the feature/feat/copy-chart-png branch August 4, 2026 09:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Copy download graph as PNG

3 participants