2
0
Files
bot/apps/builder/components/shared/TextboxWithVariableButton/TextboxWithVariableButton.tsx

116 lines
3.2 KiB
TypeScript
Raw Normal View History

import {
ComponentWithAs,
2022-01-22 18:24:57 +01:00
Flex,
HStack,
IconButton,
InputProps,
Popover,
PopoverContent,
PopoverTrigger,
TextareaProps,
2022-01-22 18:24:57 +01:00
Tooltip,
} from '@chakra-ui/react'
import { UserIcon } from 'assets/icons'
import { Variable } from 'models'
import React, { useEffect, useRef, useState } from 'react'
import { useDebounce } from 'use-debounce'
import { VariableSearchInput } from '../VariableSearchInput'
export type TextBoxWithVariableButtonProps = {
initialValue: string
onChange: (value: string) => void
delay?: number
TextBox:
| ComponentWithAs<'textarea', TextareaProps>
| ComponentWithAs<'input', InputProps>
} & Omit<InputProps & TextareaProps, 'onChange'>
export const TextBoxWithVariableButton = ({
initialValue,
onChange,
delay,
TextBox,
...props
}: TextBoxWithVariableButtonProps) => {
const textBoxRef = useRef<(HTMLInputElement & HTMLTextAreaElement) | null>(
null
)
const [value, setValue] = useState(initialValue)
const [debouncedValue] = useDebounce(value, delay ?? 100)
const [carretPosition, setCarretPosition] = useState<number>(0)
useEffect(() => {
2022-01-22 18:24:57 +01:00
if (debouncedValue !== initialValue) onChange(debouncedValue)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [debouncedValue])
2022-01-22 18:24:57 +01:00
const handleVariableSelected = (variable?: Variable) => {
if (!textBoxRef.current || !variable) return
const cursorPosition = carretPosition
const textBeforeCursorPosition = textBoxRef.current.value.substring(
0,
cursorPosition
)
const textAfterCursorPosition = textBoxRef.current.value.substring(
cursorPosition,
textBoxRef.current.value.length
)
setValue(
textBeforeCursorPosition +
`{{${variable.name}}}` +
textAfterCursorPosition
)
textBoxRef.current.focus()
setTimeout(() => {
if (!textBoxRef.current) return
textBoxRef.current.selectionStart = textBoxRef.current.selectionEnd =
carretPosition + `{{${variable.name}}}`.length
setCarretPosition(textBoxRef.current.selectionStart)
}, 100)
}
const handleKeyUp = () => {
if (!textBoxRef.current?.selectionStart) return
setCarretPosition(textBoxRef.current.selectionStart)
}
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => setValue(e.target.value)
return (
<HStack spacing={0} align={'flex-end'}>
<TextBox
ref={textBoxRef}
onKeyUp={handleKeyUp}
onClick={handleKeyUp}
value={value}
onChange={handleChange}
bgColor={'white'}
{...props}
/>
<Popover matchWidth isLazy>
<PopoverTrigger>
2022-01-22 18:24:57 +01:00
<Flex>
<Tooltip label="Insert a variable">
<IconButton
aria-label="Insert a variable"
icon={<UserIcon />}
pos="relative"
/>
</Tooltip>
</Flex>
</PopoverTrigger>
<PopoverContent w="full">
<VariableSearchInput
onSelectVariable={handleVariableSelected}
placeholder="Search for a variable"
shadow="lg"
isDefaultOpen
/>
</PopoverContent>
</Popover>
</HStack>
)
}