PluginProbe
Extendify / 1.9.0
Extendify v1.9.0
3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 0.7.0 All 126 releases
extendify / src / Draft / components / DynamicTextarea.js

DynamicTextarea.js in Extendify 1.9.0, at src/Draft/components/DynamicTextarea.js

92 lines 2.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import {
2 useLayoutEffect,
3 useEffect,
4 useRef,
5 useState,
6 } from '@wordpress/element'
7 import { motion, AnimatePresence } from 'framer-motion'
8
9 export const DynamicTextarea = ({
10 value,
11 className,
12 onChange,
13 onKeyDown,
14 disabled,
15 placeholder,
16 }) => {
17 const ref = useRef(null)
18 const [height, setHeight] = useState('auto')
19
20 // Dynamically resize the input by creating a temporary version and measuring the height.
21 // This is a workaround for scrollHeight not reducing when text is deleted.
22 useLayoutEffect(() => {
23 const tempTextarea = document.createElement('textarea')
24 tempTextarea.value = value || placeholder
25 tempTextarea.rows = 1 // Start at 1
26
27 const styleProps = [
28 'paddingTop',
29 'paddingBottom',
30 'paddingLeft',
31 'paddingRight',
32 'width',
33 'fontFamily',
34 'fontSize',
35 'borderWidth',
36 ]
37
38 const styles = window.getComputedStyle(ref.current)
39
40 // apply styles to the temporary textarea
41 styleProps.forEach((prop) => (tempTextarea.style[prop] = styles[prop]))
42
43 Object.assign(tempTextarea.style, {
44 position: 'absolute',
45 left: '-9999px',
46 })
47
48 document.body.appendChild(tempTextarea)
49 setHeight(`${tempTextarea.scrollHeight}px`)
50 document.body.removeChild(tempTextarea)
51 }, [value, placeholder])
52
53 // Focus the input.
54 useEffect(() => {
55 const input = ref.current
56 if (!input) return
57 if (document.activeElement === input) return
58
59 const inputLength = input.value.length
60 input.focus()
61 input.setSelectionRange(inputLength, inputLength) // Place cursor at the end of the input.
62 }, [value])
63
64 return (
65 <AnimatePresence>
66 <motion.div
67 key="input"
68 animate={{ height }}
69 transition={{ duration: 0.2 }}
70 style={{ lineHeight: 0 }}>
71 <label htmlFor="draft-ai-textarea" className="sr-only">
72 {placeholder}
73 </label>
74 <textarea
75 ref={ref}
76 id="draft-ai-textarea"
77 disabled={disabled}
78 className={className}
79 value={value}
80 rows={1}
81 onChange={onChange}
82 onKeyDown={onKeyDown}
83 onScroll={(event) => {
84 event.target.scrollTop = 0
85 }}
86 placeholder={placeholder}
87 />
88 </motion.div>
89 </AnimatePresence>
90 )
91 }
92