Added click to copy button#3
Conversation
|
@keyurchotaliyaa is attempting to deploy a commit to the devanshukoli's projects Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughThe PR adds clipboard-copy functionality for the rendered meme image. The feature loads the image with canvas rendering, applies text overlays, and attempts to write the result to the clipboard via the modern Clipboard API with progressive fallbacks to raw blob copy and URL text copy. A new button and status message provide user feedback. ChangesClipboard Copy Feature
Sequence DiagramsequenceDiagram
participant User
participant Handler as handleCopyImageClick
participant Canvas as Canvas Render
participant ClipboardAPI as navigator.clipboard
participant Fallback1 as Raw Blob Copy
participant Fallback2 as URL Text Copy
User->>Handler: Click copy button
Handler->>Canvas: Load image + render text to canvas
Canvas-->>Handler: PNG blob
Handler->>ClipboardAPI: Write ClipboardItem with PNG
alt Success
ClipboardAPI-->>Handler: Clipboard written
Handler->>Handler: Set copyStatus to success
else ClipboardItem not supported
Handler->>Fallback1: Attempt raw blob copy
alt Blob copy succeeds
Fallback1-->>Handler: Image copied
Handler->>Handler: Set copyStatus to success
else Blob unavailable
Handler->>Fallback2: Copy URL or use textarea
Fallback2-->>Handler: Text copied
Handler->>Handler: Set copyStatus to fallback
end
end
Handler->>Handler: Clear status after timeout
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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 `@components/Main.jsx`:
- Line 46: The disabled-state string checked elsewhere does not match the value
set by setCopyStatus; update the code so the status string is consistent: either
change the call to setCopyStatus in the copy handler to use 'Copying...' instead
of 'Copying meme...' or change the conditional that checks copy status (the
comparison against 'Copying...') to compare against 'Copying meme...'; locate
the setCopyStatus call and the button-disabled check to make both use the same
exact string so the button correctly disables during copy.
- Line 191: The copy feedback div currently rendered by Main.jsx using the
copyStatus variable is visual-only; update the element that renders {copyStatus}
(the div with className "copy-status") to be an accessible live region by adding
appropriate attributes such as role="status" and aria-live="polite" (and
optionally aria-atomic="true") so screen readers will announce success/fallback
messages when copyStatus changes.
- Around line 143-155: Wrap the
navigator.clipboard.writeText(memeInputs.imageUrl) call in a try/catch and on
rejection set an explicit failure message via setCopyStatus (e.g., "Could not
copy combined meme (clipboard denied). Image URL copied instead.") and continue
to the fallback; when using document.execCommand('copy') inspect its boolean
return value and set failure status if it returns false. Normalize the
copy-state strings so the button disable condition matches (either change
setCopyStatus to use 'Copying...' or change the button check to 'Copying
meme...') and ensure the timeout-clearing behavior remains. Finally, make the
status container (className "copy-status") an accessible live region (add
aria-live="polite" or role="status") so assistive tech announces updates.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: a952e8c0-5a93-43c9-98be-6c7b65bc98d1
📒 Files selected for processing (2)
components/Main.jsxsrc/index.css
|
|
||
| const handleCopyImageClick = async () => { | ||
| // Attempt to render the meme (image + top/bottom text) onto a canvas | ||
| setCopyStatus('Copying meme...') |
There was a problem hiding this comment.
Fix the disabled-state string mismatch.
Line 190 checks for 'Copying...', but Line 46 sets 'Copying meme...'. The button never disables, so users can start overlapping copy attempts.
Proposed fix
- <button className="copy-button" onClick={handleCopyImageClick} disabled={copyStatus === 'Copying...'}>Copy image to clipboard</button>
+ <button className="copy-button" onClick={handleCopyImageClick} disabled={copyStatus === 'Copying meme...'}>Copy image to clipboard</button>Also applies to: 190-190
🤖 Prompt for 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.
In `@components/Main.jsx` at line 46, The disabled-state string checked elsewhere
does not match the value set by setCopyStatus; update the code so the status
string is consistent: either change the call to setCopyStatus in the copy
handler to use 'Copying...' instead of 'Copying meme...' or change the
conditional that checks copy status (the comparison against 'Copying...') to
compare against 'Copying meme...'; locate the setCopyStatus call and the
button-disabled check to make both use the same exact string so the button
correctly disables during copy.
| if (navigator.clipboard && navigator.clipboard.writeText) { | ||
| await navigator.clipboard.writeText(memeInputs.imageUrl) | ||
| setCopyStatus('Could not copy combined meme (CORS). Image URL copied instead.') | ||
| } else { | ||
| const textarea = document.createElement('textarea') | ||
| textarea.value = memeInputs.imageUrl | ||
| document.body.appendChild(textarea) | ||
| textarea.select() | ||
| document.execCommand('copy') | ||
| document.body.removeChild(textarea) | ||
| setCopyStatus('Could not copy combined meme. Image URL copied (fallback).') | ||
| } | ||
| setTimeout(() => setCopyStatus(''), 5000) |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
According to the current MDN docs, under what conditions can navigator.clipboard.writeText()reject, and what doesdocument.execCommand('copy') return when the copy operation is unsuccessful?
💡 Result:
According to MDN documentation, navigator.clipboard.writeText returns a Promise that is rejected if writing to the clipboard is not allowed [1]. While MDN generally states that the promise is rejected if clipboard access is denied [2], common conditions that lead to such rejections include failing to run the code in a secure context (HTTPS) [1][2], or failing to call the method within an appropriate user gesture event handler (such as pointerdown or pointerup) [3]. Regarding document.execCommand('copy'), MDN specifies that it returns a boolean value of false if the command is unsupported or disabled [4][5]. The documentation further notes that the method only returns true if it is invoked as part of a user interaction; it cannot be used to verify browser support before calling the command [4][5].
Citations:
- 1: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText
- 2: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard
- 3: Clipboard API not compatible for Safari mdn/content#31983
- 4: https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand
- 5: https://github.com/mdn/content/blob/main/files/en-us/web/api/document/execcommand/index.md
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show relevant sections with line numbers
sed -n '1,260p' components/Main.jsx | nl -ba | sed -n '110,220p'
# Find all copyStatus usages to confirm disabled-state mismatch and accessibility
rg -n "copyStatus|setCopyStatus" components/Main.jsx
# Find where the copy button's disabled prop is set
rg -n "disabled\s*=" components/Main.jsx
# Find where the status message is rendered (look for copy status usage in JSX)
rg -n "copyStatus" components/Main.jsxRepository: Devanshukoli/meme-generator
Length of output: 114
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Print range with line numbers using awk (nl not available)
awk 'NR>=110 && NR<=220 {printf "%4d\t%s\n", NR, $0}' components/Main.jsx
# Find all copyStatus / setCopyStatus usages
rg -n "copyStatus|setCopyStatus" components/Main.jsx
# Find where disabled prop is set for copy button
rg -n "disabled\s*=" components/Main.jsx
# Look for status rendering and aria-live
rg -n "aria-live|role=\"status\"|role='status'|status" components/Main.jsxRepository: Devanshukoli/meme-generator
Length of output: 4676
Handle failures in the final URL-copy fallback
navigator.clipboard.writeText(memeInputs.imageUrl)can reject when clipboard access is denied/not allowed (e.g., insecure context, missing user gesture), and this branch has no try/catch—so a rejection can escape and leave the UI stuck in the prior copy state. Also checkdocument.execCommand('copy')’s boolean return value and set an explicit failure status when it’sfalse.- The copy button disabled state is inconsistent: it disables only when
copyStatus === 'Copying...', but the code setssetCopyStatus('Copying meme...'), so the button may not disable during copy. - The status message (
<div className="copy-status">...) isn’t in a live region (aria-live/role="status"), so assistive tech may not announce updates.
🤖 Prompt for 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.
In `@components/Main.jsx` around lines 143 - 155, Wrap the
navigator.clipboard.writeText(memeInputs.imageUrl) call in a try/catch and on
rejection set an explicit failure message via setCopyStatus (e.g., "Could not
copy combined meme (clipboard denied). Image URL copied instead.") and continue
to the fallback; when using document.execCommand('copy') inspect its boolean
return value and set failure status if it returns false. Normalize the
copy-state strings so the button disable condition matches (either change
setCopyStatus to use 'Copying...' or change the button check to 'Copying
meme...') and ensure the timeout-clearing behavior remains. Finally, make the
status container (className "copy-status") an accessible live region (add
aria-live="polite" or role="status") so assistive tech announces updates.
| </div> | ||
| <div className="copy-controls"> | ||
| <button className="copy-button" onClick={handleCopyImageClick} disabled={copyStatus === 'Copying...'}>Copy image to clipboard</button> | ||
| {copyStatus && <div className="copy-status">{copyStatus}</div>} |
There was a problem hiding this comment.
Announce copy feedback to assistive tech.
The status text is visual-only right now. Adding a live region makes success and fallback messages audible to screen-reader users.
Proposed fix
- {copyStatus && <div className="copy-status">{copyStatus}</div>}
+ {copyStatus && (
+ <div className="copy-status" role="status" aria-live="polite">
+ {copyStatus}
+ </div>
+ )}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {copyStatus && <div className="copy-status">{copyStatus}</div>} | |
| {copyStatus && ( | |
| <div className="copy-status" role="status" aria-live="polite"> | |
| {copyStatus} | |
| </div> | |
| )} |
🤖 Prompt for 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.
In `@components/Main.jsx` at line 191, The copy feedback div currently rendered by
Main.jsx using the copyStatus variable is visual-only; update the element that
renders {copyStatus} (the div with className "copy-status") to be an accessible
live region by adding appropriate attributes such as role="status" and
aria-live="polite" (and optionally aria-atomic="true") so screen readers will
announce success/fallback messages when copyStatus changes.
🚀 Feature Added: Copy Meme to Clipboard
📌 Description
Added a "Copy to Clipboard" button below the generated meme image.
Now users can quickly copy the generated meme image and paste/use it anywhere (WhatsApp, Discord, Notes, etc.).
✨ Changes Made
🛠️ Tech Used
📷 Screenshots
✅ Result
Users can now:
Summary by CodeRabbit