- fix: Make Command Prompts Non-Selectable in CodeGroup#21681
- fix: Make Command Prompts Non-Selectable in CodeGroup#21681somandhir wants to merge 2 commits intovitejs:mainfrom
Conversation
| > | ||
| <button class="copy"></button> | ||
| <span class="lang">{{ tab.language || 'bash' }}</span> | ||
| <pre><code><span class="prompt" v-if="splitCommand(tab.code).prompt">{{ splitCommand(tab.code).prompt }}</span><span class="command">{{ splitCommand(tab.code).command }}</span></code></pre> |
There was a problem hiding this comment.
Performance issue: splitCommand(tab.code) is called three times in a single render for the same input (once for v-if check, once for prompt display, once for command display). This causes the regex to execute three times per tab unnecessarily.
Fix: Compute the split result once and reuse it:
<script setup lang="ts">
const getSplitCommand = (code: string) => {
const match = code.match(/^(\s*\$\s+)(.*)$/)
return match ? { prompt: match[1], command: match[2] } : { prompt: '', command: code }
}
</script>
<template>
<div v-for="(tab, index) in tabs" :key="`content-${index}`">
<template v-memo="[tab.code]">
<pre><code><template v-if="getSplitCommand(tab.code).prompt"><span class="prompt">{{ getSplitCommand(tab.code).prompt }}</span></template><span class="command">{{ getSplitCommand(tab.code).command }}</span></code></pre>
</template>
</div>
</template>Or better, use a computed property to cache results per tab.
Spotted by Graphite Agent
Is this helpful? React 👍 or 👎 to let us know.
There was a problem hiding this comment.
Performance issue:
splitCommand(tab.code)is called three times in a single render for the same input (once for v-if check, once for prompt display, once for command display). This causes the regex to execute three times per tab unnecessarily.Fix: Compute the split result once and reuse it:
<script setup lang="ts"> const getSplitCommand = (code: string) => { const match = code.match(/^(\s*\$\s+)(.*)$/) return match ? { prompt: match[1], command: match[2] } : { prompt: '', command: code } } </script> <template> <div v-for="(tab, index) in tabs" :key="`content-${index}`"> <template v-memo="[tab.code]"> <pre><code><template v-if="getSplitCommand(tab.code).prompt"><span class="prompt">{{ getSplitCommand(tab.code).prompt }}</span></template><span class="command">{{ getSplitCommand(tab.code).command }}</span></code></pre> </template> </div> </template>Or better, use a computed property to cache results per tab.
Spotted by Graphite Agent
Is this helpful? React 👍 or 👎 to let us know.
I've optimized the component to eliminate the redundant regex executions:
Changes made:
Replaced the function with a computed property: splitCommands now maps over all tabs once and caches the results
Updated the template: Changed from calling splitCommand(tab.code) three times to accessing splitCommands[index] which is pre-computed and cached
Performance improvement:
Before: Regex executed 3x per tab per render (once for v-if, twice for display)
After: Regex executed 1x per tab total (cached in computed property)
The computed property reactively recalculates only when props.tabs changes, making the component significantly more efficient
When users triple-click on terminal commands in the CodeGroup component (e.g., $ npm create vite@latest), the entire line including the prompt ($) is selected. This makes it inconvenient to copy just the command itself
Modified the CodeGroup component to:
Split the shell prompt from the command: The regex pattern ^(\s*$\s+)(.*)$ separates the $ prefix from the actual command text
Render in separate spans: The prompt and command are now rendered in distinct elements with different styling
Disable selection on prompt: Added CSS rules with user-select: none on the prompt span, so triple-clicking only selects the command portion
Reference the issues it solves (e.g.
fixes #123).fixes $ prompt in code blocks gets selected on triple-click, causing bad copy-paste experience (2) #21678
Are there any parts you think require more attention from reviewers?
the hero.vue was asking for CodeGroup from @/components/shared/CodeGroup.vue but I couldn't find where it was pointing , so I made a custom CodeGroup in the given directory with the required code