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

Code before:
    height: 24
  },
  copiedBtn: {
    background: cssVar('$green'),
    $nest: {
      '&:hover': {
        background: cssVar('$green'),
      }
    }
  }
})

/**
 * Create a copyable text component.
 * Use this component when you want to enable your users to quickly copy paste sections of text.
*/
export interface CopyableText {
  /** Text to be displayed inside the component. */
  value: S
  /** The text displayed above the textbox. */
  label: S
  /** An identifying name for this component. */
  name?: S
  /** True if the component should allow multi-line text entry. */
  multiline?: B
  /** Custom height in px (e.g. '200px') or use '1' to fill the remaining card space. Requires `multiline` to be set. */
  height?: S
}

export const XCopyableText = ({ model }: { model: CopyableText }) => {
  const
    { name, multiline, label, value, height } = model,
    isHeight = multiline && height,
    fullHeightStyle = isHeight && height === '1' ? css.fullHeight : '',
    ref = React.useRef<Fluent.ITextField>(null),
    timeoutRef = React.useRef<U>(),
    [copied, setCopied] = React.useState(false),
    onClick = async () => {
      const el = ref.current
      if (!el) return
      try {
        if (document.queryCommandSupported('copy')) {
          el.select()
          document.execCommand('copy')
          window.getSelection()?.removeAllRanges()
        }
      } catch (error) {
        await window.navigator.clipboard.writeText(value)
      }

      setCopied(true)

Review comment (suggestion):
```suggestion
  /** Custom height in px (e.g. '200px') or '1' to fill the remaining card space. Requires `multiline` to be set. */
```

Code after:
  }),
  fullHeightStyle = {
    display: 'flex',
    flexGrow: 1,
    flexDirection: 'column',
  }

/**
 * Create a copyable text component.
 * Use this component when you want to enable your users to quickly copy paste sections of text.
*/
export interface CopyableText {
  /** Text to be displayed inside the component. */
  value: S
  /** The text displayed above the textbox. */
  label: S
  /** An identifying name for this component. */
  name?: S
  /** True if the component should allow multi-line text entry. */
  multiline?: B
  /** Custom height in px (e.g. '200px') or '1' to fill the remaining card space. Requires `multiline` to be set. */
  height?: S
}

export const XCopyableText = ({ model }: { model: CopyableText }) => {
  const
    { name, multiline, label, value, height } = model,
    heightStyle = multiline && height === '1' ? fullHeightStyle : undefined,
    ref = React.useRef<Fluent.ITextField>(null),
    timeoutRef = React.useRef<U>(),
    [copied, setCopied] = React.useState(false),
    onClick = async () => {
      const el = ref.current
      if (!el) return
      try {
        if (document.queryCommandSupported('copy')) {
          el.select()
          document.execCommand('copy')
          window.getSelection()?.removeAllRanges()
        }
      } catch (error) {
        await window.navigator.clipboard.writeText(value)
      }

      setCopied(true)
      timeoutRef.current = window.setTimeout(() => setCopied(false), 2000)
    }

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

  return (