Files
supabase/packages/ui-patterns/AssistantChat/AssistantChatForm.tsx
Jonathan Summers-Muir b8243e06d8 Feat/design system site (#26586)
* init site

* add nav menu

* add props table component

* init all the examples

• also includes moving a bunch of ./ui files to ./ui-patterns

* update package

• might need to remove some of these

* Update rehype-component.ts

* move nav

* more changes

* add new source information to contentlayer

* fix copy buttons

* add text-confirm. start new concept of "fragments"

* move base path. add homepage. add theme selection

* added colors

* add form-item-layout

* temporary fix code blocks in light mode. they currently don't switch theme to theme

* start adding code themes

* Update dark.json

* update code block themes

* fix animations

* add cdmk search

* export registry of icons in ./icons package

* add comments

* add icon copy stuff

* Update icons.tsx

* more docs

* more docs. cleaned up colors and icons docs

* Update theming.mdx

* add more docs

* update

* add package

* Update tailwind.config.js

* update content

* Update drawer-demo.tsx

* Update aspect-ratio-demo.tsx

* add new blocks

* Update source-panel.tsx

* Update source-panel.tsx

* Update source-panel.tsx

* add new source block

* Update source-panel.tsx

* Update _app.tsx

* Update page.tsx

* Delete layout-old.tsx

* remove old themes

* remove old ui registry

* comment out nav items

* Update package-lock.json

* Update AssistantChatForm.tsx

* move back

* move again

* update

* Update index.tsx

* Update package-lock.json

* Update package-lock.json

* Update package-lock.json

* update package

* udpate prettier

* fix tag issues

* Update package-lock.json

* update to contentlayer2

* update package-lock.json

* fix type errors

* ignore spelling

* Update avoid-typos.yml

* Update avoid-typos.yml

* Update package-lock.json

* Use ui type definitions.

* move tsconfig base stuff. fix content layer issue

* Update package-lock.json

* Update package-lock.json

---------

Co-authored-by: Alaister Young <a@alaisteryoung.com>
Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
2024-05-23 17:39:56 +08:00

152 lines
5.0 KiB
TypeScript

import { Loader2 } from 'lucide-react'
import React, { ChangeEvent, createRef, useEffect } from 'react'
import { TextArea } from 'ui/src/components/shadcn/ui/text-area'
import { cn } from 'ui/src/lib/utils'
export interface FormProps extends React.FormHTMLAttributes<HTMLFormElement> {
/* The ref for the textarea */
textAreaRef: React.RefObject<HTMLTextAreaElement>
/* The loading state of the form */
loading: boolean
/* The disabled state of the form */
disabled?: boolean
/* The value of the textarea */
value?: string
/* The function to handle the value change */
onValueChange: (value: ChangeEvent<HTMLTextAreaElement>) => void
/* Used to stop onSubmit event when Command popover is open. Use with AssistantCommandsPopover */
commandsOpen?: boolean
/* Used to close Command popover when onSubmit event happens. Use with AssistantCommandsPopover */
setCommandsOpen?: (value: boolean) => void
/* The icon to display on the left of the textarea */
icon?: React.ReactNode
/* The function to handle the form submission */
onSubmit: React.FormHTMLAttributes<HTMLFormElement>['onSubmit']
/* The placeholder of the textarea */
placeholder?: string
}
const AssistantChatForm = React.forwardRef<HTMLFormElement, FormProps>(
(
{
loading = false,
disabled = false,
value = '',
textAreaRef,
commandsOpen = false,
icon = null,
onValueChange,
setCommandsOpen,
onSubmit,
placeholder,
...props
},
ref
) => {
const formRef = createRef<HTMLFormElement>()
const submitRef = createRef<HTMLButtonElement>()
/**
* This effect is used to resize the textarea based on the content
*/
useEffect(() => {
if (textAreaRef) {
if (!value && textAreaRef && textAreaRef.current) {
textAreaRef.current.style.height = '40px'
} else if (textAreaRef && textAreaRef.current) {
const newHeight = textAreaRef.current.scrollHeight + 'px'
textAreaRef.current.style.height = newHeight
}
}
}, [value, textAreaRef])
/**
* This effect is used to focus the textarea when the component mounts
*/
useEffect(() => {
textAreaRef?.current?.focus()
}, [value, textAreaRef])
/**
* This function is used to handle the "Enter" key press
*/
const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
// Check if the pressed key is "Enter" (key code 13) without the "Shift" key
// also checks if the commands popover is open
if (event.key === 'Enter' && !event.shiftKey && !commandsOpen) {
event.preventDefault()
if (submitRef.current) {
submitRef.current.click()
}
}
// handles closing the commands popover if open
if (event.key === 'Enter' && commandsOpen) {
if (setCommandsOpen) setCommandsOpen(false)
}
}
return (
<form ref={formRef} className="relative" {...props} onSubmit={onSubmit}>
{icon && (
<div className={cn('absolute', 'top-2 left-2', 'ml-1 w-6 h-6 rounded-full bg-dbnew')}>
{icon}
</div>
)}
<TextArea
ref={textAreaRef}
autoFocus
rows={1}
disabled={disabled}
contentEditable
aria-expanded={false}
className={cn(
icon ? 'pl-12' : '',
'transition-all text-sm pr-10 rounded-[18px] resize-none box-border leading-6'
)}
placeholder={placeholder}
spellCheck={false}
value={value}
onChange={(event: ChangeEvent<HTMLTextAreaElement>) => onValueChange(event)}
onKeyDown={handleKeyDown}
/>
<div className="absolute right-1.5 top-1.5 flex gap-3 items-center">
{loading && (
<Loader2 size={22} className="animate-spin w-7 h-7 text-muted" strokeWidth={1} />
)}
<button
ref={submitRef}
type="submit"
className={cn(
'transition-all',
'flex items-center justify-center w-7 h-7 border border-control rounded-full mr-0.5 p-1.5 background-alternative',
!value ? 'text-muted opacity-50' : 'text-default opacity-100',
loading && 'hidden'
)}
>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M13.5 3V2.25H15V3V10C15 10.5523 14.5522 11 14 11H3.56062L5.53029 12.9697L6.06062 13.5L4.99996 14.5607L4.46963 14.0303L1.39641 10.9571C1.00588 10.5666 1.00588 9.93342 1.39641 9.54289L4.46963 6.46967L4.99996 5.93934L6.06062 7L5.53029 7.53033L3.56062 9.5H13.5V3Z"
fill="currentColor"
></path>
</svg>
</button>
</div>
</form>
)
}
)
AssistantChatForm.displayName = 'AssistantChatForm'
export { AssistantChatForm }