@@ -4,7 +4,9 @@ import _isEmpty from "lodash/isEmpty";
44import _isObject from "lodash/isObject" ;
55import _map from "lodash/map" ;
66import _truncate from "lodash/truncate" ;
7- import { FormattedMessage } from "react-intl" ;
7+ import { useState } from "react" ;
8+ import { CopyToClipboard } from "react-copy-to-clipboard" ;
9+ import { FormattedMessage , useIntl } from "react-intl" ;
810import { valueOrExternalLink } from "../../../utils/linkUtils" ;
911import SvgSymbol from "../../SvgSymbol/SvgSymbol" ;
1012import messages from "./Messages" ;
@@ -18,18 +20,61 @@ const PropertyList = (props) => {
1820 // Default is lightMode -- only do darkMode if the value is present and false
1921 const darkMode = props . lightMode === false ;
2022 const tagInfo = window . env . REACT_APP_TAGINFO_SERVER_URL ;
23+ const intl = useIntl ( ) ;
24+ const [ copied , setCopied ] = useState ( false ) ;
25+
26+ const EXCLUDED_KEYS = new Set ( [ "@id" , "osmid" ] ) ;
27+ const MAX_VALUE_LENGTH = 255 ;
28+
29+ const copyableTagText = ( ) => {
30+ if ( _isEmpty ( props . featureProperties ) ) return "" ;
31+ return Object . entries ( props . featureProperties )
32+ . filter (
33+ ( [ key , value ] ) =>
34+ ! _isObject ( value ) && ! EXCLUDED_KEYS . has ( key ) && String ( value ) . length <= MAX_VALUE_LENGTH ,
35+ )
36+ . map ( ( [ key , value ] ) => `${ key } =${ value } ` )
37+ . join ( "\n" ) ;
38+ } ;
39+
40+ const handleCopy = ( ) => {
41+ setCopied ( true ) ;
42+ setTimeout ( ( ) => setCopied ( false ) , 1500 ) ;
43+ } ;
44+
2145 const header = (
22- < h3 className = "mr-flex mr-items-center" >
23- { props . onBack && (
24- < a onClick = { props . onBack } className = "mr-mr-4" >
25- < SvgSymbol
26- sym = "icon-cheveron-left"
27- viewBox = "0 0 20 20"
28- className = "mr-fill-current mr-w-6 mr-h-6"
29- />
30- </ a >
46+ < h3 className = "mr-flex mr-items-center mr-justify-between" >
47+ < span className = "mr-flex mr-items-center" >
48+ { props . onBack && (
49+ < a onClick = { props . onBack } className = "mr-mr-4" >
50+ < SvgSymbol
51+ sym = "icon-cheveron-left"
52+ viewBox = "0 0 20 20"
53+ className = "mr-fill-current mr-w-6 mr-h-6"
54+ />
55+ </ a >
56+ ) }
57+ { props . header ? props . header : < FormattedMessage { ...messages . title } /> }
58+ </ span >
59+ { ! _isEmpty ( props . featureProperties ) && (
60+ < CopyToClipboard text = { copyableTagText ( ) } onCopy = { handleCopy } >
61+ < button
62+ className = { classNames (
63+ "mr-ml-2" ,
64+ darkMode
65+ ? "mr-text-green-lighter hover:mr-text-white"
66+ : "mr-text-grey hover:mr-text-green-dark" ,
67+ ) }
68+ title = { intl . formatMessage ( messages . copyTagsTooltip ) }
69+ >
70+ < SvgSymbol
71+ sym = { copied ? "check-icon" : "clipboard-icon" }
72+ viewBox = "0 0 20 20"
73+ className = "mr-fill-current mr-w-4 mr-h-4"
74+ />
75+ </ button >
76+ </ CopyToClipboard >
3177 ) }
32- { props . header ? props . header : < FormattedMessage { ...messages . title } /> }
3378 </ h3 >
3479 ) ;
3580
0 commit comments