Skip to content

feat(ui): added word wrap to code viewer - #2028

Closed
stephansama wants to merge 7 commits into
npmx-dev:mainfrom
stephansama:feat/add-word-wrap
Closed

feat(ui): added word wrap to code viewer#2028
stephansama wants to merge 7 commits into
npmx-dev:mainfrom
stephansama:feat/add-word-wrap

Conversation

@stephansama

Copy link
Copy Markdown

🔗 Linked issue

resolves#2027

🧭 Context

scrolling horizontally is annoying when trying to just read code in my opinion.

📚 Description

I just added a small button in the toolbar to toggle word wrap and a class to enable and disable word wrap

I did use gemini to help with this PR however i implemented a similar feature on my personal blog on code blocks. just used the ai to quickly get up to speed

@vercel

vercelBot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor

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

ProjectDeploymentActionsUpdated (UTC)
npmx.devReadyReadyPreview, CommentMar 17, 2026 10:09am
2 Skipped Deployments
ProjectDeploymentActionsUpdated (UTC)
docs.npmx.devIgnoredIgnoredPreviewMar 17, 2026 10:09am
npmx-lunariaIgnoredIgnoredMar 17, 2026 10:09am

Request Review

@github-actions

github-actionsBot commented Mar 10, 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

FileNote
i18n/locales/en.jsonSource changed, localizations will be marked as outdated.
Warnings reference
IconDescription
🔄️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.

@stephansamastephansama changed the title feat(word-wrap): added word wrap to code viewerfeat(ui): added word wrap to code viewerMar 10, 2026
@codecov

codecovBot commented Mar 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 52.00000% with 12 lines in your changes missing coverage. Please review.

Files with missing linesPatch %Lines
app/components/Code/Viewer.vue52.00%11 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai

coderabbitaiBot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are limited based on label configuration.

🚫 Review skipped — only excluded labels are configured. (1)
  • release

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1f5a3f31-e152-4f71-a719-f6301f7ac278

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a word-wrap feature to the code viewer: a new optional wordWrap prop and conditional is-wrapped class, a lineNumbersRef template ref, and syncLineHeights logic to align line-number heights with wrapped lines. The component watches wordWrap, calls syncing after updates and on window resize, and updates CSS to use pre-wrap, break-all and remove max-height for wrapped rendering. The package-code page adds a localStorage-backed toggle (npmx-code-word-wrap) with a UI button and passes :word-wrap to the viewer. English i18n (code.files.word_wrap) and schema entries were added.

Suggested reviewers

  • ghostdevv
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check nameStatusExplanation
Description check✅ PassedThe pull request description clearly relates to the changeset, mentioning the word wrap toggle button and CSS class additions.
Linked Issues check✅ PassedThe pull request successfully implements word wrap functionality for the code viewer as required by issue #2027, including wrapping logic, UI toggle button, and internationalization support.
Out of Scope Changes check✅ PassedAll changes are directly related to implementing the word wrap feature. No unrelated modifications to unrelated system components were introduced.

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

✨ 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 and usage tips.

@coderabbitaicoderabbitaiBot 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


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 29d80634-bca0-4cc4-8959-376aa22e6480

📥 Commits

Reviewing files that changed from the base of the PR and between 3712560 and ca13cca.

📒 Files selected for processing (4)
  • app/components/Code/Viewer.vue
  • app/pages/package-code/[[org]]/[packageName]/v/[version]/[...filePath].vue
  • i18n/locales/en.json
  • i18n/schema.json

Comment on lines +37 to +59
// Synchronize line number heights with code line heights (needed for word wrap)
function syncLineHeights() {
if (!props.wordWrap || !codeRef.value || !lineNumbersRef.value) {
// Reset heights if word wrap is disabled
if (lineNumbersRef.value) {
const nums = lineNumbersRef.value.querySelectorAll<HTMLElement>('.line-number')
nums.forEach(num => (num.style.height = ''))
}
return
}

const lines = codeRef.value.querySelectorAll<HTMLElement>('code > .line')
const nums = lineNumbersRef.value.querySelectorAll<HTMLElement>('.line-number')

lines.forEach((line, index) => {
const num = nums[index]
if (num) {
// Use getBoundingClientRect for more precision if needed, but offsetHeight is usually enough
const height = line.offsetHeight
num.style.height = `${height}px`
}
})
}

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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash# Verify that markdown files default to preview mode, that CodeViewer is mounted with v-show,# and that syncLineHeights currently only reruns on html/wordWrap/resize.
rg -n -C3 "const markdownViewMode|<CodeViewer|v-show=\"!fileContent.markdownHtml \\|\\| markdownViewMode === 'code'\"""app/pages/package-code/[[org]]/[packageName]/v/[version]/[...filePath].vue"
rg -n -C3 "function syncLineHeights|offsetHeight|watch\\(|props.wordWrap|useEventListener\\(window, 'resize'""app/components/Code/Viewer.vue"

Repository: npmx-dev/npmx.dev

Length of output: 2129


Re-sync wrapped line heights after the viewer becomes visible.

The parent component mounts CodeViewer with v-show="!fileContent.markdownHtml || markdownViewMode === 'code'" and defaults to preview mode. For markdown files, this means the component is initially hidden (display: none), yet the immediate watcher on [props.selectedLines, props.html] fires during mount and calls syncLineHeights() while the viewer is not rendered. This causes offsetHeight to return 0, setting all line-number heights to 0px. The heights are never corrected when the user switches to code view with word wrap enabled, leaving the line-number column collapsed.

Add visibility detection to skip measurement while hidden, or use a ResizeObserver on the rendered code block to continuously maintain synchronisation.

🧰 Tools
🪛 Biome (2.4.6)

[error] 43-43: This callback passed to forEach() iterable method should not return a value.

(lint/suspicious/useIterableCallbackReturn)

Comment threadapp/components/Code/Viewer.vue Outdated
Comment threadapp/pages/package-code/[[org]]/[packageName]/v/[version]/[...filePath].vue Outdated
@whitep4nth3r

Copy link
Copy Markdown
Contributor

Hi and thank you for this change!

In my opinion, and for accessibility reasons (for example for people who don't use a mouse) I believe that it's always better to wrap code regardless just using CSS.

For that reason I don't think we need a toggle and the wrapping can just be implemented using CSS.

@whitep4nth3r

Copy link
Copy Markdown
Contributor

Perhaps we should even have a max line length in the code viewer like in many IDEs.

@stephansama

Copy link
Copy Markdown
Author

Hi and thank you for this change!

In my opinion, and for accessibility reasons (for example for people who don't use a mouse) I believe that it's always better to wrap code regardless just using CSS.

For that reason I don't think we need a toggle and the wrapping can just be implemented using CSS.

i was trying to get it to work with css only however i was having a little issue. like it would mostly work but not all the way. i can take another crack at it again when i get out of work. 🫡

@nosthrillz

Copy link
Copy Markdown

Hi @whitep4nth3r

I created this PR in response to the same issue, avoiding a toggle
#2070

Hope I'm not stepping on toes, it's my first OSS PR ever 😅

@gameroman

Copy link
Copy Markdown
Member

In my opinion, and for accessibility reasons (for example for people who don't use a mouse) I believe that it's always better to wrap code regardless just using CSS.

I think having a toggle/setting + shortcut would be better because sometimes you do not want the code to be wrapped

@coderabbitaicoderabbitaiBot 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.

🧹 Nitpick comments (1)
app/pages/package-code/[[org]]/[packageName]/v/[version]/[...filePath].vue (1)

431-432: Simplify icon toggle using v-else and remove redundant !!.

  • !!wordWrap is unnecessary since wordWrap is already a boolean ref.
  • Using two v-if directives instead of v-if/v-else means Vue evaluates both conditions on every render.
♻️ Proposed fix
-<span v-if="!!wordWrap" class="i-lucide:wrap-text w-3 h-3" />-<span v-if="!wordWrap" class="i-lucide:text w-3 h-3" />+<span v-if="wordWrap" class="i-lucide:wrap-text w-3 h-3" />+<span v-else class="i-lucide:text w-3 h-3" />

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ab3db15d-0017-40f9-a208-64e41af7e966

📥 Commits

Reviewing files that changed from the base of the PR and between 95848e8 and e14b94f.

📒 Files selected for processing (1)
  • app/pages/package-code/[[org]]/[packageName]/v/[version]/[...filePath].vue

@stephansama

Copy link
Copy Markdown
Author

In my opinion, and for accessibility reasons (for example for people who don't use a mouse) I believe that it's always better to wrap code regardless just using CSS.

I think having a toggle/setting + shortcut would be better because sometimes you do not want the code to be wrapped

i think the toggle is better for user experience as i prefer word wrap however regular people that i meet hate word wrap. giving the choice to the people i think is the correct move

@github-actionsgithub-actionsBot added the stale This has become stale and may be closed soon label Apr 18, 2026
@npmx-devnpmx-dev deleted a comment from github-actionsBotApr 18, 2026
@serhalpserhalp added the a11y Related to accessibility and inclusion label Apr 20, 2026
@serhalpserhalp added the needs review This PR is waiting for a review from a maintainer label Apr 20, 2026
@github-actionsgithub-actionsBot removed the stale This has become stale and may be closed soon label Apr 20, 2026
@github-actionsgithub-actionsBot added stale This has become stale and may be closed soon and removed stale This has become stale and may be closed soon labels May 20, 2026
@github-actionsgithub-actionsBot added the stale This has become stale and may be closed soon label Jun 20, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a11yRelated to accessibility and inclusionneeds reviewThis PR is waiting for a review from a maintainerstaleThis has become stale and may be closed soonstale-to-close

Projects

None yet

Development

Successfully merging this pull request may close these issues.

add word wrap to code viewer

5 participants

@stephansama@whitep4nth3r@nosthrillz@gameroman@serhalp