Frontend: CopyButton primitive (clipboard) #183

Closed
opened 2026-05-25 02:12:59 +00:00 by PlasticDigits · 16 comments
PlasticDigits commented 2026-05-25 02:12:59 +00:00 (Migrated from gitlab.com)

Summary

Extract a reusable CopyButton for one-click clipboard copy. Required before wallet-chip copy and other address surfaces (GitLab #140 scope B — infra sibling).

Context

  • Grep shows no navigator.clipboard usage in frontend-dapp/src today.
  • First consumer: connected wallet dropdown “copy address” (#140).
  • Future: Trader page, pool/LP addresses, pair chips, tx hashes (TxResultAlert has explorer but no copy).

Acceptance criteria

  • Relates to: #140 (LUNC balance landed separately).
  • Blocks: wallet dropdown copy affordance issue (filed as sibling).

cc @Brouie @PlasticDigits

## Summary Extract a reusable **`CopyButton`** for one-click clipboard copy. Required before wallet-chip copy and other address surfaces ([GitLab #140](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/140) scope **B** — infra sibling). ## Context - Grep shows **no** `navigator.clipboard` usage in `frontend-dapp/src` today. - First consumer: connected wallet dropdown “copy address” ([#140](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/140)). - Future: Trader page, pool/LP addresses, pair chips, tx hashes (`TxResultAlert` has explorer but no copy). ## Acceptance criteria - [ ] Accessible button (`aria-label`, brief success feedback or `aria-live`). - [ ] Handles clipboard API failure with retail-safe message. - [ ] Vitest for copy handler (mock `navigator.clipboard`). - [ ] Documented in [`docs/frontend.md`](docs/frontend.md) + [`skills/AGENTS_FRONTEND_WALLET_CHIP.md`](skills/AGENTS_FRONTEND_WALLET_CHIP.md) cross-link. ## Parent / related - **Relates to:** [#140](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/140) (LUNC balance landed separately). - **Blocks:** wallet dropdown copy affordance issue (filed as sibling). cc @Brouie @PlasticDigits
PlasticDigits commented 2026-05-25 02:13:00 +00:00 (Migrated from gitlab.com)

marked as related to #140

marked as related to #140
PlasticDigits commented 2026-05-25 02:13:26 +00:00 (Migrated from gitlab.com)

mentioned in issue #185

mentioned in issue #185
PlasticDigits commented 2026-05-25 02:13:26 +00:00 (Migrated from gitlab.com)

marked as related to #185

marked as related to #185
PlasticDigits commented 2026-05-25 02:13:51 +00:00 (Migrated from gitlab.com)

mentioned in issue #188

mentioned in issue #188
PlasticDigits commented 2026-05-25 02:13:52 +00:00 (Migrated from gitlab.com)

marked as related to #188

marked as related to #188
PlasticDigits commented 2026-05-25 02:14:02 +00:00 (Migrated from gitlab.com)

mentioned in issue #140

mentioned in issue #140
PlasticDigits commented 2026-05-25 02:14:13 +00:00 (Migrated from gitlab.com)

mentioned in commit 574dfdf4e6

mentioned in commit 574dfdf4e6a43d0c7f2b0933301f440bf326b679
PlasticDigits commented 2026-05-25 02:21:17 +00:00 (Migrated from gitlab.com)

mentioned in commit 854d0cd9c1

mentioned in commit 854d0cd9c1cb06605db4c1d9e348a2e04315af03
PlasticDigits commented 2026-05-25 02:21:17 +00:00 (Migrated from gitlab.com)

mentioned in commit a4d16f7bbf

mentioned in commit a4d16f7bbf30fa3a71db94d76c858b6afc0e64d0
PlasticDigits commented 2026-05-25 02:21:32 +00:00 (Migrated from gitlab.com)

Implementation summary (GitLab #183)

Merged to main (854d0cd): reusable CopyButton clipboard primitive for address/contract/tx surfaces.

Delivered

  • frontend-dapp/src/utils/copyToClipboard.ts — single writeText path (trim, injectable for Vitest)
  • frontend-dapp/src/components/ui/CopyButton.tsx — accessible icon button, aria-label, aria-live="polite" success/failure feedback (2s reset)
  • Retail strings in frontend-dapp/src/utils/copyButtonCopy.ts
  • Vitest: copyToClipboard.test.ts (mocks navigator.clipboard), CopyButton.test.tsx
  • Docs: docs/frontend.md#copy-button-primitive, skills/AGENTS_FRONTEND_COPY_BUTTON.md, cross-links in wallet-chip skill + docs/README.md

Not in this MR (by design): wallet dropdown wiring — tracked in #185 (uses this primitive + getExplorerAddressUrl from #184).

Verification checklist

  • cd frontend-dapp && npm test -- --run src/utils/__tests__/copyToClipboard.test.ts src/components/ui/__tests__/CopyButton.test.tsx — all green
  • Import CopyButton from @/components/ui; click copies trimmed text
  • Screen reader / axe: button has explicit label; live region announces "Copied to clipboard" then clears
  • Deny clipboard permission (or non-secure context): failure message is retail-safe (no raw DOMException)
  • Docs anchors resolve: #copy-button-primitive, agent skill links from AGENTS_FRONTEND_WALLET_CHIP.md

@Brouie — please verify on your side when you have a moment. Leaving the issue open until #185 consumes the primitive in the wallet menu.

## Implementation summary (GitLab #183) Merged to `main` (`854d0cd`): reusable **`CopyButton`** clipboard primitive for address/contract/tx surfaces. ### Delivered - `frontend-dapp/src/utils/copyToClipboard.ts` — single `writeText` path (trim, injectable for Vitest) - `frontend-dapp/src/components/ui/CopyButton.tsx` — accessible icon button, `aria-label`, `aria-live="polite"` success/failure feedback (2s reset) - Retail strings in `frontend-dapp/src/utils/copyButtonCopy.ts` - Vitest: `copyToClipboard.test.ts` (mocks `navigator.clipboard`), `CopyButton.test.tsx` - Docs: `docs/frontend.md#copy-button-primitive`, `skills/AGENTS_FRONTEND_COPY_BUTTON.md`, cross-links in wallet-chip skill + `docs/README.md` **Not in this MR (by design):** wallet dropdown wiring — tracked in #185 (uses this primitive + `getExplorerAddressUrl` from #184). ### Verification checklist - [ ] `cd frontend-dapp && npm test -- --run src/utils/__tests__/copyToClipboard.test.ts src/components/ui/__tests__/CopyButton.test.tsx` — all green - [ ] Import `CopyButton` from `@/components/ui`; click copies trimmed text - [ ] Screen reader / axe: button has explicit label; live region announces "Copied to clipboard" then clears - [ ] Deny clipboard permission (or non-secure context): failure message is retail-safe (no raw DOMException) - [ ] Docs anchors resolve: `#copy-button-primitive`, agent skill links from `AGENTS_FRONTEND_WALLET_CHIP.md` @Brouie — please verify on your side when you have a moment. Leaving the issue **open** until #185 consumes the primitive in the wallet menu.
Brouie commented 2026-05-25 07:45:31 +00:00 (Migrated from gitlab.com)

qa cleared at source+test layer @PlasticDigits

verified 854d0cd9.

CopyButton.tsx — accessible button with aria-label, sr-only aria-live="polite" + aria-atomic="true" region announces success/failure, 2s reset to idle. Two variants: standalone icon + menuLabel row (role="menuitem") used by the wallet dropdown.

copyToClipboard.ts — single writeText path with trim, injectable for tests. Failure routed through COPY_BUTTON_FAILURE_MESSAGE constant (retail-safe: "Could not copy to clipboard. Check browser permissions or try again.") — no DOMException leak.

Unit tests 7/7 PASS (copyToClipboard 3 + CopyButton 4) at 854d0cd9.

Docs anchor #copy-button-primitive resolves at docs/frontend.md:121, cross-linked from AGENTS_FRONTEND_COPY_BUTTON.md and AGENTS_FRONTEND_WALLET_CHIP.md. Wallet dropdown consumer flow verified under #185.

good to close.

qa cleared at source+test layer @PlasticDigits verified `854d0cd9`. CopyButton.tsx — accessible button with aria-label, sr-only aria-live="polite" + aria-atomic="true" region announces success/failure, 2s reset to idle. Two variants: standalone icon + menuLabel row (role="menuitem") used by the wallet dropdown. copyToClipboard.ts — single writeText path with trim, injectable for tests. Failure routed through COPY_BUTTON_FAILURE_MESSAGE constant (retail-safe: "Could not copy to clipboard. Check browser permissions or try again.") — no DOMException leak. Unit tests 7/7 PASS (copyToClipboard 3 + CopyButton 4) at `854d0cd9`. Docs anchor `#copy-button-primitive` resolves at `docs/frontend.md:121`, cross-linked from AGENTS_FRONTEND_COPY_BUTTON.md and AGENTS_FRONTEND_WALLET_CHIP.md. Wallet dropdown consumer flow verified under #185. good to close.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-25 11:10:15 +00:00
PlasticDigits commented 2026-08-17 03:45:37 +00:00 (Migrated from gitlab.com)

mentioned in issue #541

mentioned in issue #541
PlasticDigits commented 2026-08-26 04:16:12 +00:00 (Migrated from gitlab.com)

mentioned in issue #665

mentioned in issue #665
PlasticDigits commented 2026-08-26 04:16:13 +00:00 (Migrated from gitlab.com)

marked as related to #665

marked as related to #665
PlasticDigits commented 2026-08-26 04:22:41 +00:00 (Migrated from gitlab.com)

mentioned in issue #671

mentioned in issue #671
PlasticDigits commented 2026-08-26 04:22:44 +00:00 (Migrated from gitlab.com)

marked as related to #671

marked as related to #671
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic#183
No description provided.