|
1 |
| -import React, { useCallback, useContext, useState } from 'react'; |
| 1 | +import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'; |
2 | 2 | import styled from 'styled-components';
|
3 | 3 | import { colors } from '../../../config.json';
|
4 | 4 | import { mediumText } from '../common-styles';
|
5 |
| -import { CellDisabledContext } from './Container'; |
| 5 | +import { CellDisabledContext, Container } from './Container'; |
6 | 6 | import StandaloneSwitch from '../Switch';
|
| 7 | +import ImageView from '../ImageView'; |
7 | 8 |
|
8 | 9 | export const Switch = React.forwardRef(function SwitchT(
|
9 | 10 | props: StandaloneSwitch['props'],
|
@@ -183,3 +184,141 @@ export function AutoSizingTextInput({ onChangeValue, ...otherProps }: IInputProp
|
183 | 184 | </StyledAutoSizingTextInputContainer>
|
184 | 185 | );
|
185 | 186 | }
|
| 187 | + |
| 188 | +const StyledCellInputRowContainer = styled(Container)({ |
| 189 | + backgroundColor: 'white', |
| 190 | + marginBottom: '1px', |
| 191 | +}); |
| 192 | + |
| 193 | +const StyledSubmitButton = styled.button({ |
| 194 | + border: 'none', |
| 195 | + backgroundColor: 'transparent', |
| 196 | + padding: '14px 0', |
| 197 | +}); |
| 198 | + |
| 199 | +const StyledInputWrapper = styled.div({}, (props: { marginLeft: number }) => ({ |
| 200 | + position: 'relative', |
| 201 | + flex: 1, |
| 202 | + width: '171px', |
| 203 | + marginLeft: props.marginLeft + 'px', |
| 204 | + marginRight: '25px', |
| 205 | + lineHeight: '24px', |
| 206 | + minHeight: '24px', |
| 207 | + fontFamily: 'Open Sans', |
| 208 | + fontWeight: 'normal', |
| 209 | + fontSize: '16px', |
| 210 | + padding: '14px 0', |
| 211 | + maxWidth: '100%', |
| 212 | +})); |
| 213 | + |
| 214 | +const StyledTextArea = styled.textarea({}, (props: { invalid?: boolean }) => ({ |
| 215 | + position: 'absolute', |
| 216 | + top: 0, |
| 217 | + left: 0, |
| 218 | + width: '100%', |
| 219 | + height: '100%', |
| 220 | + backgroundColor: 'transparent', |
| 221 | + border: 'none', |
| 222 | + flex: 1, |
| 223 | + lineHeight: '24px', |
| 224 | + fontFamily: 'Open Sans', |
| 225 | + fontWeight: 'normal', |
| 226 | + fontSize: '16px', |
| 227 | + resize: 'none', |
| 228 | + padding: '14px 0', |
| 229 | + color: props.invalid ? colors.red : 'auto', |
| 230 | +})); |
| 231 | + |
| 232 | +const StyledInputFiller = styled.div({ |
| 233 | + whiteSpace: 'pre-wrap', |
| 234 | + overflowWrap: 'break-word', |
| 235 | + minHeight: '24px', |
| 236 | + color: 'transparent', |
| 237 | +}); |
| 238 | + |
| 239 | +interface IRowInputProps { |
| 240 | + onChange?: (value: string) => void; |
| 241 | + onSubmit: (value: string) => void; |
| 242 | + onFocus?: (event: React.FocusEvent<HTMLTextAreaElement>) => void; |
| 243 | + onBlur?: (event?: React.FocusEvent<HTMLTextAreaElement>) => void; |
| 244 | + paddingLeft?: number; |
| 245 | + invalid?: boolean; |
| 246 | + autofocus?: boolean; |
| 247 | +} |
| 248 | + |
| 249 | +export function RowInput(props: IRowInputProps) { |
| 250 | + const [value, setValue] = useState(''); |
| 251 | + const textAreaRef = useRef() as React.RefObject<HTMLTextAreaElement>; |
| 252 | + |
| 253 | + const submit = useCallback(() => props.onSubmit(value), [props.onSubmit, value]); |
| 254 | + const onChange = useCallback( |
| 255 | + (event: React.ChangeEvent<HTMLTextAreaElement>) => { |
| 256 | + const value = event.target.value; |
| 257 | + setValue(value); |
| 258 | + props.onChange?.(value); |
| 259 | + }, |
| 260 | + [props.onChange], |
| 261 | + ); |
| 262 | + const onKeyDown = useCallback( |
| 263 | + (event: React.KeyboardEvent<HTMLTextAreaElement>) => { |
| 264 | + if (event.key === 'Enter') { |
| 265 | + event.preventDefault(); |
| 266 | + submit(); |
| 267 | + } |
| 268 | + }, |
| 269 | + [submit], |
| 270 | + ); |
| 271 | + |
| 272 | + const globalKeyListener = useCallback( |
| 273 | + (event: KeyboardEvent) => { |
| 274 | + if (event.key === 'Escape') { |
| 275 | + event.stopPropagation(); |
| 276 | + props.onBlur?.(); |
| 277 | + } |
| 278 | + }, |
| 279 | + [props.onBlur], |
| 280 | + ); |
| 281 | + |
| 282 | + useEffect(() => { |
| 283 | + if (props.autofocus) { |
| 284 | + textAreaRef.current?.focus(); |
| 285 | + } |
| 286 | + }, []); |
| 287 | + |
| 288 | + useEffect(() => { |
| 289 | + if (props.invalid) { |
| 290 | + textAreaRef.current?.focus(); |
| 291 | + } |
| 292 | + }, [props.invalid]); |
| 293 | + |
| 294 | + useEffect(() => { |
| 295 | + document.addEventListener('keydown', globalKeyListener, true); |
| 296 | + return () => document.removeEventListener('keydown', globalKeyListener, true); |
| 297 | + }, []); |
| 298 | + |
| 299 | + return ( |
| 300 | + <StyledCellInputRowContainer> |
| 301 | + <StyledInputWrapper marginLeft={props.paddingLeft ?? 0}> |
| 302 | + <StyledInputFiller>{value}</StyledInputFiller> |
| 303 | + <StyledTextArea |
| 304 | + ref={textAreaRef} |
| 305 | + onChange={onChange} |
| 306 | + onKeyDown={onKeyDown} |
| 307 | + rows={1} |
| 308 | + value={value} |
| 309 | + invalid={props.invalid} |
| 310 | + onFocus={props.onFocus} |
| 311 | + onBlur={props.onBlur} |
| 312 | + /> |
| 313 | + </StyledInputWrapper> |
| 314 | + <StyledSubmitButton onClick={submit}> |
| 315 | + <ImageView |
| 316 | + source="icon-tick" |
| 317 | + height={22} |
| 318 | + tintColor={colors.green} |
| 319 | + tintHoverColor={colors.green90} |
| 320 | + /> |
| 321 | + </StyledSubmitButton> |
| 322 | + </StyledCellInputRowContainer> |
| 323 | + ); |
| 324 | +} |
0 commit comments