Files
modeling-app/src/components/CommandBar/CommandBarTextareaInput.tsx
Frank Noirot 0c2a0a8c07 Add toolbar buttons for text-to-cad and prompt-to-edit (#4938)
* Add toolbar buttons for text-to-cad and prompt-to-edit
Resolves #4890

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-macos-8-cores)

* `preventDefault` on <kbd>Enter</kbd> with textarea input so buttons aren't clicked as well

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Pierre Jacquier <pierre@zoo.dev>
2025-01-07 16:45:30 +00:00

115 lines
3.7 KiB
TypeScript

import { useCommandsContext } from 'hooks/useCommandsContext'
import { CommandArgument } from 'lib/commandTypes'
import { RefObject, useEffect, useRef } from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
function CommandBarTextareaInput({
arg,
stepBack,
onSubmit,
}: {
arg: CommandArgument<unknown> & {
inputType: 'text'
name: string
}
stepBack: () => void
onSubmit: (event: unknown) => void
}) {
const { commandBarSend, commandBarState } = useCommandsContext()
useHotkeys('mod + k, mod + /', () => commandBarSend({ type: 'Close' }))
const formRef = useRef<HTMLFormElement>(null)
const inputRef = useRef<HTMLTextAreaElement>(null)
useTextareaAutoGrow(inputRef)
useEffect(() => {
if (inputRef.current) {
inputRef.current.focus()
inputRef.current.select()
}
}, [arg, inputRef])
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault()
onSubmit(inputRef.current?.value)
}
return (
<form id="arg-form" onSubmit={handleSubmit} ref={formRef}>
<label className="flex items-start rounded mx-4 my-4 border border-chalkboard-100 dark:border-chalkboard-80">
<span
data-testid="cmd-bar-arg-name"
className="capitalize px-2 py-1 rounded-br bg-chalkboard-100 dark:bg-chalkboard-80 text-chalkboard-10 border-b border-b-chalkboard-100 dark:border-b-chalkboard-80"
>
{arg.name}
</span>
<textarea
data-testid="cmd-bar-arg-value"
id="arg-form"
name={arg.inputType}
ref={inputRef}
required
className="flex-grow mx-2 my-1 !bg-transparent focus:outline-none min-h-12"
placeholder="Enter a value"
defaultValue={
(commandBarState.context.argumentsToSubmit[arg.name] as
| string
| undefined) || (arg.defaultValue as string)
}
onKeyDown={(event) => {
if (event.key === 'Backspace' && !event.currentTarget.value) {
stepBack()
} else if (
event.key === 'Enter' &&
(event.metaKey || event.shiftKey)
) {
// Insert a newline
event.preventDefault()
const target = event.currentTarget
const value = target.value
const selectionStart = target.selectionStart
const selectionEnd = target.selectionEnd
target.value =
value.substring(0, selectionStart) +
'\n' +
value.substring(selectionEnd)
target.selectionStart = selectionStart + 1
target.selectionEnd = selectionStart + 1
} else if (event.key === 'Enter') {
event.preventDefault()
formRef.current?.dispatchEvent(
new Event('submit', { bubbles: true })
)
}
}}
autoFocus
/>
</label>
</form>
)
}
/**
* Modified from https://www.reddit.com/r/reactjs/comments/twmild/comment/i3jf330/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
* Thank you to @sidkh for the original code
*/
const useTextareaAutoGrow = (ref: RefObject<HTMLTextAreaElement>) => {
useEffect(() => {
const listener = () => {
if (ref.current === null) return
ref.current.style.padding = '0px'
ref.current.style.height = ref.current.scrollHeight + 'px'
ref.current.style.removeProperty('padding')
}
if (ref.current === null) return
ref.current.addEventListener('input', listener)
return () => {
if (ref.current === null) return
ref.current.removeEventListener('input', listener)
}
}, [ref.current])
}
export default CommandBarTextareaInput