| import { useState, useId } from 'react'; | |
| import { PlusCircle } from 'lucide-react'; | |
| import * as Menu from '@ariakit/react/menu'; | |
| import { useFormContext } from 'react-hook-form'; | |
| import { DropdownPopup } from '@librechat/client'; | |
| import { specialVariables } from 'librechat-data-provider'; | |
| import type { TSpecialVarLabel } from 'librechat-data-provider'; | |
| import { useLocalize } from '~/hooks'; | |
| interface VariableOption { | |
| label: TSpecialVarLabel; | |
| value: string; | |
| } | |
| const variableOptions: VariableOption[] = Object.keys(specialVariables).map((key) => ({ | |
| label: `com_ui_special_var_${key}` as TSpecialVarLabel, | |
| value: `{{${key}}}`, | |
| })); | |
| interface VariablesDropdownProps { | |
| fieldName?: string; | |
| className?: string; | |
| } | |
| export default function VariablesDropdown({ | |
| fieldName = 'prompt', | |
| className = '', | |
| }: VariablesDropdownProps) { | |
| const menuId = useId(); | |
| const localize = useLocalize(); | |
| const methods = useFormContext(); | |
| const { setValue, getValues } = methods; | |
| const [isMenuOpen, setIsMenuOpen] = useState(false); | |
| const handleAddVariable = (label: TSpecialVarLabel, value: string) => { | |
| const currentText = getValues(fieldName) || ''; | |
| const spacer = currentText.length > 0 ? '\n\n' : ''; | |
| const prefix = localize(label); | |
| setValue(fieldName, currentText + spacer + prefix + ': ' + value); | |
| setIsMenuOpen(false); | |
| }; | |
| return ( | |
| <div | |
| className={className} | |
| title={`${localize('com_ui_add')} ${localize('com_ui_special_variables')}`} | |
| > | |
| <DropdownPopup | |
| portal={true} | |
| mountByState={true} | |
| unmountOnHide={true} | |
| preserveTabOrder={true} | |
| isOpen={isMenuOpen} | |
| setIsOpen={setIsMenuOpen} | |
| trigger={ | |
| <Menu.MenuButton | |
| id="variables-menu-button" | |
| aria-label={`${localize('com_ui_add')} ${localize('com_ui_special_variables')}`} | |
| className="flex h-8 items-center gap-1 rounded-md border border-border-medium bg-surface-secondary px-2 py-0 text-sm text-text-primary transition-colors duration-200 hover:bg-surface-tertiary" | |
| > | |
| <PlusCircle className="mr-1 h-3 w-3 text-text-secondary" aria-hidden={true} /> | |
| {localize('com_ui_special_variables')} | |
| </Menu.MenuButton> | |
| } | |
| items={variableOptions.map((option) => ({ | |
| label: localize(option.label) || option.label, | |
| onClick: () => handleAddVariable(option.label, option.value), | |
| }))} | |
| menuId={menuId} | |
| className="z-30" | |
| /> | |
| </div> | |
| ); | |
| } | |