main
js 101 lines 2.39 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow
8 */
9
10 import * as React from 'react';
11 import {useCallback, useState} from 'react';
12 import AutoSizeInput from './NativeStyleEditor/AutoSizeInput';
13 import styles from './EditableName.css';
14
15 type Type = 'props' | 'state' | 'context' | 'hooks';
16 type OverrideNameFn = (
17 oldName: Array<string | number>,
18 newName: Array<string | number>,
19 ) => void;
20
21 type EditableNameProps = {
22 allowEmpty?: boolean,
23 allowWhiteSpace?: boolean,
24 autoFocus?: boolean,
25 className?: string,
26 initialValue?: string,
27 overrideName: OverrideNameFn,
28 path: Array<string | number>,
29 type: Type,
30 };
31
32 export default function EditableName({
33 allowEmpty = false,
34 allowWhiteSpace = false,
35 autoFocus = false,
36 className = '',
37 initialValue = '',
38 overrideName,
39 path,
40 type,
41 }: EditableNameProps): React.Node {
42 const [editableName, setEditableName] = useState(initialValue);
43 const [isValid, setIsValid] = useState(false);
44
45 const handleChange = useCallback(
46 ({target}: $FlowFixMe) => {
47 let value = target.value;
48 if (!allowWhiteSpace) {
49 value = value.trim();
50 }
51
52 if (allowEmpty || value !== '') {
53 setIsValid(true);
54 } else {
55 setIsValid(false);
56 }
57
58 setEditableName(value);
59 },
60 [overrideName],
61 );
62
63 const handleKeyDown = useCallback(
64 (event: $FlowFixMe) => {
65 // Prevent keydown events from e.g. change selected element in the tree
66 event.stopPropagation();
67
68 switch (event.key) {
69 case 'Enter':
70 case 'Tab':
71 if (isValid) {
72 const basePath = path.slice(0, path.length - 1);
73 overrideName(
74 [...basePath, initialValue],
75 [...basePath, editableName],
76 );
77 }
78 break;
79 case 'Escape':
80 setEditableName(initialValue);
81 break;
82 default:
83 break;
84 }
85 },
86 [editableName, setEditableName, isValid, initialValue, overrideName],
87 );
88
89 return (
90 <AutoSizeInput
91 autoFocus={autoFocus}
92 className={[styles.Input, className].join(' ')}
93 onChange={handleChange}
94 onKeyDown={handleKeyDown}
95 placeholder="new entry"
96 testName="EditableName"
97 type="text"
98 value={editableName}
99 />
100 );
101 }