forked from Sofie-Automation/sofie-core
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMultiLineTextInput.tsx
More file actions
112 lines (101 loc) · 3 KB
/
Copy pathMultiLineTextInput.tsx
File metadata and controls
112 lines (101 loc) · 3 KB
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
import { useCallback, useMemo, useState } from 'react'
import ClassNames from 'classnames'
export function splitValueIntoLines(v: string | undefined): string[] {
if (v === undefined || v.length === 0) {
return []
} else {
return v.split('\n').map((i) => i.trimStart())
}
}
export function joinLines(v: string[] | undefined): string {
if (v === undefined || v.length === 0) {
return ''
} else {
return v.join('\n')
}
}
interface IMultiLineTextInputControlProps {
classNames?: string
modifiedClassName?: string
disabled?: boolean
readOnly?: boolean
placeholder?: string
/** Call handleUpdate on every change, before focus is lost */
updateOnKey?: boolean
value: string[]
handleUpdate: (value: string[]) => void
}
export function MultiLineTextInputControl({
classNames,
modifiedClassName,
value,
disabled,
readOnly,
placeholder,
handleUpdate,
updateOnKey,
}: Readonly<IMultiLineTextInputControlProps>): JSX.Element {
const [editingValue, setEditingValue] = useState<string | null>(null)
const handleChange = useCallback(
(event: React.ChangeEvent<HTMLTextAreaElement>) => {
if (readOnly) return
setEditingValue(event.target.value)
if (updateOnKey) {
handleUpdate(splitValueIntoLines(event.target.value))
}
},
[handleUpdate, updateOnKey, readOnly]
)
const handleBlur = useCallback(
(event: React.FocusEvent<HTMLTextAreaElement>) => {
if (readOnly) return
handleUpdate(splitValueIntoLines(event.target.value))
setEditingValue(null)
},
[handleUpdate, readOnly]
)
const handleFocus = useCallback((event: React.FocusEvent<HTMLTextAreaElement>) => {
setEditingValue(event.currentTarget.value)
}, [])
const handleKeyUp = useCallback((event: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (event.key === 'Escape') {
setEditingValue(null)
}
}, [])
const handleKeyPress = useCallback((event: React.KeyboardEvent<HTMLTextAreaElement>) => {
// Suppress the default behaviour of submitting on enter press
if (event.key === 'Enter') {
event.stopPropagation()
}
}, [])
return (
<textarea
className={ClassNames('form-control', classNames, editingValue !== null && modifiedClassName)}
placeholder={placeholder}
value={editingValue ?? joinLines(value) ?? ''}
onChange={handleChange}
onBlur={handleBlur}
onFocus={handleFocus}
onKeyUp={handleKeyUp}
onKeyPress={handleKeyPress}
disabled={disabled}
readOnly={readOnly}
/>
)
}
interface ICombinedMultiLineTextInputControlProps extends Omit<
IMultiLineTextInputControlProps,
'value' | 'handleUpdate'
> {
value: string
handleUpdate: (value: string) => void
}
export function CombinedMultiLineTextInputControl({
value,
handleUpdate,
...props
}: Readonly<ICombinedMultiLineTextInputControlProps>): JSX.Element {
const valueArray = useMemo(() => splitValueIntoLines(value), [value])
const handleUpdateArray = useCallback((value: string[]) => handleUpdate(joinLines(value)), [handleUpdate])
return <MultiLineTextInputControl {...props} value={valueArray} handleUpdate={handleUpdateArray} />
}