Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ Notes: web developers are advised to use [`~` (tilde range)](https://github.com/
- Added support of [contentless activity in livestream](https://github.com/microsoft/BotFramework-WebChat/blob/main/docs/LIVESTREAMING.md#scenario-3-interim-activities-with-no-content), in PR [#5430](https://github.com/microsoft/BotFramework-WebChat/pull/5430), by [@compulim](https://github.com/compulim)
- Added sliding dots typing indicator in Fluent theme, in PR [#5447](https://github.com/microsoft/BotFramework-WebChat/pull/5447) and PR [#5448](https://github.com/microsoft/BotFramework-WebChat/pull/5448), by [@compulim](https://github.com/compulim)
- (Experimental) Add an ability to pass `completion` prop into Fluent send box and expose the component, in PR [#5466](https://github.com/microsoft/BotFramework-WebChat/pull/5466), by [@OEvgeny](https://github.com/OEvgeny)
- Added feedback form for like/dislike button when `feedbackActionsPlacement` is `"activity-actions"`, in PR [#5460](https://github.com/microsoft/BotFramework-WebChat/pull/5460), PR [#5469](https://github.com/microsoft/BotFramework-WebChat/pull/5469), PR [5470](https://github.com/microsoft/BotFramework-WebChat/pull/5470) and PR [#5501](https://github.com/microsoft/BotFramework-WebChat/pull/5501) by [@lexi-taylor](https://github.com/lexi-taylor) and [@OEvgeny](https://github.com/OEvgeny)
- Added feedback form for like/dislike button when `feedbackActionsPlacement` is `"activity-actions"`, in PR [#5460](https://github.com/microsoft/BotFramework-WebChat/pull/5460), PR [#5469](https://github.com/microsoft/BotFramework-WebChat/pull/5469), PR [5470](https://github.com/microsoft/BotFramework-WebChat/pull/5470), PR [#5501](https://github.com/microsoft/BotFramework-WebChat/pull/5501), and PR [#5567](https://github.com/microsoft/BotFramework-WebChat/pull/5567) by [@lexi-taylor](https://github.com/lexi-taylor), and [@OEvgeny](https://github.com/OEvgeny)
Comment thread
OEvgeny marked this conversation as resolved.
Outdated
- <kbd>ESCAPE</kbd> key should reset the feedback form, in PR [#5480](https://github.com/microsoft/BotFramework-WebChat/pull/5480), by [@compulim](https://github.com/compulim), in PR [#5493](https://github.com/microsoft/BotFramework-WebChat/pull/5493) by [@lexi-taylor](https://github.com/lexi-taylor)
- Added multi-dimensional grouping, `styleOptions.groupActivitiesBy`, and `useGroupActivitiesByName` hook, in PR [#5471](https://github.com/microsoft/BotFramework-WebChat/pull/5471), by [@compulim](https://github.com/compulim)
- Existing behavior will be kept and activities will be grouped by `sender` followed by `status`
Expand Down
8 changes: 8 additions & 0 deletions __tests__/html2/feedbackForm/feedback.form.activity.html
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@
1000
);

// Validate aria labelledby is present for feedback form and matching elements are present
const feedbackFormSendBox = pageElements.byTestId('feedback sendbox');
const ariaLabelledBy = feedbackFormSendBox.getAttribute('aria-labelledby');
expect(ariaLabelledBy).toContain('feedback-form__form-header__id');
expect(ariaLabelledBy).toContain('feedback-form__form-footer__id');
expect(ariaLabelledBy).toContain('feedback-form__text-area__id');
await pageObjects.verifyDOMIntegrity();

// WHEN: The cancel button is clicked.
await host.sendTab(2);
await host.sendKeys('ENTER');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { hooks } from 'botframework-webchat-api';
import { useStyles } from '@msinternal/botframework-webchat-styles/react';
import React, { memo, useCallback, useEffect, useRef, useState, type FormEventHandler } from 'react';

import useUniqueId from '../../hooks/internal/useUniqueId';
import Markdownable from '../../Attachment/Text/private/Markdownable';
import testIds from '../../testIds';
import { TextArea } from '../../TextArea';
Expand All @@ -15,6 +15,9 @@ const { useLocalizer } = hooks;
function FeedbackForm() {
const classNames = useStyles(styles);
const { useFeedbackText, useSelectedAction } = useActivityFeedbackHooks();
const feedbackFormHeaderId = useUniqueId('feedback-form__form-header__id');
const disclaimerId = useUniqueId('feedback-form__form-footer__id');
const textAreaId = useUniqueId('feedback-form__text-area__id');

const [selectedAction] = useSelectedAction();
const [hasFocus, setHasFocus] = useState(false);
Expand All @@ -40,21 +43,35 @@ function FeedbackForm() {
}
}, [feedbackTextAreaRef, hasFocus, setHasFocus]);

const textAreaAriaLabelledBy = `${feedbackFormHeaderId} ${textAreaId}${disclaimer ? ` ${disclaimerId}` : ''}`;
Comment thread
lexi-taylor marked this conversation as resolved.
Outdated

return (
<div className={classNames['feedback-form__form']}>
<span className={classNames['feedback-form__form-header']}>{localize('FEEDBACK_FORM_TITLE')}</span>
<span
className={classNames['feedback-form__form-header']}
// "id" is required for "aria-labelledby"
// eslint-disable-next-line react/forbid-dom-props
id={feedbackFormHeaderId}
>
{localize('FEEDBACK_FORM_TITLE')}
</span>
<div className={classNames['feedback-form__text-box']}>
<TextArea
aria-label={localize('FEEDBACK_FORM_PLACEHOLDER')}
aria-labelledby={textAreaAriaLabelledBy}
className={classNames['feedback-form__text-area']}
data-testid={testIds.feedbackSendBox}
id={textAreaId}
onInput={handleMessageChange}
placeholder={localize('FEEDBACK_FORM_PLACEHOLDER')}
ref={feedbackTextAreaRef}
startRows={3}
value={userFeedback}
/>
</div>
{disclaimer && <Markdownable className={classNames['feedback-form__form-footer']} text={disclaimer} />}
{disclaimer && (
<Markdownable className={classNames['feedback-form__form-footer']} id={disclaimerId} text={disclaimer} />
)}
<div className={classNames['feedback-form__submission-button-bar']}>
<button className={classNames['feedback-form__submit-button']} type="submit">
{localize('FEEDBACK_FORM_SUBMIT_BUTTON_LABEL')}
Expand Down
14 changes: 10 additions & 4 deletions packages/component/src/Attachment/Text/private/Markdownable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import { useRenderMarkdownAsHTML } from '../../../hooks';
const markdownablePropsSchema = pipe(
object({
className: optional(string()),
id: optional(string()),
text: string()
}),
readonly()
);

type MarkdownableProps = InferInput<typeof markdownablePropsSchema>;

function Markdownable({ className, text }: MarkdownableProps) {
function Markdownable({ className, id, text }: MarkdownableProps) {
const renderMarkdownAsHTML = useRenderMarkdownAsHTML('message activity');

const innerHTML = useMemo<Readonly<{ __html: string }> | undefined>(
Expand All @@ -22,10 +23,15 @@ function Markdownable({ className, text }: MarkdownableProps) {
);

return innerHTML ? (
// eslint-disable-next-line react/no-danger
<span className={className} dangerouslySetInnerHTML={innerHTML} />
// "id" is required for "aria-labelledby"
// eslint-disable-next-line react/forbid-dom-props, react/no-danger
<span className={className} dangerouslySetInnerHTML={innerHTML} id={id} />
) : (
<span className={className}>{text}</span>
// "id" is required for "aria-labelledby"
// eslint-disable-next-line react/forbid-dom-props
<span className={className} id={id}>
{text}
</span>
);
}

Expand Down
6 changes: 6 additions & 0 deletions packages/component/src/TextArea/TextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const TextArea = forwardRef<
HTMLTextAreaElement,
Readonly<{
'aria-label'?: string | undefined;
'aria-labelledby'?: string | undefined;
className?: string | undefined;
completion?: ReactNode | undefined;
'data-testid'?: string | undefined;
Expand All @@ -32,6 +33,7 @@ const TextArea = forwardRef<
* This ensures the flow of focus did not sent to document body
*/
hidden?: boolean | undefined;
id?: string | undefined;
onInput?: FormEventHandler<HTMLTextAreaElement> | undefined;
placeholder?: string | undefined;
startRows?: number | undefined;
Expand Down Expand Up @@ -85,8 +87,12 @@ const TextArea = forwardRef<
<textarea
aria-disabled={disabled}
aria-label={props['aria-label']}
aria-labelledby={props['aria-labelledby']}
className={cx(classNames['text-area-input'], classNames['text-area-shared'])}
data-testid={props['data-testid']}
// "id" is required for "aria-labelledby"
// eslint-disable-next-line react/forbid-dom-props
id={props['id']}
onCompositionEnd={handleCompositionEnd}
onCompositionStart={handleCompositionStart}
onInput={props.onInput}
Expand Down
Loading