PluginProbe ʕ •ᴥ•ʔ
Presto Player / 4.5.0
Presto Player v4.5.0
4.5.0 4.4.1 4.4.0 4.3.3 4.3.2 4.3.1 4.3.0 4.2.4 4.2.3 4.2.2 4.2.0 4.2.1 trunk 1.10.0 1.10.1 1.10.2 1.11.0 1.12.0 1.13.0 1.14.0 1.14.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.14 1.5.15 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.10 1.6.11 1.6.12 1.6.13 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.16 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.2.0 2.2.1 2.2.2 2.2.3 2.2.3-beta1 2.3.0 2.3.1 2.3.2 2.3.3 3.0.0 3.0.0-beta1 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.1.0 3.1.1 3.1.2 3.1.3 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4
presto-player / src / admin / dashboard / pages / settings / general / components / CopyButton.js
presto-player / src / admin / dashboard / pages / settings / general / components Last commit date
AbilitiesList.js 2 weeks ago AdvancedDisclosure.js 2 weeks ago ClaudeConnect.js 2 weeks ago ConnectWizard.js 2 weeks ago CopyButton.js 2 weeks ago LinkButton.js 2 weeks ago McpAdapterRequiredNote.js 2 weeks ago
CopyButton.js
101 lines
1 import { __ } from '@wordpress/i18n';
2 import { useCallback, useEffect, useRef, useState } from 'react';
3 import { Button } from '@bsf/force-ui';
4 import { Check, Copy, X } from 'lucide-react';
5
6 const legacyCopy = ( text ) => {
7 const textarea = document.createElement( 'textarea' );
8 textarea.value = text;
9 textarea.style.position = 'fixed';
10 textarea.style.opacity = '0';
11 document.body.appendChild( textarea );
12 textarea.select();
13 let ok = false;
14 try {
15 ok = document.execCommand( 'copy' );
16 } finally {
17 document.body.removeChild( textarea );
18 }
19 return ok;
20 };
21
22 const copyText = ( text ) => {
23 if ( window.navigator.clipboard && window.isSecureContext ) {
24 return window.navigator.clipboard.writeText( text ).catch( () => {
25 if ( ! legacyCopy( text ) ) {
26 throw new Error( 'copy-failed' );
27 }
28 } );
29 }
30 if ( ! legacyCopy( text ) ) {
31 return Promise.reject( new Error( 'copy-failed' ) );
32 }
33 return Promise.resolve();
34 };
35
36 /**
37 * Reusable copy-to-clipboard button with a transient "Copied" confirmation.
38 *
39 * @param {Object} props
40 * @param {string} props.textToCopy Text placed on the clipboard.
41 * @param {string} [props.label] Optional visible label (icon-only if absent).
42 * @param {string} [props.variant] force-ui Button variant.
43 */
44 const CopyButton = ( { textToCopy, label, variant = 'outline' } ) => {
45 const [ copied, setCopied ] = useState( false );
46 const [ failed, setFailed ] = useState( false );
47 const timerRef = useRef();
48
49 useEffect( () => () => clearTimeout( timerRef.current ), [] );
50
51 const handleCopy = useCallback( () => {
52 if ( ! textToCopy ) {
53 return;
54 }
55 copyText( textToCopy )
56 .then( () => {
57 setFailed( false );
58 setCopied( true );
59 clearTimeout( timerRef.current );
60 timerRef.current = setTimeout( () => setCopied( false ), 1500 );
61 } )
62 .catch( () => {
63 setCopied( false );
64 setFailed( true );
65 clearTimeout( timerRef.current );
66 timerRef.current = setTimeout( () => setFailed( false ), 1500 );
67 } );
68 }, [ textToCopy ] );
69
70 let icon = <Copy className="text-icon-primary size-4" />;
71 if ( copied ) {
72 icon = <Check className="text-icon-success size-4" />;
73 } else if ( failed ) {
74 icon = <X className="text-icon-error size-4" />;
75 }
76
77 let statusLabel = label || __( 'Copy to clipboard', 'presto-player' );
78 if ( copied ) {
79 statusLabel = __( 'Copied', 'presto-player' );
80 } else if ( failed ) {
81 statusLabel = __( 'Copy failed', 'presto-player' );
82 }
83
84 const buttonLabel = label ? statusLabel : null;
85
86 return (
87 <Button
88 size="md"
89 variant={ variant }
90 icon={ icon }
91 iconPosition="left"
92 onClick={ handleCopy }
93 aria-label={ statusLabel }
94 >
95 { buttonLabel }
96 </Button>
97 );
98 };
99
100 export default CopyButton;
101