aboutsummaryrefslogtreecommitdiffstats
path: root/webui/src/components/CommentInput/CommentInput.tsx
blob: babd495ca834fecc8ae7cc65861eab3e61ce62ae (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import React, { useState, useEffect } from 'react';

import { Typography } from '@material-ui/core';
import Tab from '@material-ui/core/Tab';
import Tabs from '@material-ui/core/Tabs';
import TextField from '@material-ui/core/TextField';
import { makeStyles } from '@material-ui/core/styles';

import Content from '../Content';

/**
 * Styles
 */
const useStyles = makeStyles((theme) => ({
  container: {
    margin: theme.spacing(2, 0),
    padding: theme.spacing(0, 2, 2, 2),
  },
  textarea: {
    '& textarea.MuiInputBase-input': {
      resize: 'vertical',
    },
  },
  tabContent: {
    margin: theme.spacing(2, 0),
  },
  preview: {
    overflow: 'auto',
    borderBottom: `solid 3px ${theme.palette.grey['200']}`,
    minHeight: '5rem',
  },
  previewPlaceholder: {
    color: theme.palette.text.secondary,
    fontStyle: 'italic',
  },
}));

type TabPanelProps = {
  children: React.ReactNode;
  value: number;
  index: number;
} & React.HTMLProps<HTMLDivElement>;
function TabPanel({ children, value, index, ...props }: TabPanelProps) {
  return (
    <div
      role="tabpanel"
      hidden={value !== index}
      id={`editor-tabpanel-${index}`}
      aria-labelledby={`editor-tab-${index}`}
      {...props}
    >
      {value === index && children}
    </div>
  );
}

const a11yProps = (index: number) => ({
  id: `editor-tab-${index}`,
  'aria-controls': `editor-tabpanel-${index}`,
});

type Props = {
  inputProps?: any;
  inputText?: string;
  loading: boolean;
  onChange: (comment: string) => void;
};

/**
 * Component for issue comment input
 *
 * @param inputProps Reset input value
 * @param loading Disable input when component not ready yet
 * @param onChange Callback to return input value changes
 */
function CommentInput({ inputProps, inputText, loading, onChange }: Props) {
  const [input, setInput] = useState<string>(inputText ? inputText : '');
  const [tab, setTab] = useState(0);
  const classes = useStyles();

  useEffect(() => {
    if (inputProps) setInput(inputProps.value);
  }, [inputProps]);

  useEffect(() => {
    onChange(input);
  }, [input, onChange]);

  return (
    <div>
      <Tabs value={tab} onChange={(_, t) => setTab(t)}>
        <Tab label="Write" {...a11yProps(0)} />
        <Tab label="Preview" {...a11yProps(1)} />
      </Tabs>
      <div className={classes.tabContent}>
        <TabPanel value={tab} index={0}>
          <TextField
            fullWidth
            label="Comment"
            placeholder="Leave a comment"
            className={classes.textarea}
            multiline
            value={input}
            variant="filled"
            rows="4" // TODO: rowsMin support
            onChange={(e: any) => setInput(e.target.value)}
            disabled={loading}
          />
        </TabPanel>
        <TabPanel value={tab} index={1} className={classes.preview}>
          {input !== '' ? (
            <Content markdown={input} />
          ) : (
            <Typography className={classes.previewPlaceholder}>
              Nothing to preview.
            </Typography>
          )}
        </TabPanel>
      </div>
    </div>
  );
}

export default CommentInput;