Skip to content

feat: update readme toc button to use new component#1112

Merged
danielroe merged 7 commits intonpmx-dev:mainfrom
IdrisGit:feat-copy-readme-to-markdown
Feb 7, 2026
Merged

feat: update readme toc button to use new component#1112
danielroe merged 7 commits intonpmx-dev:mainfrom
IdrisGit:feat-copy-readme-to-markdown

Conversation

@IdrisGit
Copy link
Contributor

@IdrisGit IdrisGit commented Feb 6, 2026

Update the README toc button to use the new button components

image
(original description before pr change)

Add a button to copy raw readme markdown to the clipboard

screen recording

copy_readme_markdown_compressed.mp4

closes #1020

there is already a PR (#1058) addressing this iddue, I found that out just before creating this PR, I am opening this PR as there are some subtle design differences, not trying to compete or anything, just for a design consideration, I am okay even if my design is selected but implemented in the first PR.

@vercel
Copy link

vercel bot commented Feb 6, 2026

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

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Feb 7, 2026 1:21pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Feb 7, 2026 1:21pm
npmx-lunaria Ignored Ignored Feb 7, 2026 1:21pm

Request Review

@github-actions
Copy link

github-actions bot commented Feb 6, 2026

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
lunaria/files/en-GB.json Localization changed, will be marked as complete. 🔄️
lunaria/files/en-US.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
Copy link

codecov bot commented Feb 6, 2026

Codecov Report

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

Files with missing lines Patch % Lines
app/components/ReadmeTocDropdown.vue 0.00% 1 Missing and 1 partial ⚠️
app/components/Button/Base.vue 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 6, 2026

📝 Walkthrough

Walkthrough

ReadmeTocDropdown.vue now uses the ButtonBase component instead of a native button element, replaces the inner icon span with a classicon="i-carbon:list" attribute, and updates the closing tag accordingly. The dropdown toggle was hardened by using optional chaining and a guard when calling getBoundingClientRect() on the trigger ref. Button/Base.vue’s public API was extended: its exposed interface now includes getBoundingClientRect() in addition to focus() so parent components can obtain the button’s bounding rect.

Suggested reviewers

  • ghostdevv
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description clearly relates to updating the README TOC button to use new button components, directly corresponding to the changeset modifications.
Linked Issues check ✅ Passed The pull request updates the button component to use ButtonBase with proper positioning logic, directly addressing the functionality required by issue #1020 for copying README markdown.
Out of Scope Changes check ✅ Passed All changes are scoped to updating ReadmeTocDropdown.vue and Button/Base.vue to support the new button component integration, remaining within the PR objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
server/utils/readme.ts (1)

456-461: Consider the payload size impact of returning raw markdown alongside HTML.

Returning markdown: content effectively doubles the README payload for every API response, since both the rendered HTML and the raw markdown are now transmitted. For packages with large READMEs (some exceed 100 KB), this adds non-trivial bandwidth and memory pressure on every page load — even when the user never clicks the copy button.

Consider either:

  1. Serving the markdown via a separate on-demand endpoint (e.g. /api/registry/readme-markdown/[...pkg]) so it is only fetched when the user clicks "Copy".
  2. Lazy-loading the markdown field on the client side only when the copy button is clicked.

This keeps the default page load lean and only pays the cost when the feature is actually used.

app/pages/package/[[org]]/[name].vue (1)

1145-1171: Good feature implementation overall — a couple of minor observations.

  1. aria-live="polite" on the label span (line 1161) — Nice accessibility touch; screen readers will announce the state change when the text switches to "Copied".

  2. Icon choice for the default (non-copied) state: The copy button uses i-carbon:document as its default icon. Other copy buttons in this file (e.g. the package-name copy button at line 550) use i-carbon:copy. Consider using i-carbon:copy here too for visual consistency across copy actions on the page, or i-carbon:markdown if available and you want to emphasise the markdown aspect.

Copy link
Contributor

@ghostdevv ghostdevv left a comment

Choose a reason for hiding this comment

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

I'm rebasing rq

@IdrisGit
Copy link
Contributor Author

IdrisGit commented Feb 7, 2026

Image

@vercel
Copy link

vercel bot commented Feb 7, 2026

Deployment failed with the following error:

Failed to create deployment for team_pU9rqpNXTh3hue2YWfbuRLFz in project prj_RypB9aOA2tZJOgXvauA3RFur02oX: FetchError: request to https://76.76.21.112/v13/now/deployments?ownerId=team_pU9rqpNXTh3hue2YWfbuRLFz&projectId=prj_RypB9aOA2tZJOgXvauA3RFur02oX&skipAutoDetectionConfirmation=1&teamId=team_pU9rqpNXTh3hue2YWfbuRLFz&traceCarrier=%7B%22ot-baggage-webhookAt%22%3A%221770455227159%22%2C%22ot-baggage-senderUsername%22%3A%22gh.IdrisGit%22%2C%22x-datadog-trace-id%22%3A%223636785109791512527%22%2C%22x-datadog-parent-id%22%3A%223154465748945442650%22%2C%22x-datadog-sampling-priority%22%3A%222%22%2C%22x-datadog-tags%22%3A%22_dd.p.tid%3D698700bb00000000%2C_dd.p.dm%3D-3%22%2C%22traceparent%22%3A%2200-698700bb00000000327874c9f18d97cf-2bc6e9e2b607975a-01%22%2C%22tracestate%22%3A%22dd%3Dt.tid%3A698700bb00000000%3Bt.dm%3A-3%3Bs%3A2%3Bp%3A2bc6e9e2b607975a%22%7D failed, reason: socket hang up

@vercel
Copy link

vercel bot commented Feb 7, 2026

Deployment failed with the following error:

Failed to create deployment for team_ALCY5q4yeU97jar3pmPUQ7I3 in project prj_0L4Fs1yierGXfNgP2jR79rMitJi6: FetchError: request to https://76.76.21.112/v13/now/deployments?ownerId=team_ALCY5q4yeU97jar3pmPUQ7I3&projectId=prj_0L4Fs1yierGXfNgP2jR79rMitJi6&skipAutoDetectionConfirmation=1&teamId=team_ALCY5q4yeU97jar3pmPUQ7I3&traceCarrier=%7B%22ot-baggage-webhookAt%22%3A%221770455227159%22%2C%22ot-baggage-senderUsername%22%3A%22gh.IdrisGit%22%2C%22x-datadog-trace-id%22%3A%223636785109791512527%22%2C%22x-datadog-parent-id%22%3A%225772184500733472770%22%2C%22x-datadog-sampling-priority%22%3A%222%22%2C%22x-datadog-tags%22%3A%22_dd.p.tid%3D698700bb00000000%2C_dd.p.dm%3D-3%22%2C%22traceparent%22%3A%2200-698700bb00000000327874c9f18d97cf-501aeb38983bf002-01%22%2C%22tracestate%22%3A%22dd%3Dt.tid%3A698700bb00000000%3Bt.dm%3A-3%3Bs%3A2%3Bp%3A501aeb38983bf002%22%7D failed, reason: socket hang up

@vercel
Copy link

vercel bot commented Feb 7, 2026

Deployment failed with the following error:

Failed to create deployment for team_pU9rqpNXTh3hue2YWfbuRLFz in project prj_MJNmtAsoWitL8bQBYh39a9SHANTl: FetchError: request to https://76.76.21.112/v13/now/deployments?ownerId=team_pU9rqpNXTh3hue2YWfbuRLFz&projectId=prj_MJNmtAsoWitL8bQBYh39a9SHANTl&skipAutoDetectionConfirmation=1&teamId=team_pU9rqpNXTh3hue2YWfbuRLFz&traceCarrier=%7B%22ot-baggage-webhookAt%22%3A%221770455227159%22%2C%22ot-baggage-senderUsername%22%3A%22gh.IdrisGit%22%2C%22x-datadog-trace-id%22%3A%223636785109791512527%22%2C%22x-datadog-parent-id%22%3A%223154465748945442650%22%2C%22x-datadog-sampling-priority%22%3A%222%22%2C%22x-datadog-tags%22%3A%22_dd.p.tid%3D698700bb00000000%2C_dd.p.dm%3D-3%22%2C%22traceparent%22%3A%2200-698700bb00000000327874c9f18d97cf-2bc6e9e2b607975a-01%22%2C%22tracestate%22%3A%22dd%3Dt.tid%3A698700bb00000000%3Bt.dm%3A-3%3Bs%3A2%3Bp%3A2bc6e9e2b607975a%22%7D failed, reason: socket hang up

@ghostdevv ghostdevv force-pushed the feat-copy-readme-to-markdown branch from a48379f to a110b4a Compare February 7, 2026 12:57
@ghostdevv ghostdevv changed the title feat: unify style of readme copy button feat: update readme toc button to use new component Feb 7, 2026
@ghostdevv
Copy link
Contributor

This poor PR has been through a lot, but I'm determined to save it!

@ghostdevv ghostdevv marked this pull request as ready for review February 7, 2026 12:59
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
app/components/ReadmeTocDropdown.vue (2)

83-88: ⚠️ Potential issue | 🔴 Critical

Fix buttonRef access — requires .value to dereference the exposed ref.

buttonRef exposed from ButtonBase is the raw Ref<HTMLButtonElement> returned by useTemplateRef. Vue does not auto-unwrap refs accessed on component instances via defineExpose. Therefore, triggerRef.value.buttonRef returns the Ref object itself, not the HTMLButtonElement.

Lines 84, 105, and 142 currently call .getBoundingClientRect() and .focus() directly on the Ref object, which lacks these DOM methods and will throw a TypeError at runtime.

The guard on line 83 is also incorrect—it checks if the Ref object exists (always truthy), not if the element exists.

All three usages require .value appended:

Proposed fix
 function toggle() {
   if (isOpen.value) {
     close()
   } else {
-    if (triggerRef.value?.buttonRef) {
-      const rect = triggerRef.value?.buttonRef.getBoundingClientRect()
+    const buttonEl = triggerRef.value?.buttonRef?.value
+    if (buttonEl) {
+      const rect = buttonEl.getBoundingClientRect()
       dropdownPosition.value = {
         top: rect.bottom + 4,
         right: rect.right,
       }
     }

And fix lines 105 and 142:

- triggerRef.value?.buttonRef?.focus()
+ triggerRef.value?.buttonRef?.value?.focus()

115-115: ⚠️ Potential issue | 🟠 Major

onClickOutside ignore requires the actual DOM button element, not the component instance ref.

triggerRef is a component instance ref to ButtonBase. VueUse's onClickOutside ignore option expects DOM element refs (like those from useTemplateRef()) or selector strings, not component refs. You should either use unrefElement(triggerRef) with a computed, pass the exposed buttonRef directly, or use a selector string.

For example:

-onClickOutside(listRef, close, { ignore: [triggerRef] })
+onClickOutside(listRef, close, { ignore: [() => unrefElement(triggerRef)] })

Or, since ButtonBase exposes buttonRef:

-onClickOutside(listRef, close, { ignore: [triggerRef] })
+onClickOutside(listRef, close, { ignore: computed(() => [triggerRef.value?.buttonRef?.value]) })

@ghostdevv ghostdevv force-pushed the feat-copy-readme-to-markdown branch from d9b4325 to 7152c10 Compare February 7, 2026 13:16
@ghostdevv
Copy link
Contributor

ghostdevv commented Feb 7, 2026

@danielroe I totally just overwrote your commit 🤦‍♀️ force-with-lease isn't working and regardless I forget we squash merge!! I hopefully have done the same result?

@ghostdevv ghostdevv requested a review from danielroe February 7, 2026 13:17

defineExpose({
focus: () => el.value?.focus(),
buttonRef: el,
Copy link
Member

Choose a reason for hiding this comment

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

previously only the focus was exposed to avoid too much dependency externally on the inner workings of the button, so I wonder if it would be better simply to expose getBoundingClientRect and/or consider whether we can refactor in future.

@danielroe
Copy link
Member

you did exactly what I did 👌
very nice!

@danielroe danielroe enabled auto-merge February 7, 2026 13:22
@danielroe danielroe added this pull request to the merge queue Feb 7, 2026
Merged via the queue into npmx-dev:main with commit 9867a47 Feb 7, 2026
17 checks passed
whitep4nth3r pushed a commit that referenced this pull request Feb 7, 2026
Co-authored-by: Willow (GHOST) <git@willow.sh>
Co-authored-by: Daniel Roe <daniel@roe.dev>
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.

Add copy button for README

3 participants