Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorporate PR changes #1

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,598 changes: 1,800 additions & 1,798 deletions CHANGELOG.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion __tests__/html/attachment.combineAttachmentsAndText.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
Expand Down
16 changes: 14 additions & 2 deletions docs/HOOKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ Following is the list of hooks supported by Web Chat API.
- [`useScrollUp`](#usescrollup)
- [`useSendBoxValue`](#usesendboxvalue)
- [`useSendEvent`](#usesendevent)
- [`useSendFiles`](#usesendfiles)
- [`useSendFiles`](#usesendfiles) (Deprecated)
- [`useSendMessage`](#usesendmessage)
- [`useSendMessageBack`](#usesendmessageback)
- [`useSendPostBack`](#usesendpostback)
Expand Down Expand Up @@ -999,6 +999,8 @@ When called, this function will send an event activity to the bot.

## `useSendFiles`

> This function is deprecated. Developers should migrate to [`useSendMessage`](#usesendmessage).

<!-- prettier-ignore-start -->
```js
useSendFiles(): (files: (Blob | File)[]) => void
Expand All @@ -1016,14 +1018,24 @@ If you are using an `ArrayBuffer`, you can use `FileReader` to convert it into a

<!-- prettier-ignore-start -->
```js
useSendMessage(): (text: string, method: string) => void
useSendMessage(): (
text?: string,
method: string,
{
files?: Iterable<Blob | File> | undefined
}
) => void
```
<!-- prettier-ignore-end -->

When called, this function will send a text message activity to the bot.

You can optionally include the input method how the text message was collected. Currently, if specified, only `speech` is supported.

For media attachments, thumbnail can be optionally provided and should be a data URL.

Either `text` or `files` must be defined. If none of them are defined, the function will be no-op.

## `useSendMessageBack`

<!-- prettier-ignore-start -->
Expand Down
7 changes: 5 additions & 2 deletions packages/api/src/StyleOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,10 +270,13 @@ type StyleOptions = {
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#multiple
*/
uploadMultiple?: boolean;

/**
* Send the attachments and message text together as a single activity
* If set to `send` (default), attachment will be sent when the send button is clicked, or when the message is being sent.
*
* Otherwise, if set to `upload`, attachment will be sent immediately after upload.
*/
combineAttachmentsAndText?: boolean;
sendAttachmentOn?: 'upload' | 'send';

/** Send box button: Icon color, defaults to subtle */
sendBoxButtonColor?: string;
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/defaultStyleOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ const DEFAULT_OPTIONS: Required<StyleOptions> = {
sendBoxBackground: 'White',
uploadAccept: undefined,
uploadMultiple: true,
combineAttachmentsAndText: undefined,
sendAttachmentOn: 'send',

// Send box buttons
sendBoxButtonColor: undefined,
Expand Down
62 changes: 29 additions & 33 deletions packages/api/src/hooks/Composer.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import { Provider } from 'react-redux';
import PropTypes from 'prop-types';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import updateIn from 'simple-update-in';
import {
clearSuggestedActions,
connect as createConnectAction,
Expand All @@ -21,6 +17,7 @@ import {
setLanguage,
setNotification,
setSendBox,
setSendBoxAttachments,
setSendTimeout,
setSendTypingIndicator,
singleToArray,
Expand All @@ -30,42 +27,46 @@ import {
stopSpeakingActivity,
submitSendBox
} from 'botframework-webchat-core';
import PropTypes from 'prop-types';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Provider } from 'react-redux';
import updateIn from 'simple-update-in';

import { default as WebChatAPIContext } from './internal/WebChatAPIContext';
import StyleOptions from '../StyleOptions';
import usePonyfill from '../hooks/usePonyfill';
import getAllLocalizedStrings from '../localization/getAllLocalizedStrings';
import normalizeStyleOptions from '../normalizeStyleOptions';
import patchStyleOptionsFromDeprecatedProps from '../patchStyleOptionsFromDeprecatedProps';
import ActivityAcknowledgementComposer from '../providers/ActivityAcknowledgement/ActivityAcknowledgementComposer';
import ActivityKeyerComposer from '../providers/ActivityKeyer/ActivityKeyerComposer';
import ActivityMiddleware from '../types/ActivityMiddleware';
import ActivitySendStatusComposer from '../providers/ActivitySendStatus/ActivitySendStatusComposer';
import ActivitySendStatusTelemetryComposer from '../providers/ActivitySendStatusTelemetry/ActivitySendStatusTelemetryComposer';
import PonyfillComposer from '../providers/Ponyfill/PonyfillComposer';
import ActivityMiddleware from '../types/ActivityMiddleware';
import AttachmentForScreenReaderMiddleware from '../types/AttachmentForScreenReaderMiddleware';
import AttachmentMiddleware from '../types/AttachmentMiddleware';
import AvatarMiddleware from '../types/AvatarMiddleware';
import CardActionMiddleware from '../types/CardActionMiddleware';
import createCustomEvent from '../utils/createCustomEvent';
import createDefaultCardActionMiddleware from './middleware/createDefaultCardActionMiddleware';
import createDefaultGroupActivitiesMiddleware from './middleware/createDefaultGroupActivitiesMiddleware';
import defaultSelectVoice from './internal/defaultSelectVoice';
import ErrorBoundary from './utils/ErrorBoundary';
import getAllLocalizedStrings from '../localization/getAllLocalizedStrings';
import GroupActivitiesMiddleware from '../types/GroupActivitiesMiddleware';
import isObject from '../utils/isObject';
import LocalizedStrings from '../types/LocalizedStrings';
import mapMap from '../utils/mapMap';
import normalizeLanguage from '../utils/normalizeLanguage';
import normalizeStyleOptions from '../normalizeStyleOptions';
import observableToPromise from './utils/observableToPromise';
import patchStyleOptionsFromDeprecatedProps from '../patchStyleOptionsFromDeprecatedProps';
import PonyfillComposer from '../providers/Ponyfill/PonyfillComposer';
import PrecompiledGlobalizeType from '../types/PrecompiledGlobalize';
import ScrollToEndButtonMiddleware, { ScrollToEndButtonComponentFactory } from '../types/ScrollToEndButtonMiddleware';
import StyleOptions from '../StyleOptions';
import TelemetryMeasurementEvent, { TelemetryExceptionMeasurementEvent } from '../types/TelemetryMeasurementEvent';
import ToastMiddleware from '../types/ToastMiddleware';
import Tracker from './internal/Tracker';
import TypingIndicatorMiddleware from '../types/TypingIndicatorMiddleware';
import useMarkAllAsAcknowledged from './useMarkAllAsAcknowledged';
import usePonyfill from '../hooks/usePonyfill';
import createCustomEvent from '../utils/createCustomEvent';
import isObject from '../utils/isObject';
import mapMap from '../utils/mapMap';
import normalizeLanguage from '../utils/normalizeLanguage';
import Tracker from './internal/Tracker';
import { default as WebChatAPIContext } from './internal/WebChatAPIContext';
import WebChatReduxContext, { useDispatch } from './internal/WebChatReduxContext';
import defaultSelectVoice from './internal/defaultSelectVoice';
import createDefaultCardActionMiddleware from './middleware/createDefaultCardActionMiddleware';
import createDefaultGroupActivitiesMiddleware from './middleware/createDefaultGroupActivitiesMiddleware';
import useMarkAllAsAcknowledged from './useMarkAllAsAcknowledged';
import ErrorBoundary from './utils/ErrorBoundary';
import observableToPromise from './utils/observableToPromise';

import applyMiddleware, {
forLegacyRenderer as applyMiddlewareForLegacyRenderer,
Expand All @@ -76,15 +77,15 @@ import applyMiddleware, {
// @ts-ignore
import PrecompiledGlobalize from '../external/PrecompiledGlobalize';

import type { ActivityStatusMiddleware, RenderActivityStatus } from '../types/ActivityStatusMiddleware';
import type { ContextOf } from '../types/internal/ContextOf';
import type {
DirectLineJSBotConnection,
OneOrMany,
GlobalScopePonyfill,
OneOrMany,
WebChatActivity
} from 'botframework-webchat-core';
import type { ReactNode } from 'react';
import type { ActivityStatusMiddleware, RenderActivityStatus } from '../types/ActivityStatusMiddleware';
import type { ContextOf } from '../types/internal/ContextOf';

// List of Redux actions factory we are hoisting as Web Chat functions
const DISPATCHERS = {
Expand All @@ -102,6 +103,7 @@ const DISPATCHERS = {
setDictateState,
setNotification,
setSendBox,
setSendBoxAttachments,
setSendTimeout,
startDictate,
startSpeakingActivity,
Expand Down Expand Up @@ -540,9 +542,6 @@ const ComposerCore = ({
[scrollToEndButtonMiddleware]
);

// For useFiles hook
const [files, setFiles] = useState<File[]>([]);

// For useUploadButtonRef
const uploadButtonRef = useRef<HTMLInputElement>();

Expand Down Expand Up @@ -571,7 +570,6 @@ const ComposerCore = ({
directLine,
disabled,
downscaleImageToDataURL,
files,
grammars: patchedGrammars,
internalErrorBoxClass,
language: locale,
Expand All @@ -582,7 +580,6 @@ const ComposerCore = ({
scrollToEndButtonRenderer,
selectVoice: patchedSelectVoice,
sendTypingIndicator,
setFiles,
styleOptions: patchedStyleOptions,
telemetryDimensionsRef,
toastRenderer: patchedToastRenderer,
Expand All @@ -597,7 +594,6 @@ const ComposerCore = ({
directLine,
disabled,
downscaleImageToDataURL,
files,
groupActivitiesContext,
hoistedDispatchers,
internalErrorBoxClass,
Expand All @@ -619,7 +615,7 @@ const ComposerCore = ({
renderMarkdown,
scrollToEndButtonRenderer,
sendTypingIndicator,
setFiles,
telemetryDimensionsRef,
trackDimension,
userID,
username
Expand Down
6 changes: 2 additions & 4 deletions packages/api/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import useDirection from './useDirection';
import useDisabled from './useDisabled';
import useDismissNotification from './useDismissNotification';
import useEmitTypingIndicator from './useEmitTypingIndicator';
import useFiles from './useFiles';
import useGetActivityByKey from './useGetActivityByKey';
import useGetHasAcknowledgedByActivityKey from './useGetHasAcknowledgedByActivityKey';
import useGetKeyByActivity from './useGetKeyByActivity';
Expand All @@ -46,6 +45,7 @@ import useRenderAttachment from './useRenderAttachment';
import useRenderAvatar from './useRenderAvatar';
import useRenderToast from './useRenderToast';
import useRenderTypingIndicator from './useRenderTypingIndicator';
import useSendBoxAttachments from './useSendBoxAttachments';
import useSendBoxValue from './useSendBoxValue';
import useSendEvent from './useSendEvent';
import useSendFiles from './useSendFiles';
Expand All @@ -67,7 +67,6 @@ import useTrackDimension from './useTrackDimension';
import useTrackEvent from './useTrackEvent';
import useTrackException from './useTrackException';
import useTrackTiming from './useTrackTiming';
import useUploadButtonRef from './useUploadButtonRef';
import useUserID from './useUserID';
import useUsername from './useUsername';
import useVoiceSelector from './useVoiceSelector';
Expand All @@ -94,7 +93,6 @@ export {
useDisabled,
useDismissNotification,
useEmitTypingIndicator,
useFiles,
useGetActivityByKey,
useGetHasAcknowledgedByActivityKey,
useGetKeyByActivity,
Expand All @@ -121,6 +119,7 @@ export {
useRenderAvatar,
useRenderToast,
useRenderTypingIndicator,
useSendBoxAttachments,
useSendBoxValue,
useSendEvent,
useSendFiles,
Expand All @@ -142,7 +141,6 @@ export {
useTrackEvent,
useTrackException,
useTrackTiming,
useUploadButtonRef,
useUserID,
useUsername,
useVoiceSelector
Expand Down
39 changes: 25 additions & 14 deletions packages/api/src/hooks/internal/WebChatAPIContext.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,42 @@
import { createContext } from 'react';
import { createContext, type Dispatch, type SetStateAction } from 'react';

import { AttachmentForScreenReaderComponentFactory } from '../../types/AttachmentForScreenReaderMiddleware';
import { AvatarComponentFactory } from '../../types/AvatarMiddleware';
import { GroupActivities } from '../../types/GroupActivitiesMiddleware';
import { StrictStyleOptions } from '../../StyleOptions';
import { LegacyActivityRenderer } from '../../types/ActivityMiddleware';
import { PerformCardAction } from '../../types/CardActionMiddleware';
import { RenderActivityStatus } from '../../types/ActivityStatusMiddleware';
import { AttachmentForScreenReaderComponentFactory } from '../../types/AttachmentForScreenReaderMiddleware';
import { RenderAttachment } from '../../types/AttachmentMiddleware';
import { RenderToast } from '../../types/ToastMiddleware';
import { ScrollToEndButtonComponentFactory } from '../../types/ScrollToEndButtonMiddleware';
import { StrictStyleOptions } from '../../StyleOptions';
import { AvatarComponentFactory } from '../../types/AvatarMiddleware';
import { PerformCardAction } from '../../types/CardActionMiddleware';
import { GroupActivities } from '../../types/GroupActivitiesMiddleware';
import LocalizedStrings from '../../types/LocalizedStrings';
import Notification from '../../types/Notification';
import PrecompiledGlobalize from '../../types/PrecompiledGlobalize';
import { ScrollToEndButtonComponentFactory } from '../../types/ScrollToEndButtonMiddleware';
import TelemetryMeasurementEvent from '../../types/TelemetryMeasurementEvent';
import { RenderToast } from '../../types/ToastMiddleware';

import type { DirectLineJSBotConnection, Observable, WebChatActivity } from 'botframework-webchat-core';
import type {
DirectLineJSBotConnection,
Observable,
sendFiles,
sendMessage,
WebChatActivity,
WebChatPostActivityAttachment
} from 'botframework-webchat-core';

type WebChatAPIContext = {
activityRenderer?: LegacyActivityRenderer;
activityStatusRenderer: RenderActivityStatus;
attachmentForScreenReaderRenderer?: AttachmentForScreenReaderComponentFactory;
attachmentRenderer?: RenderAttachment;
avatarRenderer?: AvatarComponentFactory;
avatarRenderer: AvatarComponentFactory;
clearSuggestedActions?: () => void;
dir?: string;
directLine?: DirectLineJSBotConnection;
disabled?: boolean;
dismissNotification?: (id: string) => void;
downscaleImageToDataURL?: (blob: Blob, maxWidth: number, maxHeight: number, type: string, quality: number) => string;
emitTypingIndicator?: () => void;
files?: File[];
grammars?: any;
groupActivities?: GroupActivities;
internalErrorBoxClass?: React.Component | Function;
Expand All @@ -46,17 +53,21 @@ type WebChatAPIContext = {
linkOptions: { externalLinkAlt: string }
) => string;
scrollToEndButtonRenderer?: ScrollToEndButtonComponentFactory;
selectVoice?: (voices: (typeof window.SpeechSynthesisVoice)[], activity: WebChatActivity) => void;
selectVoice?: (
voices: (typeof window.SpeechSynthesisVoice)[],
activity: WebChatActivity
) => typeof window.SpeechSynthesisVoice;
sendEvent?: (name: string, value: any) => void;
sendFiles?: (files: File[], text?: string) => void;
sendMessage?: (text: string, method?: string, { channelData }?: { channelData?: any }) => void;
sendFiles?: typeof sendFiles;
sendMessage?: typeof sendMessage;
sendMessageBack?: (value: any, text?: string, displayText?: string) => void;
sendPostBack?: (value?: any) => void;
sendTypingIndicator?: boolean;
setDictateInterims?: (interims: string[]) => void;
setDictateState?: (dictateState: number) => void;
setNotification?: (notification: Notification) => void;
setSendBox?: (value: string) => void;
setSendBoxAttachments?: Dispatch<SetStateAction<readonly WebChatPostActivityAttachment[]>>;
setSendTimeout?: (timeout: number) => void;
startDictate?: () => void;
startSpeakingActivity?: () => void;
Expand Down
10 changes: 0 additions & 10 deletions packages/api/src/hooks/useFiles.ts

This file was deleted.

19 changes: 19 additions & 0 deletions packages/api/src/hooks/useSendBoxAttachments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { WebChatPostActivityAttachment } from 'botframework-webchat-core';
import { useMemo, type Dispatch, type SetStateAction } from 'react';

import { useSelector } from './internal/WebChatReduxContext';
import useWebChatAPIContext from './internal/useWebChatAPIContext';

export default function useSendBoxAttachments(): readonly [
readonly WebChatPostActivityAttachment[],
Dispatch<SetStateAction<readonly WebChatPostActivityAttachment[]>>
] {
// TODO: We should use the selector from "core" package.
const sendBoxAttachments = useSelector(({ sendBoxAttachments }) => sendBoxAttachments);
const { setSendBoxAttachments } = useWebChatAPIContext();

return useMemo(
() => Object.freeze([sendBoxAttachments, setSendBoxAttachments]),
[sendBoxAttachments, setSendBoxAttachments]
);
}
Loading