🔊 fix(tts): NotAllowedError (mobile/safari), Unsupported MediaSource type (firefox), Hide Audio Element (#2854)

* fix: hide audio element on mobile

* chore: add tts docs link

* fix: select voice option on first render

* fix: NotAllowedError, prevent async playback for mobile triggers, consolidate MessageAudio code, user user-triggered unmutes

* fix: Firefox/unsupported type for MediaSource hack

* refactor(STT): make icon red when recording. consolidate logic to AudioRecorder component

* fix: revert Redis changes to use separate client for sessions
This commit is contained in:
Danny Avila 2024-05-24 12:18:11 -04:00 committed by GitHub
parent dcd2e3e62d
commit 35ba4ba1a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 421 additions and 130 deletions

View file

@ -0,0 +1,105 @@
import React, { FC } from 'react';
import { Listbox } from '@headlessui/react';
import { cn } from '~/utils/';
type OptionType = {
value: string;
display?: string;
};
type DropdownPosition = 'left' | 'right';
interface DropdownProps {
value: string;
label?: string;
onChange: (value: string) => void;
options: (string | OptionType)[];
className?: string;
position?: DropdownPosition;
width?: number;
maxHeight?: string;
testId?: string;
}
const Dropdown: FC<DropdownProps> = ({
value,
label = '',
onChange,
options,
className = '',
position = 'right',
width,
maxHeight = 'auto',
testId = 'dropdown-menu',
}) => {
const positionClasses = {
right: 'origin-bottom-left left-0',
left: 'origin-bottom-right right-0',
};
return (
<div className={cn('relative', className)}>
<Listbox
value={value}
onChange={(newValue) => {
onChange(newValue);
}}
>
<div className={cn('relative', className)}>
<Listbox.Button
data-testid={testId}
className={cn(
'relative inline-flex items-center justify-between rounded-md border-gray-300 bg-white py-2 pl-3 pr-8 text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600',
'w-auto',
className,
)}
>
<span className="block truncate">
{label}
{options
.map((o) => (typeof o === 'string' ? { value: o, display: o } : o))
.find((o) => o.value === value)?.display || value}
</span>
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="2"
stroke="currentColor"
className="h-4 w-5 rotate-0 transform text-gray-400 transition-transform duration-300 ease-in-out"
>
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</span>
</Listbox.Button>
<Listbox.Options
className={cn(
`absolute z-50 mt-1 flex max-h-[40vh] flex-col items-start gap-1 overflow-auto rounded-lg border border-gray-300 bg-white p-1.5 text-gray-700 shadow-lg transition-opacity focus:outline-none dark:border-gray-600 dark:bg-gray-700 dark:text-white ${positionClasses[position]}`,
className,
)}
style={{ width: width ? `${width}px` : 'auto', maxHeight: maxHeight }}
>
{options.map((item, index) => (
<Listbox.Option
key={index}
value={typeof item === 'string' ? item : item.value}
className={cn(
'relative cursor-pointer select-none rounded border-gray-300 bg-white py-2.5 pl-3 pr-6 text-gray-700 hover:bg-gray-100 dark:border-gray-300 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600',
)}
style={{ width: '100%' }}
data-theme={typeof item === 'string' ? item : (item as OptionType).value}
>
<span className="block truncate">
{typeof item === 'string' ? item : (item as OptionType).display}
</span>
</Listbox.Option>
))}
</Listbox.Options>
</div>
</Listbox>
</div>
);
};
export default Dropdown;