-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🗨️ refactor(VariableForm): use
InputCombobox
, fix Dropdown Variables (
#3692) * feat: Add SimpleCombobox component * feat: Add labelClassName and add manual focus handling * feat: Update VariableForm component to use SimpleCombobox The VariableForm component in the client/src/components/Prompts/Groups/VariableForm.tsx file has been updated to use the SimpleCombobox component instead of the InputWithDropdown component. This change improves the functionality and styling of the form. * chore: Update VariableForm component placeholder text * refactor: Improve VariableForm component The VariableForm component in the client/src/components/Prompts/Groups/VariableForm.tsx file has been refactored to improve its functionality. The `parseFieldConfig` function now trims the `variable` string before processing it. Additionally, the `onSubmit` function now properly escapes potential regex special chars that may cause issues when replacing text * refactor: Improve VariableForm using ariakit helpers/custom fields, open menu on input focus * refactor: rename SimpleCombobox to InputCombobox
- Loading branch information
1 parent
8ca1e4f
commit 598e2be
Showing
3 changed files
with
134 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import React from 'react'; | ||
import * as Ariakit from '@ariakit/react'; | ||
import type { OptionWithIcon } from '~/common'; | ||
import { cn } from '~/utils'; | ||
|
||
type ComboboxProps = { | ||
label?: string; | ||
placeholder?: string; | ||
options: OptionWithIcon[] | string[]; | ||
className?: string; | ||
labelClassName?: string; | ||
value: string; | ||
onChange: (value: string) => void; | ||
onBlur: () => void; | ||
}; | ||
|
||
export const InputCombobox: React.FC<ComboboxProps> = ({ | ||
label, | ||
labelClassName, | ||
placeholder = 'Select an option', | ||
options, | ||
className, | ||
value, | ||
onChange, | ||
onBlur, | ||
}) => { | ||
const isOptionObject = (option: unknown): option is OptionWithIcon => { | ||
return option != null && typeof option === 'object' && 'value' in option; | ||
}; | ||
|
||
const [isOpen, setIsOpen] = React.useState(false); | ||
const [inputValue, setInputValue] = React.useState(value); | ||
const [isKeyboardFocus, setIsKeyboardFocus] = React.useState(false); | ||
|
||
React.useEffect(() => { | ||
setInputValue(value); | ||
}, [value]); | ||
|
||
const handleChange = (newValue: string) => { | ||
setInputValue(newValue); | ||
onChange(newValue); | ||
}; | ||
|
||
return ( | ||
<Ariakit.ComboboxProvider value={inputValue} setValue={handleChange}> | ||
{label != null && ( | ||
<Ariakit.ComboboxLabel | ||
className={cn('mb-2 block text-sm font-medium text-text-primary', labelClassName ?? '')} | ||
> | ||
{label} | ||
</Ariakit.ComboboxLabel> | ||
)} | ||
<div className={cn('relative', isKeyboardFocus ? 'rounded-md ring-2 ring-ring-primary' : '')}> | ||
<Ariakit.Combobox | ||
placeholder={placeholder} | ||
className={cn( | ||
'h-10 w-full rounded-md border border-border-light bg-surface-primary px-3 py-2 text-sm', | ||
'placeholder-text-secondary hover:bg-surface-hover', | ||
'focus:outline-none', | ||
className, | ||
)} | ||
onChange={(event) => handleChange(event.target.value)} | ||
onBlur={() => { | ||
setIsKeyboardFocus(false); | ||
onBlur(); | ||
}} | ||
onFocusVisible={() => { | ||
setIsKeyboardFocus(true); | ||
setIsOpen(true); | ||
}} | ||
onMouseDown={() => { | ||
setIsKeyboardFocus(false); | ||
}} | ||
/> | ||
</div> | ||
<Ariakit.ComboboxPopover | ||
gutter={4} | ||
sameWidth | ||
open={isOpen} | ||
onClose={() => setIsOpen(false)} | ||
className={cn( | ||
'z-50 max-h-60 w-full overflow-auto rounded-md bg-surface-primary p-1 shadow-lg', | ||
'animate-in fade-in-0 zoom-in-95', | ||
)} | ||
> | ||
{options.map((option: string | OptionWithIcon, index: number) => ( | ||
<Ariakit.ComboboxItem | ||
key={index} | ||
className={cn( | ||
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none', | ||
'cursor-pointer hover:bg-surface-tertiary hover:text-text-primary', | ||
'data-[active-item]:bg-surface-tertiary data-[active-item]:text-text-primary', | ||
)} | ||
value={isOptionObject(option) ? `${option.value ?? ''}` : option} | ||
> | ||
{isOptionObject(option) && option.icon != null && ( | ||
<span className="mr-2 flex-shrink-0">{option.icon}</span> | ||
)} | ||
{isOptionObject(option) ? option.label : option} | ||
</Ariakit.ComboboxItem> | ||
))} | ||
</Ariakit.ComboboxPopover> | ||
</Ariakit.ComboboxProvider> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters