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

Code before:
      setUserInput(newVal)
    },
    onKeyDown = (e: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => { if (e.key === 'Enter') submit() },
    submit = () => {
      if (!userInput.trim()) return
      setMsgs([...msgs, { msg: userInput, fromUser: true }])
      wave.push()
      setUserInput('')
    }

  React.useEffect(() => {
    if (msgContainerRef.current) msgContainerRef.current.scrollTo({ top: msgContainerRef.current.scrollHeight, behavior: 'smooth' })
  }, [msgs])
  React.useEffect(() => { if (model.data) setMsgs(model.data as ChatMessage[]) }, [model.data])

  return (
    <div className={css.chatWindow}>
      <div className={css.msgContainer} ref={msgContainerRef}>
        {msgs.map(({ msg, fromUser }, idx) => (
          <div
            key={idx}
            className={clas(css.msgWrapper, fromUser ? css.userMsg : '')}
            style={{
              paddingTop: msgs[idx - 1]?.fromUser !== fromUser ? rem(0.7) : 0,
              paddingBottom: msgs?.[idx + 1]?.fromUser !== fromUser ? rem(0.85) : 0,
              color: cssVar(fromUser ? '$neutralDark' : '$themePrimary')
            }} >
            <div
              className={clas(css.msg, 'wave-s14')}
              style={{ padding: msg?.includes('\n') ? 12 : 6 }}>
              <span className={css.text}>
                <Markdown source={msg || ''} />
              </span>
            </div>
          </div>
        ))}
      </div>
      <div className={css.textInput}>
        <Fluent.TextField
          data-test={model.name}
          value={userInput}
          onChange={onChange}
          onKeyDown={onKeyDown}
          autoComplete='off'
          placeholder={model.placeholder || 'Type your message'}
          styles={{ root: { flexGrow: 1 }, field: { width: `calc(100% - ${SUBMIT_BTN_SIZE}px)`, paddingRight: 0 } }}
        />
        <Fluent.IconButton
          data-test={`${model.name}-submit`}
          iconProps={{ iconName: 'Send' }}
          onClick={submit}

Review comment (suggestion):
Let's stick with a single text color that is easy to read. I would maybe even consider using `getContrast` function to be sure the text is properly visible in all cases.
```suggestion
              color: cssVar('$neutralDark')
```

Code after:
      setMsgs([...msgs, { msg: userInput, fromUser: true }])
      wave.push()
      setUserInput('')
    }

  React.useEffect(() => {
    if (!msgContainerRef.current) return
    const offsetTop = msgContainerRef.current.scrollHeight
    if (msgContainerRef.current?.scrollTo) msgContainerRef.current.scrollTo({ top: offsetTop, behavior: 'smooth' })
    else msgContainerRef.current.scrollTop = offsetTop
  }, [msgs])
  React.useEffect(() => { if (model.data) setMsgs(model.data as ChatMessage[]) }, [model.data])

  return (
    <div className={css.chatWindow}>
      <div className={css.msgContainer} ref={msgContainerRef}>
        {msgs.map(({ msg, fromUser }, idx) => (
          <div
            key={idx}
            className={clas(css.msgWrapper, fromUser ? '' : css.botMsg)}
            style={{
              paddingTop: msgs[idx - 1]?.fromUser !== fromUser ? rem(0.8) : 0,
              paddingBottom: msgs?.[idx + 1]?.fromUser !== fromUser ? rem(0.8) : 0,
              color: fromUser ? '$text' : botTextColor
            }} >
            <span
              className={clas(css.msg, 'wave-s14')}
              style={{ padding: msg?.includes('\n') ? 12 : 6 }}>
              <Markdown source={msg || ''} />
            </span>
          </div>
        ))}
      </div>
      <div className={css.textInput}>
        <Fluent.TextField
          data-test={model.name}
          value={userInput}
          onChange={onChange}
          onKeyDown={onKeyDown}
          autoComplete='off'
          placeholder={model.placeholder || 'Type your message'}
          styles={{ root: { flexGrow: 1 }, field: { width: `calc(100% - ${SUBMIT_BTN_SIZE}px)`, paddingRight: 0 } }}
        />
        <Fluent.IconButton
          data-test={`${model.name}-submit`}
          iconProps={{ iconName: 'Send' }}
          onClick={submit}
          disabled={!userInput.trim()}
          styles={{
            root: { position: 'absolute', top: 15, right: 15, height: SUBMIT_BTN_SIZE },
            rootHovered: { backgroundColor: 'transparent' },