Repository: h2oai/wave
File: ui/src/copyable_text.tsx (TypeScript)

Code before:
          (anchorElement as any)?.select()
          document.execCommand('copy')
          window.getSelection()?.removeAllRanges()
        }
      } catch (error) {
        await window.navigator.clipboard.writeText(value)
      }

      setCopied(true)
      timeoutRef.current = window.setTimeout(() => setCopied(false), 2000)
    }, [anchorElement, value])

  React.useEffect(() => {
    if (anchorElement && showOnHoverOnly) {
      anchorElement.addEventListener('mouseenter', () => setVisible(true))
      anchorElement.addEventListener('mouseleave', (ev: MouseEvent) => {
        if ((ev.relatedTarget as HTMLElement)?.id === 'copybutton') return
        setVisible(false)
      })
    }
  }, [anchorElement, showOnHoverOnly])

  React.useEffect(() => () => window.clearTimeout(timeoutRef.current), [])

  return <Fluent.PrimaryButton
    id='copybutton'
    title='Copy to clipboard'
    onClick={onClick}
    iconProps={{ iconName: copied ? 'CheckMark' : 'Copy' }}
    className={clas(css.btn, copied ? css.copiedBtn : '', showOnHoverOnly ? css.animate : '', visible ? css.visible : '')}
  />
}

export const XCopyableText = ({ model }: { model: CopyableText }) => {
  const
    { name, multiline, label, value, height } = model,
    heightStyle = multiline && height === '1' ? fullHeightStyle : undefined,
    [inputEl, setInputEl] = React.useState(),
    domRef = React.useCallback(node => {
      const inputEl = node?.children[0]?.children[1]
      if (inputEl) setInputEl(inputEl)
    }, [])

  return (
    <Fluent.TextField
      data-test={name}
      // Temporary solution which will be replaced with 'ref' once Fluent.TextField is converted to a function component.
      elementRef={domRef}
      value={value}
      multiline={multiline}
      onRenderLabel={() =>

Review comment (suggestion):
I assume this `id` is unnecessary as well. But even if wasn't, ids need to be unique and cannot be hardcoded if there is a chance there are going to be more than 1 instances of the component, like here.

Code after:
        iconName: copied ? 'CheckMark' : 'Copy',
        styles: { root: { marginTop: -1.35 } } // Nudge up the icon a bit to account for incorrect Fluent crop.
      }}
      className={clas(css.btn, copied ? css.copiedBtn : '')}
    />
  )
}

export const XCopyableText = ({ model }: { model: CopyableText }) => {
  const
    { name, multiline, label, value, height } = model,
    heightStyle = multiline && height === '1' ? fullHeightStyle : undefined

  return (
    <Fluent.TextField
      data-test={name}
      value={value}
      multiline={multiline}
      onRenderLabel={() =>
        <div className={css.labelContainer}>
          <Fluent.Label>{label}</Fluent.Label>
          <ClipboardCopyButton value={value} />
        </div>
      }
      styles={{
        root: {
          ...heightStyle,
          textFieldRoot: { position: 'relative', width: pc(100) },
          textFieldMultiline: multiline ? { '& button': { opacity: 0 }, '&:hover button': { opacity: 1 } } : undefined
        },
        wrapper: heightStyle,
        fieldGroup: heightStyle || { minHeight: height },
        field: { ...heightStyle, height, resize: multiline ? 'vertical' : 'none', },
      }}
      readOnly
    />
  )
}