diff --git a/packages/devextreme-angular/src/ui/chat/index.ts b/packages/devextreme-angular/src/ui/chat/index.ts index ccd3cdcf3131..6d1203a5e671 100644 --- a/packages/devextreme-angular/src/ui/chat/index.ts +++ b/packages/devextreme-angular/src/ui/chat/index.ts @@ -29,6 +29,7 @@ import { DataSourceOptions } from 'devextreme/data/data_source'; import { Store } from 'devextreme/data/store'; import { Format } from 'devextreme/common/core/localization'; import { dxFileUploaderOptions } from 'devextreme/ui/file_uploader'; +import { dxSpeechToTextOptions } from 'devextreme/ui/speech_to_text'; import DxChat from 'devextreme/ui/chat'; @@ -56,11 +57,14 @@ import { DxoUserModule } from 'devextreme-angular/ui/nested'; import { DxiChatAlertModule } from 'devextreme-angular/ui/chat/nested'; import { DxiChatAttachmentModule } from 'devextreme-angular/ui/chat/nested'; import { DxoChatAuthorModule } from 'devextreme-angular/ui/chat/nested'; +import { DxoChatCustomSpeechRecognizerModule } from 'devextreme-angular/ui/chat/nested'; import { DxoChatDayHeaderFormatModule } from 'devextreme-angular/ui/chat/nested'; import { DxoChatEditingModule } from 'devextreme-angular/ui/chat/nested'; import { DxoChatFileUploaderOptionsModule } from 'devextreme-angular/ui/chat/nested'; import { DxiChatItemModule } from 'devextreme-angular/ui/chat/nested'; import { DxoChatMessageTimestampFormatModule } from 'devextreme-angular/ui/chat/nested'; +import { DxoChatSpeechRecognitionConfigModule } from 'devextreme-angular/ui/chat/nested'; +import { DxoChatSpeechToTextOptionsModule } from 'devextreme-angular/ui/chat/nested'; import { DxiChatTypingUserModule } from 'devextreme-angular/ui/chat/nested'; import { DxoChatUserModule } from 'devextreme-angular/ui/chat/nested'; import { @@ -291,6 +295,16 @@ export class DxChatComponent extends DxComponent implements OnDestroy, OnChanges } + + @Input() + get inputFieldText(): any { + return this._getOption('inputFieldText'); + } + set inputFieldText(value: any) { + this._setOption('inputFieldText', value); + } + + /** * [descr:dxChatOptions.items] @@ -408,6 +422,16 @@ export class DxChatComponent extends DxComponent implements OnDestroy, OnChanges } + + @Input() + get speechToTextOptions(): dxSpeechToTextOptions { + return this._getOption('speechToTextOptions'); + } + set speechToTextOptions(value: dxSpeechToTextOptions) { + this._setOption('speechToTextOptions', value); + } + + /** * [descr:dxChatOptions.typingUsers] @@ -661,6 +685,13 @@ export class DxChatComponent extends DxComponent implements OnDestroy, OnChanges */ @Output() hoverStateEnabledChange: EventEmitter; + /** + + * This member supports the internal infrastructure and is not intended to be used directly from your code. + + */ + @Output() inputFieldTextChange: EventEmitter; + /** * This member supports the internal infrastructure and is not intended to be used directly from your code. @@ -724,6 +755,13 @@ export class DxChatComponent extends DxComponent implements OnDestroy, OnChanges */ @Output() showUserNameChange: EventEmitter; + /** + + * This member supports the internal infrastructure and is not intended to be used directly from your code. + + */ + @Output() speechToTextOptionsChange: EventEmitter; + /** * This member supports the internal infrastructure and is not intended to be used directly from your code. @@ -792,6 +830,7 @@ export class DxChatComponent extends DxComponent implements OnDestroy, OnChanges { emit: 'heightChange' }, { emit: 'hintChange' }, { emit: 'hoverStateEnabledChange' }, + { emit: 'inputFieldTextChange' }, { emit: 'itemsChange' }, { emit: 'messageTemplateChange' }, { emit: 'messageTimestampFormatChange' }, @@ -801,6 +840,7 @@ export class DxChatComponent extends DxComponent implements OnDestroy, OnChanges { emit: 'showDayHeadersChange' }, { emit: 'showMessageTimestampChange' }, { emit: 'showUserNameChange' }, + { emit: 'speechToTextOptionsChange' }, { emit: 'typingUsersChange' }, { emit: 'userChange' }, { emit: 'visibleChange' }, @@ -869,11 +909,14 @@ export class DxChatComponent extends DxComponent implements OnDestroy, OnChanges DxiChatAlertModule, DxiChatAttachmentModule, DxoChatAuthorModule, + DxoChatCustomSpeechRecognizerModule, DxoChatDayHeaderFormatModule, DxoChatEditingModule, DxoChatFileUploaderOptionsModule, DxiChatItemModule, DxoChatMessageTimestampFormatModule, + DxoChatSpeechRecognitionConfigModule, + DxoChatSpeechToTextOptionsModule, DxiChatTypingUserModule, DxoChatUserModule, DxIntegrationModule, @@ -892,11 +935,14 @@ export class DxChatComponent extends DxComponent implements OnDestroy, OnChanges DxiChatAlertModule, DxiChatAttachmentModule, DxoChatAuthorModule, + DxoChatCustomSpeechRecognizerModule, DxoChatDayHeaderFormatModule, DxoChatEditingModule, DxoChatFileUploaderOptionsModule, DxiChatItemModule, DxoChatMessageTimestampFormatModule, + DxoChatSpeechRecognitionConfigModule, + DxoChatSpeechToTextOptionsModule, DxiChatTypingUserModule, DxoChatUserModule, DxTemplateModule diff --git a/packages/devextreme-angular/src/ui/chat/nested/custom-speech-recognizer.ts b/packages/devextreme-angular/src/ui/chat/nested/custom-speech-recognizer.ts new file mode 100644 index 000000000000..73831940a754 --- /dev/null +++ b/packages/devextreme-angular/src/ui/chat/nested/custom-speech-recognizer.ts @@ -0,0 +1,83 @@ +/* tslint:disable:max-line-length */ + + +import { + Component, + OnInit, + OnDestroy, + NgModule, + Host, + SkipSelf, + Input +} from '@angular/core'; + + + + + +import { + DxIntegrationModule, + NestedOptionHost, +} from 'devextreme-angular/core'; +import { NestedOption } from 'devextreme-angular/core'; + + +@Component({ + selector: 'dxo-chat-custom-speech-recognizer', + standalone: true, + template: '', + styles: [''], + imports: [ DxIntegrationModule ], + providers: [NestedOptionHost] +}) +export class DxoChatCustomSpeechRecognizerComponent extends NestedOption implements OnDestroy, OnInit { + @Input() + get enabled(): boolean { + return this._getOption('enabled'); + } + set enabled(value: boolean) { + this._setOption('enabled', value); + } + + @Input() + get isListening(): boolean { + return this._getOption('isListening'); + } + set isListening(value: boolean) { + this._setOption('isListening', value); + } + + + protected get _optionPath() { + return 'customSpeechRecognizer'; + } + + + constructor(@SkipSelf() @Host() parentOptionHost: NestedOptionHost, + @Host() optionHost: NestedOptionHost) { + super(); + parentOptionHost.setNestedOption(this); + optionHost.setHost(this, this._fullOptionPath.bind(this)); + } + + + ngOnInit() { + this._addRecreatedComponent(); + } + + ngOnDestroy() { + this._addRemovedOption(this._getOptionPath()); + } + + +} + +@NgModule({ + imports: [ + DxoChatCustomSpeechRecognizerComponent + ], + exports: [ + DxoChatCustomSpeechRecognizerComponent + ], +}) +export class DxoChatCustomSpeechRecognizerModule { } diff --git a/packages/devextreme-angular/src/ui/chat/nested/index.ts b/packages/devextreme-angular/src/ui/chat/nested/index.ts index 93eac66e115c..90da87825498 100644 --- a/packages/devextreme-angular/src/ui/chat/nested/index.ts +++ b/packages/devextreme-angular/src/ui/chat/nested/index.ts @@ -1,11 +1,14 @@ export * from './alert-dxi'; export * from './attachment-dxi'; export * from './author'; +export * from './custom-speech-recognizer'; export * from './day-header-format'; export * from './editing'; export * from './file-uploader-options'; export * from './item-dxi'; export * from './message-timestamp-format'; +export * from './speech-recognition-config'; +export * from './speech-to-text-options'; export * from './typing-user-dxi'; export * from './user'; diff --git a/packages/devextreme-angular/src/ui/chat/nested/speech-recognition-config.ts b/packages/devextreme-angular/src/ui/chat/nested/speech-recognition-config.ts new file mode 100644 index 000000000000..ed821d34aaa1 --- /dev/null +++ b/packages/devextreme-angular/src/ui/chat/nested/speech-recognition-config.ts @@ -0,0 +1,107 @@ +/* tslint:disable:max-line-length */ + + +import { + Component, + OnInit, + OnDestroy, + NgModule, + Host, + SkipSelf, + Input +} from '@angular/core'; + + + + + +import { + DxIntegrationModule, + NestedOptionHost, +} from 'devextreme-angular/core'; +import { NestedOption } from 'devextreme-angular/core'; + + +@Component({ + selector: 'dxo-chat-speech-recognition-config', + standalone: true, + template: '', + styles: [''], + imports: [ DxIntegrationModule ], + providers: [NestedOptionHost] +}) +export class DxoChatSpeechRecognitionConfigComponent extends NestedOption implements OnDestroy, OnInit { + @Input() + get continuous(): boolean { + return this._getOption('continuous'); + } + set continuous(value: boolean) { + this._setOption('continuous', value); + } + + @Input() + get grammars(): Array { + return this._getOption('grammars'); + } + set grammars(value: Array) { + this._setOption('grammars', value); + } + + @Input() + get interimResults(): boolean { + return this._getOption('interimResults'); + } + set interimResults(value: boolean) { + this._setOption('interimResults', value); + } + + @Input() + get lang(): string { + return this._getOption('lang'); + } + set lang(value: string) { + this._setOption('lang', value); + } + + @Input() + get maxAlternatives(): number { + return this._getOption('maxAlternatives'); + } + set maxAlternatives(value: number) { + this._setOption('maxAlternatives', value); + } + + + protected get _optionPath() { + return 'speechRecognitionConfig'; + } + + + constructor(@SkipSelf() @Host() parentOptionHost: NestedOptionHost, + @Host() optionHost: NestedOptionHost) { + super(); + parentOptionHost.setNestedOption(this); + optionHost.setHost(this, this._fullOptionPath.bind(this)); + } + + + ngOnInit() { + this._addRecreatedComponent(); + } + + ngOnDestroy() { + this._addRemovedOption(this._getOptionPath()); + } + + +} + +@NgModule({ + imports: [ + DxoChatSpeechRecognitionConfigComponent + ], + exports: [ + DxoChatSpeechRecognitionConfigComponent + ], +}) +export class DxoChatSpeechRecognitionConfigModule { } diff --git a/packages/devextreme-angular/src/ui/chat/nested/speech-to-text-options.ts b/packages/devextreme-angular/src/ui/chat/nested/speech-to-text-options.ts new file mode 100644 index 000000000000..2f48d997a36d --- /dev/null +++ b/packages/devextreme-angular/src/ui/chat/nested/speech-to-text-options.ts @@ -0,0 +1,301 @@ +/* tslint:disable:max-line-length */ + + +import { + Component, + OnInit, + OnDestroy, + NgModule, + Host, + SkipSelf, + Input +} from '@angular/core'; + + + + +import { CustomSpeechRecognizer, ContentReadyEvent, DisposingEvent, EndEvent, ErrorEvent, InitializedEvent, OptionChangedEvent, ResultEvent, StartClickEvent, StopClickEvent, SpeechRecognitionConfig } from 'devextreme/ui/speech_to_text'; +import { ButtonStyle, ButtonType } from 'devextreme/common'; + +import { + DxIntegrationModule, + NestedOptionHost, +} from 'devextreme-angular/core'; +import { NestedOption } from 'devextreme-angular/core'; + + +@Component({ + selector: 'dxo-chat-speech-to-text-options', + standalone: true, + template: '', + styles: [''], + imports: [ DxIntegrationModule ], + providers: [NestedOptionHost] +}) +export class DxoChatSpeechToTextOptionsComponent extends NestedOption implements OnDestroy, OnInit { + @Input() + get accessKey(): string | undefined { + return this._getOption('accessKey'); + } + set accessKey(value: string | undefined) { + this._setOption('accessKey', value); + } + + @Input() + get activeStateEnabled(): boolean { + return this._getOption('activeStateEnabled'); + } + set activeStateEnabled(value: boolean) { + this._setOption('activeStateEnabled', value); + } + + @Input() + get customSpeechRecognizer(): CustomSpeechRecognizer { + return this._getOption('customSpeechRecognizer'); + } + set customSpeechRecognizer(value: CustomSpeechRecognizer) { + this._setOption('customSpeechRecognizer', value); + } + + @Input() + get disabled(): boolean { + return this._getOption('disabled'); + } + set disabled(value: boolean) { + this._setOption('disabled', value); + } + + @Input() + get elementAttr(): Record { + return this._getOption('elementAttr'); + } + set elementAttr(value: Record) { + this._setOption('elementAttr', value); + } + + @Input() + get focusStateEnabled(): boolean { + return this._getOption('focusStateEnabled'); + } + set focusStateEnabled(value: boolean) { + this._setOption('focusStateEnabled', value); + } + + @Input() + get height(): number | string | undefined { + return this._getOption('height'); + } + set height(value: number | string | undefined) { + this._setOption('height', value); + } + + @Input() + get hint(): string | undefined { + return this._getOption('hint'); + } + set hint(value: string | undefined) { + this._setOption('hint', value); + } + + @Input() + get hoverStateEnabled(): boolean { + return this._getOption('hoverStateEnabled'); + } + set hoverStateEnabled(value: boolean) { + this._setOption('hoverStateEnabled', value); + } + + @Input() + get onContentReady(): ((e: ContentReadyEvent) => void) { + return this._getOption('onContentReady'); + } + set onContentReady(value: ((e: ContentReadyEvent) => void)) { + this._setOption('onContentReady', value); + } + + @Input() + get onDisposing(): ((e: DisposingEvent) => void) { + return this._getOption('onDisposing'); + } + set onDisposing(value: ((e: DisposingEvent) => void)) { + this._setOption('onDisposing', value); + } + + @Input() + get onEnd(): ((e: EndEvent) => void) | undefined { + return this._getOption('onEnd'); + } + set onEnd(value: ((e: EndEvent) => void) | undefined) { + this._setOption('onEnd', value); + } + + @Input() + get onError(): ((e: ErrorEvent) => void) | undefined { + return this._getOption('onError'); + } + set onError(value: ((e: ErrorEvent) => void) | undefined) { + this._setOption('onError', value); + } + + @Input() + get onInitialized(): ((e: InitializedEvent) => void) { + return this._getOption('onInitialized'); + } + set onInitialized(value: ((e: InitializedEvent) => void)) { + this._setOption('onInitialized', value); + } + + @Input() + get onOptionChanged(): ((e: OptionChangedEvent) => void) { + return this._getOption('onOptionChanged'); + } + set onOptionChanged(value: ((e: OptionChangedEvent) => void)) { + this._setOption('onOptionChanged', value); + } + + @Input() + get onResult(): ((e: ResultEvent) => void) | undefined { + return this._getOption('onResult'); + } + set onResult(value: ((e: ResultEvent) => void) | undefined) { + this._setOption('onResult', value); + } + + @Input() + get onStartClick(): ((e: StartClickEvent) => void) | undefined { + return this._getOption('onStartClick'); + } + set onStartClick(value: ((e: StartClickEvent) => void) | undefined) { + this._setOption('onStartClick', value); + } + + @Input() + get onStopClick(): ((e: StopClickEvent) => void) | undefined { + return this._getOption('onStopClick'); + } + set onStopClick(value: ((e: StopClickEvent) => void) | undefined) { + this._setOption('onStopClick', value); + } + + @Input() + get rtlEnabled(): boolean { + return this._getOption('rtlEnabled'); + } + set rtlEnabled(value: boolean) { + this._setOption('rtlEnabled', value); + } + + @Input() + get speechRecognitionConfig(): Record | SpeechRecognitionConfig { + return this._getOption('speechRecognitionConfig'); + } + set speechRecognitionConfig(value: Record | SpeechRecognitionConfig) { + this._setOption('speechRecognitionConfig', value); + } + + @Input() + get startIcon(): string { + return this._getOption('startIcon'); + } + set startIcon(value: string) { + this._setOption('startIcon', value); + } + + @Input() + get startText(): string { + return this._getOption('startText'); + } + set startText(value: string) { + this._setOption('startText', value); + } + + @Input() + get stopIcon(): string { + return this._getOption('stopIcon'); + } + set stopIcon(value: string) { + this._setOption('stopIcon', value); + } + + @Input() + get stopText(): string { + return this._getOption('stopText'); + } + set stopText(value: string) { + this._setOption('stopText', value); + } + + @Input() + get stylingMode(): ButtonStyle { + return this._getOption('stylingMode'); + } + set stylingMode(value: ButtonStyle) { + this._setOption('stylingMode', value); + } + + @Input() + get tabIndex(): number { + return this._getOption('tabIndex'); + } + set tabIndex(value: number) { + this._setOption('tabIndex', value); + } + + @Input() + get type(): ButtonType | string { + return this._getOption('type'); + } + set type(value: ButtonType | string) { + this._setOption('type', value); + } + + @Input() + get visible(): boolean { + return this._getOption('visible'); + } + set visible(value: boolean) { + this._setOption('visible', value); + } + + @Input() + get width(): number | string | undefined { + return this._getOption('width'); + } + set width(value: number | string | undefined) { + this._setOption('width', value); + } + + + protected get _optionPath() { + return 'speechToTextOptions'; + } + + + constructor(@SkipSelf() @Host() parentOptionHost: NestedOptionHost, + @Host() optionHost: NestedOptionHost) { + super(); + parentOptionHost.setNestedOption(this); + optionHost.setHost(this, this._fullOptionPath.bind(this)); + } + + + ngOnInit() { + this._addRecreatedComponent(); + } + + ngOnDestroy() { + this._addRemovedOption(this._getOptionPath()); + } + + +} + +@NgModule({ + imports: [ + DxoChatSpeechToTextOptionsComponent + ], + exports: [ + DxoChatSpeechToTextOptionsComponent + ], +}) +export class DxoChatSpeechToTextOptionsModule { } diff --git a/packages/devextreme-metadata/make-angular-metadata.ts b/packages/devextreme-metadata/make-angular-metadata.ts index 08e060a56a8e..7d060e316f83 100644 --- a/packages/devextreme-metadata/make-angular-metadata.ts +++ b/packages/devextreme-metadata/make-angular-metadata.ts @@ -51,6 +51,8 @@ Ng.makeMetadata({ removeMembers(/\/card_view:/), removeMembers(/\/chat:TextMessage.attachments/), removeMembers(/\/chat:dxChatOptions\.(fileUploaderOptions|onAttachmentDownloadClick)/), + removeMembers(/\/chat:dxChatOptions.speechToTextOptions/), + removeMembers(/\/chat:dxChatOptions.inputFieldText/), removeMembers(/\/form:dxFormOptions\.(aiIntegration|onSmartPasting|onSmartPasted|smartPaste)/), removeMembers(/\/form:dxFormSimpleItem\.aiOptions/), removeMembers(/\/form:FormPredefinedButtonItem/), diff --git a/packages/devextreme-react/src/chat.ts b/packages/devextreme-react/src/chat.ts index c427f7135b74..6df640011bc2 100644 --- a/packages/devextreme-react/src/chat.ts +++ b/packages/devextreme-react/src/chat.ts @@ -10,7 +10,8 @@ import NestedOption from "./core/nested-option"; import type { Message, AttachmentDownloadClickEvent, DisposingEvent, InitializedEvent, MessageDeletedEvent, MessageDeletingEvent, MessageEditCanceledEvent, MessageEditingStartEvent, MessageEnteredEvent, MessageUpdatedEvent, MessageUpdatingEvent, TypingEndEvent, TypingStartEvent, Attachment as ChatAttachment, User as ChatUser } from "devextreme/ui/chat"; import type { DisposingEvent as FileUploaderDisposingEvent, InitializedEvent as FileUploaderInitializedEvent, BeforeSendEvent, ContentReadyEvent, DropZoneEnterEvent, DropZoneLeaveEvent, FilesUploadedEvent, OptionChangedEvent, ProgressEvent, UploadAbortedEvent, UploadedEvent, UploadErrorEvent, UploadStartedEvent, ValueChangedEvent, UploadHttpMethod, FileUploadMode } from "devextreme/ui/file_uploader"; -import type { Format, ValidationStatus } from "devextreme/common"; +import type { DisposingEvent as SpeechToTextDisposingEvent, InitializedEvent as SpeechToTextInitializedEvent, ContentReadyEvent as SpeechToTextContentReadyEvent, OptionChangedEvent as SpeechToTextOptionChangedEvent, CustomSpeechRecognizer as SpeechToTextCustomSpeechRecognizer, EndEvent, ErrorEvent, ResultEvent, StartClickEvent, StopClickEvent, SpeechRecognitionConfig as SpeechToTextSpeechRecognitionConfig } from "devextreme/ui/speech_to_text"; +import type { Format, ValidationStatus, ButtonStyle, ButtonType } from "devextreme/common"; import type UploadInfo from "devextreme/file_management/upload_info"; @@ -73,6 +74,7 @@ const Chat = memo( fileUploaderOptions: { optionName: "fileUploaderOptions", isCollectionItem: false }, item: { optionName: "items", isCollectionItem: true }, messageTimestampFormat: { optionName: "messageTimestampFormat", isCollectionItem: false }, + speechToTextOptions: { optionName: "speechToTextOptions", isCollectionItem: false }, typingUser: { optionName: "typingUsers", isCollectionItem: true }, user: { optionName: "user", isCollectionItem: false } }), []); @@ -168,6 +170,25 @@ const Author = Object.assign(_comp componentType: "option", }); +// owners: +// SpeechToTextOptions +type ICustomSpeechRecognizerProps = React.PropsWithChildren<{ + enabled?: boolean; + isListening?: boolean; +}> +const _componentCustomSpeechRecognizer = (props: ICustomSpeechRecognizerProps) => { + return React.createElement(NestedOption, { + ...props, + elementDescriptor: { + OptionName: "customSpeechRecognizer", + }, + }); +}; + +const CustomSpeechRecognizer = Object.assign(_componentCustomSpeechRecognizer, { + componentType: "option", +}); + // owners: // Chat type IDayHeaderFormatProps = React.PropsWithChildren<{ @@ -351,6 +372,78 @@ const MessageTimestampFormat = Object.assign; + interimResults?: boolean; + lang?: string; + maxAlternatives?: number; +}> +const _componentSpeechRecognitionConfig = (props: ISpeechRecognitionConfigProps) => { + return React.createElement(NestedOption, { + ...props, + elementDescriptor: { + OptionName: "speechRecognitionConfig", + }, + }); +}; + +const SpeechRecognitionConfig = Object.assign(_componentSpeechRecognitionConfig, { + componentType: "option", +}); + +// owners: +// Chat +type ISpeechToTextOptionsProps = React.PropsWithChildren<{ + accessKey?: string | undefined; + activeStateEnabled?: boolean; + customSpeechRecognizer?: SpeechToTextCustomSpeechRecognizer; + disabled?: boolean; + elementAttr?: Record; + focusStateEnabled?: boolean; + height?: number | string | undefined; + hint?: string | undefined; + hoverStateEnabled?: boolean; + onContentReady?: ((e: SpeechToTextContentReadyEvent) => void); + onDisposing?: ((e: SpeechToTextDisposingEvent) => void); + onEnd?: ((e: EndEvent) => void) | undefined; + onError?: ((e: ErrorEvent) => void) | undefined; + onInitialized?: ((e: SpeechToTextInitializedEvent) => void); + onOptionChanged?: ((e: SpeechToTextOptionChangedEvent) => void); + onResult?: ((e: ResultEvent) => void) | undefined; + onStartClick?: ((e: StartClickEvent) => void) | undefined; + onStopClick?: ((e: StopClickEvent) => void) | undefined; + rtlEnabled?: boolean; + speechRecognitionConfig?: Record | SpeechToTextSpeechRecognitionConfig; + startIcon?: string; + startText?: string; + stopIcon?: string; + stopText?: string; + stylingMode?: ButtonStyle; + tabIndex?: number; + type?: ButtonType | string; + visible?: boolean; + width?: number | string | undefined; +}> +const _componentSpeechToTextOptions = (props: ISpeechToTextOptionsProps) => { + return React.createElement(NestedOption, { + ...props, + elementDescriptor: { + OptionName: "speechToTextOptions", + ExpectedChildren: { + customSpeechRecognizer: { optionName: "customSpeechRecognizer", isCollectionItem: false }, + speechRecognitionConfig: { optionName: "speechRecognitionConfig", isCollectionItem: false } + }, + }, + }); +}; + +const SpeechToTextOptions = Object.assign(_componentSpeechToTextOptions, { + componentType: "option", +}); + // owners: // Chat type ITypingUserProps = React.PropsWithChildren<{ @@ -405,6 +498,8 @@ export { IAttachmentProps, Author, IAuthorProps, + CustomSpeechRecognizer, + ICustomSpeechRecognizerProps, DayHeaderFormat, IDayHeaderFormatProps, Editing, @@ -415,6 +510,10 @@ export { IItemProps, MessageTimestampFormat, IMessageTimestampFormatProps, + SpeechRecognitionConfig, + ISpeechRecognitionConfigProps, + SpeechToTextOptions, + ISpeechToTextOptionsProps, TypingUser, ITypingUserProps, User, diff --git a/packages/devextreme-vue/src/chat.ts b/packages/devextreme-vue/src/chat.ts index ff0edbe3dcd7..8babddbe3024 100644 --- a/packages/devextreme-vue/src/chat.ts +++ b/packages/devextreme-vue/src/chat.ts @@ -36,6 +36,8 @@ import { import { Format as CommonFormat, ValidationStatus, + ButtonStyle, + ButtonType, } from "devextreme/common"; import { dxFileUploaderOptions, @@ -56,6 +58,20 @@ import { UploadHttpMethod, FileUploadMode, } from "devextreme/ui/file_uploader"; +import { + dxSpeechToTextOptions, + CustomSpeechRecognizer, + ContentReadyEvent as SpeechToTextContentReadyEvent, + DisposingEvent as SpeechToTextDisposingEvent, + EndEvent, + ErrorEvent, + InitializedEvent as SpeechToTextInitializedEvent, + OptionChangedEvent as SpeechToTextOptionChangedEvent, + ResultEvent, + StartClickEvent, + StopClickEvent, + SpeechRecognitionConfig, +} from "devextreme/ui/speech_to_text"; import { prepareConfigurationComponentConfig } from "./core/index"; type AccessibleOptions = Pick>, messageTemplate: {}, messageTimestampFormat: [Object, String, Function] as PropType string)) | Record | string>, @@ -143,6 +162,7 @@ const componentConfig = { showDayHeaders: Boolean, showMessageTimestamp: Boolean, showUserName: Boolean, + speechToTextOptions: Object as PropType>, typingUsers: Array as PropType>, user: Object as PropType>, visible: Boolean, @@ -165,6 +185,7 @@ const componentConfig = { "update:height": null, "update:hint": null, "update:hoverStateEnabled": null, + "update:inputFieldText": null, "update:items": null, "update:messageTemplate": null, "update:messageTimestampFormat": null, @@ -187,6 +208,7 @@ const componentConfig = { "update:showDayHeaders": null, "update:showMessageTimestamp": null, "update:showUserName": null, + "update:speechToTextOptions": null, "update:typingUsers": null, "update:user": null, "update:visible": null, @@ -207,6 +229,7 @@ const componentConfig = { fileUploaderOptions: { isCollectionItem: false, optionName: "fileUploaderOptions" }, item: { isCollectionItem: true, optionName: "items" }, messageTimestampFormat: { isCollectionItem: false, optionName: "messageTimestampFormat" }, + speechToTextOptions: { isCollectionItem: false, optionName: "speechToTextOptions" }, typingUser: { isCollectionItem: true, optionName: "typingUsers" }, user: { isCollectionItem: false, optionName: "user" } }; @@ -281,6 +304,25 @@ const DxAuthor = defineComponent(DxAuthorConfig); (DxAuthor as any).$_optionName = "author"; +const DxCustomSpeechRecognizerConfig = { + emits: { + "update:isActive": null, + "update:hoveredElement": null, + "update:enabled": null, + "update:isListening": null, + }, + props: { + enabled: Boolean, + isListening: Boolean + } +}; + +prepareConfigurationComponentConfig(DxCustomSpeechRecognizerConfig); + +const DxCustomSpeechRecognizer = defineComponent(DxCustomSpeechRecognizerConfig); + +(DxCustomSpeechRecognizer as any).$_optionName = "customSpeechRecognizer"; + const DxDayHeaderFormatConfig = { emits: { "update:isActive": null, @@ -537,6 +579,108 @@ const DxMessageTimestampFormat = defineComponent(DxMessageTimestampFormatConfig) (DxMessageTimestampFormat as any).$_optionName = "messageTimestampFormat"; +const DxSpeechRecognitionConfigConfig = { + emits: { + "update:isActive": null, + "update:hoveredElement": null, + "update:continuous": null, + "update:grammars": null, + "update:interimResults": null, + "update:lang": null, + "update:maxAlternatives": null, + }, + props: { + continuous: Boolean, + grammars: Array as PropType>, + interimResults: Boolean, + lang: String, + maxAlternatives: Number + } +}; + +prepareConfigurationComponentConfig(DxSpeechRecognitionConfigConfig); + +const DxSpeechRecognitionConfig = defineComponent(DxSpeechRecognitionConfigConfig); + +(DxSpeechRecognitionConfig as any).$_optionName = "speechRecognitionConfig"; + +const DxSpeechToTextOptionsConfig = { + emits: { + "update:isActive": null, + "update:hoveredElement": null, + "update:accessKey": null, + "update:activeStateEnabled": null, + "update:customSpeechRecognizer": null, + "update:disabled": null, + "update:elementAttr": null, + "update:focusStateEnabled": null, + "update:height": null, + "update:hint": null, + "update:hoverStateEnabled": null, + "update:onContentReady": null, + "update:onDisposing": null, + "update:onEnd": null, + "update:onError": null, + "update:onInitialized": null, + "update:onOptionChanged": null, + "update:onResult": null, + "update:onStartClick": null, + "update:onStopClick": null, + "update:rtlEnabled": null, + "update:speechRecognitionConfig": null, + "update:startIcon": null, + "update:startText": null, + "update:stopIcon": null, + "update:stopText": null, + "update:stylingMode": null, + "update:tabIndex": null, + "update:type": null, + "update:visible": null, + "update:width": null, + }, + props: { + accessKey: String, + activeStateEnabled: Boolean, + customSpeechRecognizer: Object as PropType>, + disabled: Boolean, + elementAttr: Object as PropType>, + focusStateEnabled: Boolean, + height: [Number, String], + hint: String, + hoverStateEnabled: Boolean, + onContentReady: Function as PropType<((e: SpeechToTextContentReadyEvent) => void)>, + onDisposing: Function as PropType<((e: SpeechToTextDisposingEvent) => void)>, + onEnd: Function as PropType<((e: EndEvent) => void)>, + onError: Function as PropType<((e: ErrorEvent) => void)>, + onInitialized: Function as PropType<((e: SpeechToTextInitializedEvent) => void)>, + onOptionChanged: Function as PropType<((e: SpeechToTextOptionChangedEvent) => void)>, + onResult: Function as PropType<((e: ResultEvent) => void)>, + onStartClick: Function as PropType<((e: StartClickEvent) => void)>, + onStopClick: Function as PropType<((e: StopClickEvent) => void)>, + rtlEnabled: Boolean, + speechRecognitionConfig: Object as PropType | SpeechRecognitionConfig>, + startIcon: String, + startText: String, + stopIcon: String, + stopText: String, + stylingMode: String as PropType, + tabIndex: Number, + type: String as PropType, + visible: Boolean, + width: [Number, String] + } +}; + +prepareConfigurationComponentConfig(DxSpeechToTextOptionsConfig); + +const DxSpeechToTextOptions = defineComponent(DxSpeechToTextOptionsConfig); + +(DxSpeechToTextOptions as any).$_optionName = "speechToTextOptions"; +(DxSpeechToTextOptions as any).$_expectedChildren = { + customSpeechRecognizer: { isCollectionItem: false, optionName: "customSpeechRecognizer" }, + speechRecognitionConfig: { isCollectionItem: false, optionName: "speechRecognitionConfig" } +}; + const DxTypingUserConfig = { emits: { "update:isActive": null, @@ -590,11 +734,14 @@ export { DxAlert, DxAttachment, DxAuthor, + DxCustomSpeechRecognizer, DxDayHeaderFormat, DxEditing, DxFileUploaderOptions, DxItem, DxMessageTimestampFormat, + DxSpeechRecognitionConfig, + DxSpeechToTextOptions, DxTypingUser, DxUser }; diff --git a/packages/devextreme/js/ui/chat.d.ts b/packages/devextreme/js/ui/chat.d.ts index 49c907573dab..aadecc7e7238 100644 --- a/packages/devextreme/js/ui/chat.d.ts +++ b/packages/devextreme/js/ui/chat.d.ts @@ -15,6 +15,10 @@ import { Properties as FileUploaderOptions, } from './file_uploader'; +import { Properties as SpeechToTextOptions } from './speech_to_text'; + +import { Properties as TextAreaProperties } from './text_area'; + import Widget, { WidgetOptions } from './widget/ui.widget'; import { EventInfo, @@ -353,7 +357,6 @@ export interface dxChatOptions extends WidgetOptions { activeStateEnabled?: boolean; /** * @docid - * @default null * @type dxFileUploaderOptions * @public */ @@ -432,6 +435,12 @@ export interface dxChatOptions extends WidgetOptions { * @public */ alerts?: Array; + /** + * @docid + * @default "" + * @public + */ + inputFieldText?: TextAreaProperties['value']; /** * @docid * @default null @@ -475,6 +484,12 @@ export interface dxChatOptions extends WidgetOptions { * @public */ showMessageTimestamp?: boolean; + /** + * @docid + * @type dxSpeechToTextOptions + * @public + */ + speechToTextOptions?: Omit; /** * @docid * @default undefined diff --git a/packages/devextreme/ts/dx.all.d.ts b/packages/devextreme/ts/dx.all.d.ts index 796de6c7a91c..99ffda14fa97 100644 --- a/packages/devextreme/ts/dx.all.d.ts +++ b/packages/devextreme/ts/dx.all.d.ts @@ -11414,6 +11414,10 @@ declare module DevExpress.ui { * [descr:dxChatOptions.alerts] */ alerts?: Array; + /** + * [descr:dxChatOptions.inputFieldText] + */ + inputFieldText?: DevExpress.ui.dxTextArea.Properties['value']; /** * [descr:dxChatOptions.messageTemplate] */ @@ -11448,6 +11452,13 @@ declare module DevExpress.ui { * [descr:dxChatOptions.showMessageTimestamp] */ showMessageTimestamp?: boolean; + /** + * [descr:dxChatOptions.speechToTextOptions] + */ + speechToTextOptions?: Omit< + DevExpress.ui.dxSpeechToText.Properties, + 'stylingMode' | 'type' + >; /** * [descr:dxChatOptions.onAttachmentDownloadClick] */